authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-28 19:13:15+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-05 08:56:01+01:00
loge3121accacaa2b9debaa60e0d4e8188de0b6a2f4
treeefd10cf4f4f674ed2773bddfcf2c17cad9c4d8fa
parentf2a5d0bf94897554e25e889dc1c6c4c7fc6c1217
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: introduce logical immediate instructions


4 files changed, 186 insertions(+), 40 deletions(-)

src/arch/aarch64/CodeGen.zig+81-23
......@@ -950,10 +950,69 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
950950 switch (operand_ty.zigTypeTag()) {
951951 .Bool => {
952952 // TODO convert this to mvn + and
953 const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool);
954 break :result dest;
953 const op_reg = switch (operand) {
954 .register => |r| r,
955 else => try self.copyToTmpRegister(operand_ty, operand),
956 };
957 self.register_manager.freezeRegs(&.{op_reg});
958 defer self.register_manager.unfreezeRegs(&.{op_reg});
959
960 const dest_reg = blk: {
961 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
962 break :blk op_reg;
963 }
964
965 break :blk try self.register_manager.allocReg(null);
966 };
967
968 _ = try self.addInst(.{
969 .tag = .eor_immediate,
970 .data = .{ .rr_bitmask = .{
971 .rd = dest_reg,
972 .rn = op_reg,
973 .imms = 0b000000,
974 .immr = 0b000000,
975 .n = 0b1,
976 } },
977 });
978
979 break :result MCValue{ .register = dest_reg };
980 },
981 .Vector => return self.fail("TODO bitwise not for vectors", .{}),
982 .Int => {
983 const int_info = operand_ty.intInfo(self.target.*);
984 if (int_info.bits <= 64) {
985 const op_reg = switch (operand) {
986 .register => |r| r,
987 else => try self.copyToTmpRegister(operand_ty, operand),
988 };
989 self.register_manager.freezeRegs(&.{op_reg});
990 defer self.register_manager.unfreezeRegs(&.{op_reg});
991
992 const dest_reg = blk: {
993 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
994 break :blk op_reg;
995 }
996
997 break :blk try self.register_manager.allocReg(null);
998 };
999
1000 _ = try self.addInst(.{
1001 .tag = .mvn,
1002 .data = .{ .rr_imm6_shift = .{
1003 .rd = dest_reg,
1004 .rm = op_reg,
1005 .imm6 = 0,
1006 .shift = .lsl,
1007 } },
1008 });
1009
1010 break :result MCValue{ .register = dest_reg };
1011 } else {
1012 return self.fail("TODO AArch64 not on integers > u64/i64", .{});
1013 }
9551014 },
956 else => return self.fail("TODO bitwise not", .{}),
1015 else => unreachable,
9571016 }
9581017 },
9591018 }
......@@ -1259,15 +1318,13 @@ fn binOp(
12591318 }
12601319 },
12611320 // Bitwise operations on integers
1262 .xor => {
1321 .bit_and,
1322 .bit_or,
1323 .xor,
1324 => {
12631325 switch (lhs_ty.zigTypeTag()) {
12641326 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1265 .Int => return self.fail("TODO binary operations on vectors", .{}),
1266 .Bool => {
1267 assert(lhs_ty.eql(rhs_ty));
1268 // TODO boolean operations with immediates
1269 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1270 },
1327 .Int => return self.fail("TODO binary operations on integers", .{}),
12711328 else => unreachable,
12721329 }
12731330 },
......@@ -3136,11 +3193,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31363193 4, 8 => .str_stack,
31373194 else => unreachable, // unexpected abi size
31383195 };
3139 const rt: Register = switch (abi_size) {
3140 1, 2, 4 => reg.to32(),
3141 8 => reg.to64(),
3142 else => unreachable, // unexpected abi size
3143 };
3196 const rt = registerAlias(reg, abi_size);
31443197
31453198 _ = try self.addInst(.{
31463199 .tag = tag,
......@@ -3622,7 +3675,6 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
36223675fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
36233676 if (typed_value.val.isUndef())
36243677 return MCValue{ .undef = {} };
3625 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
36263678
36273679 if (typed_value.val.castTag(.decl_ref)) |payload| {
36283680 return self.lowerDeclRef(typed_value, payload.data);
......@@ -3652,13 +3704,19 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
36523704 },
36533705 .Int => {
36543706 const info = typed_value.ty.intInfo(self.target.*);
3655 if (info.bits <= ptr_bits and info.signedness == .signed) {
3656 return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) };
3657 }
3658 if (info.bits > ptr_bits or info.signedness == .signed) {
3659 return self.fail("TODO const int bigger than ptr and signed int", .{});
3707 if (info.bits <= 64) {
3708 const unsigned = switch (info.signedness) {
3709 .signed => blk: {
3710 const signed = typed_value.val.toSignedInt();
3711 break :blk @bitCast(u64, signed);
3712 },
3713 .unsigned => typed_value.val.toUnsignedInt(),
3714 };
3715
3716 return MCValue{ .immediate = unsigned };
3717 } else {
3718 return self.lowerUnnamedConst(typed_value);
36603719 }
3661 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
36623720 },
36633721 .Bool => {
36643722 return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) };
......@@ -3875,7 +3933,7 @@ fn parseRegName(name: []const u8) ?Register {
38753933 return std.meta.stringToEnum(Register, name);
38763934}
38773935
3878fn registerAlias(reg: Register, size_bytes: u32) Register {
3936fn registerAlias(reg: Register, size_bytes: u64) Register {
38793937 if (size_bytes == 0) {
38803938 unreachable; // should be comptime known
38813939 } else if (size_bytes <= 4) {
src/arch/aarch64/Emit.zig+20-3
......@@ -95,6 +95,8 @@ pub fn emitMir(
9595
9696 .call_extern => try emit.mirCallExtern(inst),
9797
98 .eor_immediate => try emit.mirLogicalImmediate(inst),
99
98100 .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
99101 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
100102 .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
......@@ -605,6 +607,21 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
605607 }
606608}
607609
610fn mirLogicalImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
611 const tag = emit.mir.instructions.items(.tag)[inst];
612 const rr_bitmask = emit.mir.instructions.items(.data)[inst].rr_bitmask;
613 const rd = rr_bitmask.rd;
614 const rn = rr_bitmask.rn;
615 const imms = rr_bitmask.imms;
616 const immr = rr_bitmask.immr;
617 const n = rr_bitmask.n;
618
619 switch (tag) {
620 .eor_immediate => try emit.writeInstruction(Instruction.eorImmediate(rd, rn, imms, immr, n)),
621 else => unreachable,
622 }
623}
624
608625fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
609626 const tag = emit.mir.instructions.items(.tag)[inst];
610627 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 {
643660 const imm6 = rrr_imm6_logical_shift.imm6;
644661
645662 switch (tag) {
646 .eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)),
663 .eor_shifted_register => try emit.writeInstruction(Instruction.eorShiftedRegister(rd, rn, rm, shift, imm6)),
647664 else => unreachable,
648665 }
649666}
......@@ -844,7 +861,7 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
844861 switch (tag) {
845862 .mov_register => {
846863 const rr = emit.mir.instructions.items(.data)[inst].rr;
847 try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0));
864 try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, .xzr, rr.rn, .lsl, 0));
848865 },
849866 .mov_to_from_sp => {
850867 const rr = emit.mir.instructions.items(.data)[inst].rr;
......@@ -852,7 +869,7 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
852869 },
853870 .mvn => {
854871 const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;
855 try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0));
872 try emit.writeInstruction(Instruction.ornShiftedRegister(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, rr_imm6_shift.shift, rr_imm6_shift.imm6));
856873 },
857874 else => unreachable,
858875 }
src/arch/aarch64/Mir.zig+15-2
......@@ -54,6 +54,8 @@ pub const Inst = struct {
5454 dbg_epilogue_begin,
5555 /// Pseudo-instruction: Update debug line
5656 dbg_line,
57 /// Bitwise Exclusive OR (immediate)
58 eor_immediate,
5759 /// Bitwise Exclusive OR (shifted register)
5860 eor_shifted_register,
5961 /// Loads the contents into a register
......@@ -231,14 +233,25 @@ pub const Inst = struct {
231233 imm12: u12,
232234 sh: u1 = 0,
233235 },
234 /// Two registers and a shift (shift type and 6-bit amount)
236 /// Two registers and a shift (logical instruction version)
237 /// (shift type and 6-bit amount)
235238 ///
236239 /// Used by e.g. mvn
237240 rr_imm6_shift: struct {
238241 rd: Register,
239242 rm: Register,
240243 imm6: u6,
241 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
244 shift: bits.Instruction.LogicalShiftedRegisterShift,
245 },
246 /// Two registers and a bitmask immediate
247 ///
248 /// Used by e.g. eor_immediate
249 rr_bitmask: struct {
250 rd: Register,
251 rn: Register,
252 imms: u6,
253 immr: u6,
254 n: u1,
242255 },
243256 /// Two registers
244257 ///
src/arch/aarch64/bits.zig+70-12
......@@ -323,6 +323,16 @@ pub const Instruction = union(enum) {
323323 op: u1,
324324 sf: u1,
325325 },
326 logical_immediate: packed struct {
327 rd: u5,
328 rn: u5,
329 imms: u6,
330 immr: u6,
331 n: u1,
332 fixed: u6 = 0b100100,
333 opc: u2,
334 sf: u1,
335 },
326336 add_subtract_shifted_register: packed struct {
327337 rd: u5,
328338 rn: u5,
......@@ -487,6 +497,7 @@ pub const Instruction = union(enum) {
487497 .no_operation => |v| @bitCast(u32, v),
488498 .logical_shifted_register => |v| @bitCast(u32, v),
489499 .add_subtract_immediate => |v| @bitCast(u32, v),
500 .logical_immediate => |v| @bitCast(u32, v),
490501 .add_subtract_shifted_register => |v| @bitCast(u32, v),
491502 // TODO once packed structs work, this can be refactored
492503 .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) {
900911 };
901912 }
902913
914 fn logicalImmediate(
915 opc: u2,
916 rd: Register,
917 rn: Register,
918 imms: u6,
919 immr: u6,
920 n: u1,
921 ) Instruction {
922 return Instruction{
923 .logical_immediate = .{
924 .rd = rd.enc(),
925 .rn = rn.enc(),
926 .imms = imms,
927 .immr = immr,
928 .n = n,
929 .opc = opc,
930 .sf = switch (rd.size()) {
931 32 => 0b0,
932 64 => 0b1,
933 else => unreachable, // unexpected register size
934 },
935 },
936 };
937 }
938
903939 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
904940
905941 fn addSubtractShiftedRegister(
......@@ -1173,7 +1209,7 @@ pub const Instruction = union(enum) {
11731209
11741210 // Logical (shifted register)
11751211
1176 pub fn @"and"(
1212 pub fn andShiftedRegister(
11771213 rd: Register,
11781214 rn: Register,
11791215 rm: Register,
......@@ -1183,7 +1219,7 @@ pub const Instruction = union(enum) {
11831219 return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
11841220 }
11851221
1186 pub fn bic(
1222 pub fn bicShiftedRegister(
11871223 rd: Register,
11881224 rn: Register,
11891225 rm: Register,
......@@ -1193,7 +1229,7 @@ pub const Instruction = union(enum) {
11931229 return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
11941230 }
11951231
1196 pub fn orr(
1232 pub fn orrShiftedRegister(
11971233 rd: Register,
11981234 rn: Register,
11991235 rm: Register,
......@@ -1203,7 +1239,7 @@ pub const Instruction = union(enum) {
12031239 return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
12041240 }
12051241
1206 pub fn orn(
1242 pub fn ornShiftedRegister(
12071243 rd: Register,
12081244 rn: Register,
12091245 rm: Register,
......@@ -1213,7 +1249,7 @@ pub const Instruction = union(enum) {
12131249 return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
12141250 }
12151251
1216 pub fn eor(
1252 pub fn eorShiftedRegister(
12171253 rd: Register,
12181254 rn: Register,
12191255 rm: Register,
......@@ -1223,7 +1259,7 @@ pub const Instruction = union(enum) {
12231259 return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
12241260 }
12251261
1226 pub fn eon(
1262 pub fn eonShiftedRegister(
12271263 rd: Register,
12281264 rn: Register,
12291265 rm: Register,
......@@ -1233,7 +1269,7 @@ pub const Instruction = union(enum) {
12331269 return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
12341270 }
12351271
1236 pub fn ands(
1272 pub fn andsShiftedRegister(
12371273 rd: Register,
12381274 rn: Register,
12391275 rm: Register,
......@@ -1243,7 +1279,7 @@ pub const Instruction = union(enum) {
12431279 return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
12441280 }
12451281
1246 pub fn bics(
1282 pub fn bicsShiftedRegister(
12471283 rd: Register,
12481284 rn: Register,
12491285 rm: Register,
......@@ -1271,6 +1307,24 @@ pub const Instruction = union(enum) {
12711307 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
12721308 }
12731309
1310 // Logical (immediate)
1311
1312 pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1313 return logicalImmediate(0b00, rd, rn, imms, immr, n);
1314 }
1315
1316 pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1317 return logicalImmediate(0b01, rd, rn, imms, immr, n);
1318 }
1319
1320 pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1321 return logicalImmediate(0b10, rd, rn, imms, immr, n);
1322 }
1323
1324 pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1325 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1326 }
1327
12741328 // Add/subtract (shifted register)
12751329
12761330 pub fn addShiftedRegister(
......@@ -1378,11 +1432,11 @@ test "serialize instructions" {
13781432
13791433 const testcases = [_]Testcase{
13801434 .{ // orr x0, xzr, x1
1381 .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0),
1435 .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
13821436 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
13831437 },
13841438 .{ // orn x0, xzr, x1
1385 .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0),
1439 .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
13861440 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
13871441 },
13881442 .{ // movz x1, #4
......@@ -1502,11 +1556,11 @@ test "serialize instructions" {
15021556 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
15031557 },
15041558 .{ // and x0, x4, x2
1505 .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0),
1559 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0),
15061560 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
15071561 },
15081562 .{ // and x0, x4, x2, lsl #0x8
1509 .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8),
1563 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8),
15101564 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
15111565 },
15121566 .{ // add x0, x10, #10
......@@ -1537,6 +1591,10 @@ test "serialize instructions" {
15371591 .inst = Instruction.mul(.x1, .x4, .x9),
15381592 .expected = 0b1_00_11011_000_01001_0_11111_00100_00001,
15391593 },
1594 .{ // eor x3, x5, #1
1595 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
1596 .expected = 0b1_10_100100_1_000000_000000_00101_00011,
1597 },
15401598 };
15411599
15421600 for (testcases) |case| {