diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-02-28 19:13:15 +0100 |
|---|---|---|
| committer | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2022-03-05 08:56:01 +0100 |
| commit | e3121accacaa2b9debaa60e0d4e8188de0b6a2f4 (patch) | |
| tree | efd10cf4f4f674ed2773bddfcf2c17cad9c4d8fa /src | |
| parent | f2a5d0bf94897554e25e889dc1c6c4c7fc6c1217 (diff) | |
| download | zig-e3121accacaa2b9debaa60e0d4e8188de0b6a2f4.tar.gz zig-e3121accacaa2b9debaa60e0d4e8188de0b6a2f4.zip | |
stage2 AArch64: introduce logical immediate instructions
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 104 | ||||
| -rw-r--r-- | src/arch/aarch64/Emit.zig | 23 | ||||
| -rw-r--r-- | src/arch/aarch64/Mir.zig | 17 | ||||
| -rw-r--r-- | src/arch/aarch64/bits.zig | 82 |
4 files changed, 186 insertions, 40 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 19b444cb15..2c804d4840 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -950,10 +950,69 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { switch (operand_ty.zigTypeTag()) { .Bool => { // TODO convert this to mvn + and - const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool); - break :result dest; + const op_reg = switch (operand) { + .register => |r| r, + else => try self.copyToTmpRegister(operand_ty, operand), + }; + self.register_manager.freezeRegs(&.{op_reg}); + defer self.register_manager.unfreezeRegs(&.{op_reg}); + + const dest_reg = blk: { + if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :blk op_reg; + } + + break :blk try self.register_manager.allocReg(null); + }; + + _ = try self.addInst(.{ + .tag = .eor_immediate, + .data = .{ .rr_bitmask = .{ + .rd = dest_reg, + .rn = op_reg, + .imms = 0b000000, + .immr = 0b000000, + .n = 0b1, + } }, + }); + + break :result MCValue{ .register = dest_reg }; + }, + .Vector => return self.fail("TODO bitwise not for vectors", .{}), + .Int => { + const int_info = operand_ty.intInfo(self.target.*); + if (int_info.bits <= 64) { + const op_reg = switch (operand) { + .register => |r| r, + else => try self.copyToTmpRegister(operand_ty, operand), + }; + self.register_manager.freezeRegs(&.{op_reg}); + defer self.register_manager.unfreezeRegs(&.{op_reg}); + + const dest_reg = blk: { + if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :blk op_reg; + } + + break :blk try self.register_manager.allocReg(null); + }; + + _ = try self.addInst(.{ + .tag = .mvn, + .data = .{ .rr_imm6_shift = .{ + .rd = dest_reg, + .rm = op_reg, + .imm6 = 0, + .shift = .lsl, + } }, + }); + + break :result MCValue{ .register = dest_reg }; + } else { + return self.fail("TODO AArch64 not on integers > u64/i64", .{}); + } }, - else => return self.fail("TODO bitwise not", .{}), + else => unreachable, } }, } @@ -1259,15 +1318,13 @@ fn binOp( } }, // Bitwise operations on integers - .xor => { + .bit_and, + .bit_or, + .xor, + => { switch (lhs_ty.zigTypeTag()) { .Vector => return self.fail("TODO binary operations on vectors", .{}), - .Int => return self.fail("TODO binary operations on vectors", .{}), - .Bool => { - assert(lhs_ty.eql(rhs_ty)); - // TODO boolean operations with immediates - return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); - }, + .Int => return self.fail("TODO binary operations on integers", .{}), else => unreachable, } }, @@ -3136,11 +3193,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro 4, 8 => .str_stack, else => unreachable, // unexpected abi size }; - const rt: Register = switch (abi_size) { - 1, 2, 4 => reg.to32(), - 8 => reg.to64(), - else => unreachable, // unexpected abi size - }; + const rt = registerAlias(reg, abi_size); _ = try self.addInst(.{ .tag = tag, @@ -3622,7 +3675,6 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.isUndef()) return MCValue{ .undef = {} }; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); if (typed_value.val.castTag(.decl_ref)) |payload| { return self.lowerDeclRef(typed_value, payload.data); @@ -3652,13 +3704,19 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { }, .Int => { const info = typed_value.ty.intInfo(self.target.*); - if (info.bits <= ptr_bits and info.signedness == .signed) { - return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; - } - if (info.bits > ptr_bits or info.signedness == .signed) { - return self.fail("TODO const int bigger than ptr and signed int", .{}); + if (info.bits <= 64) { + const unsigned = switch (info.signedness) { + .signed => blk: { + const signed = typed_value.val.toSignedInt(); + break :blk @bitCast(u64, signed); + }, + .unsigned => typed_value.val.toUnsignedInt(), + }; + + return MCValue{ .immediate = unsigned }; + } else { + return self.lowerUnnamedConst(typed_value); } - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; }, .Bool => { return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; @@ -3875,7 +3933,7 @@ fn parseRegName(name: []const u8) ?Register { return std.meta.stringToEnum(Register, name); } -fn registerAlias(reg: Register, size_bytes: u32) Register { +fn registerAlias(reg: Register, size_bytes: u64) Register { if (size_bytes == 0) { unreachable; // should be comptime known } else if (size_bytes <= 4) { diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index d98aa09e56..922aa731ef 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -95,6 +95,8 @@ pub fn emitMir( .call_extern => try emit.mirCallExtern(inst), + .eor_immediate => try emit.mirLogicalImmediate(inst), + .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), @@ -605,6 +607,21 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { } } +fn mirLogicalImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const rr_bitmask = emit.mir.instructions.items(.data)[inst].rr_bitmask; + const rd = rr_bitmask.rd; + const rn = rr_bitmask.rn; + const imms = rr_bitmask.imms; + const immr = rr_bitmask.immr; + const n = rr_bitmask.n; + + switch (tag) { + .eor_immediate => try emit.writeInstruction(Instruction.eorImmediate(rd, rn, imms, immr, n)), + else => unreachable, + } +} + fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift; @@ -643,7 +660,7 @@ fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { const imm6 = rrr_imm6_logical_shift.imm6; switch (tag) { - .eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)), + .eor_shifted_register => try emit.writeInstruction(Instruction.eorShiftedRegister(rd, rn, rm, shift, imm6)), else => unreachable, } } @@ -844,7 +861,7 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void { switch (tag) { .mov_register => { const rr = emit.mir.instructions.items(.data)[inst].rr; - try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0)); + try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, .xzr, rr.rn, .lsl, 0)); }, .mov_to_from_sp => { const rr = emit.mir.instructions.items(.data)[inst].rr; @@ -852,7 +869,7 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void { }, .mvn => { const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift; - try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0)); + try emit.writeInstruction(Instruction.ornShiftedRegister(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, rr_imm6_shift.shift, rr_imm6_shift.imm6)); }, else => unreachable, } diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index c2ffbad422..7e9f8a819f 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -54,6 +54,8 @@ pub const Inst = struct { dbg_epilogue_begin, /// Pseudo-instruction: Update debug line dbg_line, + /// Bitwise Exclusive OR (immediate) + eor_immediate, /// Bitwise Exclusive OR (shifted register) eor_shifted_register, /// Loads the contents into a register @@ -231,14 +233,25 @@ pub const Inst = struct { imm12: u12, sh: u1 = 0, }, - /// Two registers and a shift (shift type and 6-bit amount) + /// Two registers and a shift (logical instruction version) + /// (shift type and 6-bit amount) /// /// Used by e.g. mvn rr_imm6_shift: struct { rd: Register, rm: Register, imm6: u6, - shift: bits.Instruction.AddSubtractShiftedRegisterShift, + shift: bits.Instruction.LogicalShiftedRegisterShift, + }, + /// Two registers and a bitmask immediate + /// + /// Used by e.g. eor_immediate + rr_bitmask: struct { + rd: Register, + rn: Register, + imms: u6, + immr: u6, + n: u1, }, /// Two registers /// diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index c427f86472..9e5ad30701 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -323,6 +323,16 @@ pub const Instruction = union(enum) { op: u1, sf: u1, }, + logical_immediate: packed struct { + rd: u5, + rn: u5, + imms: u6, + immr: u6, + n: u1, + fixed: u6 = 0b100100, + opc: u2, + sf: u1, + }, add_subtract_shifted_register: packed struct { rd: u5, rn: u5, @@ -487,6 +497,7 @@ pub const Instruction = union(enum) { .no_operation => |v| @bitCast(u32, v), .logical_shifted_register => |v| @bitCast(u32, v), .add_subtract_immediate => |v| @bitCast(u32, v), + .logical_immediate => |v| @bitCast(u32, v), .add_subtract_shifted_register => |v| @bitCast(u32, v), // TODO once packed structs work, this can be refactored .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25), @@ -900,6 +911,31 @@ pub const Instruction = union(enum) { }; } + fn logicalImmediate( + opc: u2, + rd: Register, + rn: Register, + imms: u6, + immr: u6, + n: u1, + ) Instruction { + return Instruction{ + .logical_immediate = .{ + .rd = rd.enc(), + .rn = rn.enc(), + .imms = imms, + .immr = immr, + .n = n, + .opc = opc, + .sf = switch (rd.size()) { + 32 => 0b0, + 64 => 0b1, + else => unreachable, // unexpected register size + }, + }, + }; + } + pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ }; fn addSubtractShiftedRegister( @@ -1173,7 +1209,7 @@ pub const Instruction = union(enum) { // Logical (shifted register) - pub fn @"and"( + pub fn andShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1183,7 +1219,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount); } - pub fn bic( + pub fn bicShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1193,7 +1229,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount); } - pub fn orr( + pub fn orrShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1203,7 +1239,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount); } - pub fn orn( + pub fn ornShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1213,7 +1249,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount); } - pub fn eor( + pub fn eorShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1223,7 +1259,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount); } - pub fn eon( + pub fn eonShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1233,7 +1269,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount); } - pub fn ands( + pub fn andsShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1243,7 +1279,7 @@ pub const Instruction = union(enum) { return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount); } - pub fn bics( + pub fn bicsShiftedRegister( rd: Register, rn: Register, rm: Register, @@ -1271,6 +1307,24 @@ pub const Instruction = union(enum) { return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); } + // Logical (immediate) + + pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { + return logicalImmediate(0b00, rd, rn, imms, immr, n); + } + + pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { + return logicalImmediate(0b01, rd, rn, imms, immr, n); + } + + pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { + return logicalImmediate(0b10, rd, rn, imms, immr, n); + } + + pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { + return logicalImmediate(0b11, rd, rn, imms, immr, n); + } + // Add/subtract (shifted register) pub fn addShiftedRegister( @@ -1378,11 +1432,11 @@ test "serialize instructions" { const testcases = [_]Testcase{ .{ // orr x0, xzr, x1 - .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0), + .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0), .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, }, .{ // orn x0, xzr, x1 - .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0), + .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0), .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, }, .{ // movz x1, #4 @@ -1502,11 +1556,11 @@ test "serialize instructions" { .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, }, .{ // and x0, x4, x2 - .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0), + .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0), .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, }, .{ // and x0, x4, x2, lsl #0x8 - .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8), + .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8), .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, }, .{ // add x0, x10, #10 @@ -1537,6 +1591,10 @@ test "serialize instructions" { .inst = Instruction.mul(.x1, .x4, .x9), .expected = 0b1_00_11011_000_01001_0_11111_00100_00001, }, + .{ // eor x3, x5, #1 + .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), + .expected = 0b1_10_100100_1_000000_000000_00101_00011, + }, }; for (testcases) |case| { |
