diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-02-24 22:18:21 +0100 |
|---|---|---|
| committer | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-02-26 12:59:57 +0100 |
| commit | 8ef80cfaab2a74506d7b3a866dc066d9cd281f55 (patch) | |
| tree | 5f96c3e02d299e29a9738c74ae429b9f967aac9d /src/arch | |
| parent | db82c1b9820449f2d1e6ef54dd32ec3ffd3c583f (diff) | |
| download | zig-8ef80cfaab2a74506d7b3a866dc066d9cd281f55.tar.gz zig-8ef80cfaab2a74506d7b3a866dc066d9cd281f55.zip | |
stage2 ARM: implement truncate to ints with bits <= 32
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 69 | ||||
| -rw-r--r-- | src/arch/arm/Emit.zig | 19 | ||||
| -rw-r--r-- | src/arch/arm/Mir.zig | 14 | ||||
| -rw-r--r-- | src/arch/arm/bits.zig | 44 |
4 files changed, 142 insertions, 4 deletions
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 8ad9e980cf..467e560687 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -439,7 +439,7 @@ fn gen(self: *Self) !void { // the code. Therefore, we can just delete // the space initially reserved for the // jump - self.mir_instructions.len -= 1; + self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]); } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { self.mir_instructions.set(jmp_reloc, .{ .tag = .b, @@ -749,6 +749,17 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { const elem_ty = self.air.typeOfIndex(inst).elemType(); + + if (!elem_ty.hasRuntimeBits()) { + // As this stack item will never be dereferenced at runtime, + // return the current stack offset + try self.stack.putNoClobber(self.gpa, self.next_stack_offset, .{ + .inst = inst, + .size = 0, + }); + return self.next_stack_offset; + } + const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); }; @@ -872,11 +883,61 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + const operand_ty = self.air.typeOf(ty_op.operand); const operand = try self.resolveInst(ty_op.operand); - _ = operand; + const info_a = operand_ty.intInfo(self.target.*); + const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); - return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + const result: MCValue = blk: { + if (info_b.bits <= 32) { + const operand_reg = switch (operand) { + .register => |r| r, + else => operand_reg: { + if (info_a.bits <= 32) { + break :operand_reg try self.copyToTmpRegister(operand_ty, operand); + } else { + return self.fail("TODO load least significant word into register", .{}); + } + }, + }; + self.register_manager.freezeRegs(&.{operand_reg}); + defer self.register_manager.unfreezeRegs(&.{operand_reg}); + + const dest_reg = dest_reg: { + if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :dest_reg operand_reg; + } + + break :dest_reg try self.register_manager.allocReg(null); + }; + + switch (info_b.bits) { + 32 => { + try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg }); + break :blk MCValue{ .register = dest_reg }; + }, + else => { + _ = try self.addInst(.{ + .tag = switch (info_b.signedness) { + .signed => .sbfx, + .unsigned => .ubfx, + }, + .data = .{ .rr_lsb_width = .{ + .rd = dest_reg, + .rn = operand_reg, + .lsb = 0, + .width = @intCast(u6, info_b.bits), + } }, + }); + break :blk MCValue{ .register = dest_reg }; + }, + } + } else { + return self.fail("TODO: truncate to ints > 32 bits", .{}); + } + }; + + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 3ee70583d0..d4561553c4 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -130,6 +130,9 @@ pub fn emitMir( .push => try emit.mirBlockDataTransfer(inst), .svc => try emit.mirSupervisorCall(inst), + + .sbfx => try emit.mirBitFieldExtract(inst), + .ubfx => try emit.mirBitFieldExtract(inst), } } } @@ -691,3 +694,19 @@ fn mirSupervisorCall(emit: *Emit, inst: Mir.Inst.Index) !void { else => unreachable, } } + +fn mirBitFieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const cond = emit.mir.instructions.items(.cond)[inst]; + const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width; + const rd = rr_lsb_width.rd; + const rn = rr_lsb_width.rn; + const lsb = rr_lsb_width.lsb; + const width = rr_lsb_width.width; + + switch (tag) { + .sbfx => try emit.writeInstruction(Instruction.sbfx(cond, rd, rn, lsb, width)), + .ubfx => try emit.writeInstruction(Instruction.ubfx(cond, rd, rn, lsb, width)), + else => unreachable, + } +} diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig index e6f1bcb0a2..c85acae085 100644 --- a/src/arch/arm/Mir.zig +++ b/src/arch/arm/Mir.zig @@ -88,6 +88,8 @@ pub const Inst = struct { push, /// Reverse Subtract rsb, + /// Signed Bit Field Extract + sbfx, /// Store Register str, /// Store Register Byte @@ -98,6 +100,8 @@ pub const Inst = struct { sub, /// Supervisor Call svc, + /// Unsigned Bit Field Extract + ubfx, }; /// The position of an MIR instruction within the `Mir` instructions array. @@ -179,6 +183,16 @@ pub const Inst = struct { rn: Register, offset: bits.Instruction.ExtraLoadStoreOffsetArgs, }, + /// Two registers and a lsb (range 0-31) and a width (range + /// 1-32) + /// + /// Used by e.g. sbfx + rr_lsb_width: struct { + rd: Register, + rn: Register, + lsb: u5, + width: u6, + }, /// Three registers /// /// Used by e.g. mul diff --git a/src/arch/arm/bits.zig b/src/arch/arm/bits.zig index 792bf0dc05..a8866ac5c9 100644 --- a/src/arch/arm/bits.zig +++ b/src/arch/arm/bits.zig @@ -1,5 +1,6 @@ const std = @import("std"); const DW = std.dwarf; +const assert = std.debug.assert; const testing = std.testing; /// The condition field specifies the flags necessary for an @@ -237,6 +238,17 @@ pub const Instruction = union(enum) { fixed_3: u5 = 0b00010, cond: u4, }, + bit_field_extract: packed struct { + rn: u4, + fixed_1: u3 = 0b101, + lsb: u5, + rd: u4, + widthm1: u5, + fixed_2: u1 = 0b1, + unsigned: u1, + fixed_3: u5 = 0b01111, + cond: u4, + }, single_data_transfer: packed struct { offset: u12, rd: u4, @@ -576,6 +588,7 @@ pub const Instruction = union(enum) { .multiply => |v| @bitCast(u32, v), .multiply_long => |v| @bitCast(u32, v), .integer_saturating_arithmetic => |v| @bitCast(u32, v), + .bit_field_extract => |v| @bitCast(u32, v), .single_data_transfer => |v| @bitCast(u32, v), .extra_load_store => |v| @bitCast(u32, v), .block_data_transfer => |v| @bitCast(u32, v), @@ -691,6 +704,27 @@ pub const Instruction = union(enum) { }; } + fn bitFieldExtract( + unsigned: u1, + cond: Condition, + rd: Register, + rn: Register, + lsb: u5, + width: u6, + ) Instruction { + assert(width > 0 and width <= 32); + return Instruction{ + .bit_field_extract = .{ + .rn = rn.id(), + .lsb = lsb, + .rd = rd.id(), + .widthm1 = @intCast(u5, width - 1), + .unsigned = unsigned, + .cond = @enumToInt(cond), + }, + }; + } + fn singleDataTransfer( cond: Condition, rd: Register, @@ -1044,6 +1078,16 @@ pub const Instruction = union(enum) { return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn); } + // Bit field extract + + pub fn ubfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction { + return bitFieldExtract(0b1, cond, rd, rn, lsb, width); + } + + pub fn sbfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction { + return bitFieldExtract(0b0, cond, rd, rn, lsb, width); + } + // Single data transfer pub const OffsetArgs = struct { |
