diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2021-12-28 22:00:14 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-12-28 20:38:37 -0500 |
| commit | c0ae9647f9656ea47c49ffd64443b7da73aeffc7 (patch) | |
| tree | 3f39f2283482c3dd05b44404d967475fb495df4c /src | |
| parent | 4f4f0bc6f03a84597247504a5ee15ed7f1e050d1 (diff) | |
| download | zig-c0ae9647f9656ea47c49ffd64443b7da73aeffc7.tar.gz zig-c0ae9647f9656ea47c49ffd64443b7da73aeffc7.zip | |
stage2 ARM: implement slice_elem_val for types with size <= 4
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 143 | ||||
| -rw-r--r-- | src/codegen.zig | 174 |
2 files changed, 251 insertions, 66 deletions
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 2b7610e761..d714e4174e 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -1159,13 +1159,29 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const mcv = try self.resolveInst(ty_op.operand); + switch (mcv) { + .stack_offset => |off| { + break :result MCValue{ .stack_offset = off }; + }, + else => return self.fail("TODO implement slice_ptr for {}", .{mcv}), + } + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const mcv = try self.resolveInst(ty_op.operand); + switch (mcv) { + .stack_offset => |off| { + break :result MCValue{ .stack_offset = off + 4 }; + }, + else => return self.fail("TODO implement slice_len for {}", .{mcv}), + } + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1184,7 +1200,76 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = false; // TODO const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}); + const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { + const slice_mcv = try self.resolveInst(bin_op.lhs); + const index_mcv = try self.resolveInst(bin_op.rhs); + + const slice_ty = self.air.typeOf(bin_op.lhs); + const elem_ty = slice_ty.childType(); + const elem_size = elem_ty.abiSize(self.target.*); + + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); + + // TODO optimize this for the case when elem_size is a power + // of two (includes elem_size == 1) + const offset_mcv = try self.genArmMulConstant(inst, bin_op.rhs, 1, @intCast(u32, elem_size)); + assert(offset_mcv == .register); // result of multiplication should always be register + + const base_mcv: MCValue = switch (slice_mcv) { + .stack_offset => |off| blk: { + const reg = try self.register_manager.allocReg(null, &.{offset_mcv.register}); + try self.genSetReg(slice_ptr_field_type, reg, MCValue{ .stack_offset = off }); + break :blk MCValue{ .register = reg }; + }, + else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), + }; + + if (elem_size <= 4) { + const dst_reg = try self.register_manager.allocReg(inst, &.{ base_mcv.register, offset_mcv.register }); + switch (elem_size) { + 1, 4 => { + const tag: Mir.Inst.Tag = switch (elem_size) { + 1 => .ldrb, + 4 => .ldr, + else => unreachable, + }; + + _ = try self.addInst(.{ + .tag = tag, + .cond = .al, + .data = .{ .rr_offset = .{ + .rt = dst_reg, + .rn = base_mcv.register, + .offset = .{ .offset = Instruction.Offset.reg(offset_mcv.register, 0) }, + } }, + }); + }, + 2 => { + _ = try self.addInst(.{ + .tag = .ldrh, + .cond = .al, + .data = .{ .rr_extra_offset = .{ + .rt = dst_reg, + .rn = base_mcv.register, + .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.reg(offset_mcv.register) }, + } }, + }); + }, + else => unreachable, + } + + break :result MCValue{ .register = dst_reg }; + } else { + // const dst_mcv = try self.allocRegOrMem(inst, false); + return self.fail("TODO implement slice_elem_val for elem_size >= 4", .{}); + } + + _ = offset_mcv; + _ = slice_mcv; + _ = index_mcv; + _ = offset_mcv; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1839,6 +1924,58 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai return dst_mcv; } +fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_index: Liveness.OperandInt, imm: u32) !MCValue { + const mcv = try self.resolveInst(op); + const rhs = MCValue{ .immediate = imm }; + + const lhs_is_register = mcv == .register; + const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op, op_index, mcv); + + // Destination must be a register + // LHS must be a register + // RHS must be a register + var dst_mcv: MCValue = undefined; + var lhs_mcv: MCValue = mcv; + var rhs_mcv: MCValue = rhs; + + // Allocate registers for operands and/or destination + if (reuse_lhs) { + // Allocate 1 register + rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{mcv.register}) }; + dst_mcv = mcv; + } else { + // Allocate 1 or 2 registers + if (lhs_is_register) { + // Move RHS to register + dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{mcv.register}) }; + rhs_mcv = dst_mcv; + } else { + // Move LHS and RHS to register + const regs = try self.register_manager.allocRegs(2, .{ inst, null }, &.{}); + lhs_mcv = MCValue{ .register = regs[0] }; + rhs_mcv = MCValue{ .register = regs[1] }; + dst_mcv = lhs_mcv; + } + } + + // Move the operands to the newly allocated registers + if (!lhs_is_register) { + try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, mcv); + } + try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs); + + _ = try self.addInst(.{ + .tag = .mul, + .cond = .al, + .data = .{ .rrr = .{ + .rd = dst_mcv.register, + .rn = lhs_mcv.register, + .rm = rhs_mcv.register, + } }, + }); + return dst_mcv; +} + fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { const ty_str = self.air.instructions.items(.data)[inst].ty_str; const zir = &self.mod_fn.owner_decl.getFileScope().zir; diff --git a/src/codegen.zig b/src/codegen.zig index d734194699..f93c53804b 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -168,9 +168,10 @@ pub fn generateSymbol( ), }; }, - .Array => { - // TODO populate .debug_info for the array - if (typed_value.val.castTag(.bytes)) |payload| { + .Array => switch (typed_value.val.tag()) { + .bytes => { + // TODO populate .debug_info for the array + const payload = typed_value.val.castTag(.bytes).?; if (typed_value.ty.sentinel()) |sentinel| { try code.ensureUnusedCapacity(payload.data.len + 1); code.appendSliceAssumeCapacity(payload.data); @@ -188,94 +189,83 @@ pub fn generateSymbol( } else { return Result{ .externally_managed = payload.data }; } - } - return Result{ + }, + .array => { + // TODO populate .debug_info for the array + const elem_vals = typed_value.val.castTag(.array).?.data; + const elem_ty = typed_value.ty.elemType(); + for (elem_vals) |elem_val| { + switch (try generateSymbol(bin_file, src_loc, .{ + .ty = elem_ty, + .val = elem_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |slice| { + code.appendSliceAssumeCapacity(slice); + return Result{ .appended = {} }; + }, + .fail => |em| return Result{ .fail = em }, + } + } + return Result{ .appended = {} }; + }, + else => return Result{ .fail = try ErrorMsg.create( bin_file.allocator, src_loc, - "TODO implement generateSymbol for more kinds of arrays", - .{}, + "TODO implement generateSymbol for array type value: {s}", + .{@tagName(typed_value.val.tag())}, ), - }; + }, }, - .Pointer => switch (typed_value.ty.ptrSize()) { - .Slice => { + .Pointer => switch (typed_value.val.tag()) { + .variable => { + const decl = typed_value.val.castTag(.variable).?.data.owner_decl; + return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output); + }, + .decl_ref => { + const decl = typed_value.val.castTag(.decl_ref).?.data; + return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output); + }, + .slice => { // TODO populate .debug_info for the slice + const slice = typed_value.val.castTag(.slice).?.data; // generate ptr var buf: Type.SlicePtrFieldTypeBuffer = undefined; const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); switch (try generateSymbol(bin_file, src_loc, .{ .ty = slice_ptr_field_type, - .val = typed_value.val.slicePtr(), + .val = slice.ptr, }, code, debug_output)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); }, .fail => |em| return Result{ .fail = em }, } // generate length - var int_buffer: Value.Payload.U64 = .{ - .base = .{ .tag = .int_u64 }, - .data = typed_value.val.sliceLen(), - }; switch (try generateSymbol(bin_file, src_loc, .{ .ty = Type.initTag(.usize), - .val = Value.initPayload(&int_buffer.base), + .val = slice.len, }, code, debug_output)) { .appended => {}, - .externally_managed => |slice| { - code.appendSliceAssumeCapacity(slice); + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); }, .fail => |em| return Result{ .fail = em }, } - return Result{ - .fail = try ErrorMsg.create( - bin_file.allocator, - src_loc, - "TODO implement generateSymbol for slice {}", - .{typed_value.val}, - ), - }; + return Result{ .appended = {} }; }, - else => { - // TODO populate .debug_info for the pointer - if (typed_value.val.castTag(.decl_ref)) |payload| { - const decl = payload.data; - if (decl.analysis != .complete) return error.AnalysisFail; - decl.alive = true; - // TODO handle the dependency of this symbol on the decl's vaddr. - // If the decl changes vaddr, then this symbol needs to get regenerated. - const vaddr = bin_file.getDeclVAddr(decl); - const endian = bin_file.options.target.cpu.arch.endian(); - switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { - 16 => { - try code.resize(2); - mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); - }, - 32 => { - try code.resize(4); - mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian); - }, - 64 => { - try code.resize(8); - mem.writeInt(u64, code.items[0..8], vaddr, endian); - }, - else => unreachable, - } - return Result{ .appended = {} }; - } - return Result{ - .fail = try ErrorMsg.create( - bin_file.allocator, - src_loc, - "TODO implement generateSymbol for pointer {}", - .{typed_value.val}, - ), - }; + else => return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "TODO implement generateSymbol for pointer type value: '{s}'", + .{@tagName(typed_value.val.tag())}, + ), }, }, .Int => { @@ -401,3 +391,61 @@ pub fn generateSymbol( }, } } + +fn lowerDeclRef( + bin_file: *link.File, + src_loc: Module.SrcLoc, + typed_value: TypedValue, + decl: *Module.Decl, + code: *std.ArrayList(u8), + debug_output: DebugInfoOutput, +) GenerateSymbolError!Result { + if (typed_value.ty.isSlice()) { + // generate ptr + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); + switch (try generateSymbol(bin_file, src_loc, .{ + .ty = slice_ptr_field_type, + .val = typed_value.val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); + }, + .fail => |em| return Result{ .fail = em }, + } + + // generate length + var slice_len: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = typed_value.val.sliceLen(), + }; + switch (try generateSymbol(bin_file, src_loc, .{ + .ty = Type.initTag(.usize), + .val = Value.initPayload(&slice_len.base), + }, code, debug_output)) { + .appended => {}, + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); + }, + .fail => |em| return Result{ .fail = em }, + } + + return Result{ .appended = {} }; + } + + if (decl.analysis != .complete) return error.AnalysisFail; + decl.alive = true; + // TODO handle the dependency of this symbol on the decl's vaddr. + // If the decl changes vaddr, then this symbol needs to get regenerated. + const vaddr = bin_file.getDeclVAddr(decl); + const endian = bin_file.options.target.cpu.arch.endian(); + switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { + 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian), + 32 => mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, vaddr), endian), + 64 => mem.writeInt(u64, try code.addManyAsArray(8), vaddr, endian), + else => unreachable, + } + + return Result{ .appended = {} }; +} |
