authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-09 22:36:23+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-13 11:32:07+01:00
log12207bbbd620903c81b0134816e71e373751b2d6
treec25e83b31f83f1ddc182b36c1ae0309b1e3e1024
parent03dddc8d9c7613aff877f0dcf0efe0193869ef73
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: Implement bit shifting with immediate operands


5 files changed, 163 insertions(+), 21 deletions(-)

src/arch/aarch64/CodeGen.zig+25-2
...@@ -1277,6 +1277,15 @@ fn binOpImmediate(...@@ -1277,6 +1277,15 @@ fn binOpImmediate(
1277 const mir_tag: Mir.Inst.Tag = switch (tag) {1277 const mir_tag: Mir.Inst.Tag = switch (tag) {
1278 .add => .add_immediate,1278 .add => .add_immediate,
1279 .sub => .sub_immediate,1279 .sub => .sub_immediate,
1280 .shl,
1281 .shl_exact,
1282 => .lsl_immediate,
1283 .shr,
1284 .shr_exact,
1285 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1286 .signed => Mir.Inst.Tag.asr_immediate,
1287 .unsigned => Mir.Inst.Tag.lsr_immediate,
1288 },
1280 else => unreachable,1289 else => unreachable,
1281 };1290 };
1282 const mir_data: Mir.Inst.Data = switch (tag) {1291 const mir_data: Mir.Inst.Data = switch (tag) {
...@@ -1287,6 +1296,15 @@ fn binOpImmediate(...@@ -1287,6 +1296,15 @@ fn binOpImmediate(
1287 .rn = lhs_reg,1296 .rn = lhs_reg,
1288 .imm12 = @intCast(u12, rhs.immediate),1297 .imm12 = @intCast(u12, rhs.immediate),
1289 } },1298 } },
1299 .shl,
1300 .shl_exact,
1301 .shr,
1302 .shr_exact,
1303 => .{ .rr_shift = .{
1304 .rd = dest_reg,
1305 .rn = lhs_reg,
1306 .shift = @intCast(u6, rhs.immediate),
1307 } },
1290 else => unreachable,1308 else => unreachable,
1291 };1309 };
12921310
...@@ -1407,8 +1425,13 @@ fn binOp(...@@ -1407,8 +1425,13 @@ fn binOp(
1407 .Int => {1425 .Int => {
1408 const int_info = lhs_ty.intInfo(self.target.*);1426 const int_info = lhs_ty.intInfo(self.target.*);
1409 if (int_info.bits <= 64) {1427 if (int_info.bits <= 64) {
1410 // TODO immediate shifts1428 const rhs_immediate_ok = rhs == .immediate;
1411 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1429
1430 if (rhs_immediate_ok) {
1431 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1432 } else {
1433 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1434 }
1412 } else {1435 } else {
1413 return self.fail("TODO binary operations on int with bits > 64", .{});1436 return self.fail("TODO binary operations on int with bits > 64", .{});
1414 }1437 }
src/arch/aarch64/Emit.zig+22-17
...@@ -84,6 +84,10 @@ pub fn emitMir(...@@ -84,6 +84,10 @@ pub fn emitMir(
84 .lsl_register => try emit.mirShiftRegister(inst),84 .lsl_register => try emit.mirShiftRegister(inst),
85 .lsr_register => try emit.mirShiftRegister(inst),85 .lsr_register => try emit.mirShiftRegister(inst),
8686
87 .asr_immediate => try emit.mirShiftImmediate(inst),
88 .lsl_immediate => try emit.mirShiftImmediate(inst),
89 .lsr_immediate => try emit.mirShiftImmediate(inst),
90
87 .b_cond => try emit.mirConditionalBranchImmediate(inst),91 .b_cond => try emit.mirConditionalBranchImmediate(inst),
8892
89 .b => try emit.mirBranch(inst),93 .b => try emit.mirBranch(inst),
...@@ -378,20 +382,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {...@@ -378,20 +382,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
378 return error.EmitFail;382 return error.EmitFail;
379}383}
380384
381fn moveImmediate(emit: *Emit, reg: Register, imm64: u64) !void {
382 try emit.writeInstruction(Instruction.movz(reg, @truncate(u16, imm64), 0));
383
384 if (imm64 > math.maxInt(u16)) {
385 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 16), 16));
386 }
387 if (imm64 > math.maxInt(u32)) {
388 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 32), 32));
389 }
390 if (imm64 > math.maxInt(u48)) {
391 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 48), 48));
392 }
393}
394
395fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {385fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
396 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);386 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
397 const delta_pc: usize = self.code.items.len - self.prev_di_pc;387 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
...@@ -481,9 +471,24 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -481,9 +471,24 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
481 const rm = rrr.rm;471 const rm = rrr.rm;
482472
483 switch (tag) {473 switch (tag) {
484 .asr_register => try emit.writeInstruction(Instruction.asrv(rd, rn, rm)),474 .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),
485 .lsl_register => try emit.writeInstruction(Instruction.lslv(rd, rn, rm)),475 .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),
486 .lsr_register => try emit.writeInstruction(Instruction.lsrv(rd, rn, rm)),476 .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)),
477 else => unreachable,
478 }
479}
480
481fn mirShiftImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
482 const tag = emit.mir.instructions.items(.tag)[inst];
483 const rr_shift = emit.mir.instructions.items(.data)[inst].rr_shift;
484 const rd = rr_shift.rd;
485 const rn = rr_shift.rn;
486 const shift = rr_shift.shift;
487
488 switch (tag) {
489 .asr_immediate => try emit.writeInstruction(Instruction.asrImmediate(rd, rn, shift)),
490 .lsl_immediate => try emit.writeInstruction(Instruction.lslImmediate(rd, rn, shift)),
491 .lsr_immediate => try emit.writeInstruction(Instruction.lsrImmediate(rd, rn, shift)),
487 else => unreachable,492 else => unreachable,
488 }493 }
489}494}
src/arch/aarch64/Mir.zig+15-1
...@@ -30,6 +30,8 @@ pub const Inst = struct {...@@ -30,6 +30,8 @@ pub const Inst = struct {
30 add_shifted_register,30 add_shifted_register,
31 /// Bitwise AND (shifted register)31 /// Bitwise AND (shifted register)
32 and_shifted_register,32 and_shifted_register,
33 /// Arithmetic Shift Right (immediate)
34 asr_immediate,
33 /// Arithmetic Shift Right (register)35 /// Arithmetic Shift Right (register)
34 asr_register,36 asr_register,
35 /// Branch conditionally37 /// Branch conditionally
...@@ -98,8 +100,12 @@ pub const Inst = struct {...@@ -98,8 +100,12 @@ pub const Inst = struct {
98 ldrh_immediate,100 ldrh_immediate,
99 /// Load Register Halfword (register)101 /// Load Register Halfword (register)
100 ldrh_register,102 ldrh_register,
103 /// Logical Shift Left (immediate)
104 lsl_immediate,
101 /// Logical Shift Left (register)105 /// Logical Shift Left (register)
102 lsl_register,106 lsl_register,
107 /// Logical Shift Right (immediate)
108 lsr_immediate,
103 /// Logical Shift Right (register)109 /// Logical Shift Right (register)
104 lsr_register,110 lsr_register,
105 /// Move (to/from SP)111 /// Move (to/from SP)
...@@ -263,7 +269,15 @@ pub const Inst = struct {...@@ -263,7 +269,15 @@ pub const Inst = struct {
263 immr: u6,269 immr: u6,
264 n: u1,270 n: u1,
265 },271 },
266 /// Two registers272 /// Two registers and a 6-bit unsigned shift
273 ///
274 /// Used by e.g. lsl_immediate
275 rr_shift: struct {
276 rd: Register,
277 rn: Register,
278 shift: u6,
279 },
280 /// Three registers
267 ///281 ///
268 /// Used by e.g. mul282 /// Used by e.g. mul
269 rrr: struct {283 rrr: struct {
src/arch/aarch64/bits.zig+100
...@@ -308,6 +308,16 @@ pub const Instruction = union(enum) {...@@ -308,6 +308,16 @@ pub const Instruction = union(enum) {
308 opc: u2,308 opc: u2,
309 sf: u1,309 sf: u1,
310 },310 },
311 bitfield: packed struct {
312 rd: u5,
313 rn: u5,
314 imms: u6,
315 immr: u6,
316 n: u1,
317 fixed: u6 = 0b100110,
318 opc: u2,
319 sf: u1,
320 },
311 add_subtract_shifted_register: packed struct {321 add_subtract_shifted_register: packed struct {
312 rd: u5,322 rd: u5,
313 rn: u5,323 rn: u5,
...@@ -483,6 +493,7 @@ pub const Instruction = union(enum) {...@@ -483,6 +493,7 @@ pub const Instruction = union(enum) {
483 .logical_shifted_register => |v| @bitCast(u32, v),493 .logical_shifted_register => |v| @bitCast(u32, v),
484 .add_subtract_immediate => |v| @bitCast(u32, v),494 .add_subtract_immediate => |v| @bitCast(u32, v),
485 .logical_immediate => |v| @bitCast(u32, v),495 .logical_immediate => |v| @bitCast(u32, v),
496 .bitfield => |v| @bitCast(u32, v),
486 .add_subtract_shifted_register => |v| @bitCast(u32, v),497 .add_subtract_shifted_register => |v| @bitCast(u32, v),
487 // TODO once packed structs work, this can be refactored498 // TODO once packed structs work, this can be refactored
488 .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),499 .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),
...@@ -922,6 +933,31 @@ pub const Instruction = union(enum) {...@@ -922,6 +933,31 @@ pub const Instruction = union(enum) {
922 };933 };
923 }934 }
924935
936 fn bitfield(
937 opc: u2,
938 n: u1,
939 rd: Register,
940 rn: Register,
941 immr: u6,
942 imms: u6,
943 ) Instruction {
944 return Instruction{
945 .bitfield = .{
946 .rd = rd.enc(),
947 .rn = rn.enc(),
948 .imms = imms,
949 .immr = immr,
950 .n = n,
951 .opc = opc,
952 .sf = switch (rd.size()) {
953 32 => 0b0,
954 64 => 0b1,
955 else => unreachable, // unexpected register size
956 },
957 },
958 };
959 }
960
925 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };961 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
926962
927 fn addSubtractShiftedRegister(963 fn addSubtractShiftedRegister(
...@@ -1334,6 +1370,50 @@ pub const Instruction = union(enum) {...@@ -1334,6 +1370,50 @@ pub const Instruction = union(enum) {
1334 return logicalImmediate(0b11, rd, rn, imms, immr, n);1370 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1335 }1371 }
13361372
1373 // Bitfield
1374
1375 pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1376 const n: u1 = switch (rd.size()) {
1377 32 => 0b0,
1378 64 => 0b1,
1379 else => unreachable, // unexpected register size
1380 };
1381 return bitfield(0b00, n, rd, rn, immr, imms);
1382 }
1383
1384 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1385 const n: u1 = switch (rd.size()) {
1386 32 => 0b0,
1387 64 => 0b1,
1388 else => unreachable, // unexpected register size
1389 };
1390 return bitfield(0b01, n, rd, rn, immr, imms);
1391 }
1392
1393 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1394 const n: u1 = switch (rd.size()) {
1395 32 => 0b0,
1396 64 => 0b1,
1397 else => unreachable, // unexpected register size
1398 };
1399 return bitfield(0b10, n, rd, rn, immr, imms);
1400 }
1401
1402 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1403 const imms = @intCast(u6, rd.size() - 1);
1404 return sbfm(rd, rn, shift, imms);
1405 }
1406
1407 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1408 const size = @intCast(u6, rd.size() - 1);
1409 return ubfm(rd, rn, size - shift + 1, size - shift);
1410 }
1411
1412 pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1413 const imms = @intCast(u6, rd.size() - 1);
1414 return ubfm(rd, rn, shift, imms);
1415 }
1416
1337 // Add/subtract (shifted register)1417 // Add/subtract (shifted register)
13381418
1339 pub fn addShiftedRegister(1419 pub fn addShiftedRegister(
...@@ -1441,6 +1521,10 @@ pub const Instruction = union(enum) {...@@ -1441,6 +1521,10 @@ pub const Instruction = union(enum) {
1441 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {1521 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
1442 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);1522 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
1443 }1523 }
1524
1525 pub const asrRegister = asrv;
1526 pub const lslRegister = lslv;
1527 pub const lsrRegister = lsrv;
1444};1528};
14451529
1446test {1530test {
...@@ -1622,6 +1706,22 @@ test "serialize instructions" {...@@ -1622,6 +1706,22 @@ test "serialize instructions" {
1622 .inst = Instruction.lslv(.x6, .x9, .x10),1706 .inst = Instruction.lslv(.x6, .x9, .x10),
1623 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,1707 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
1624 },1708 },
1709 .{ // lsl x4, x2, #42
1710 .inst = Instruction.lslImmediate(.x4, .x2, 42),
1711 .expected = 0b1_10_100110_1_010110_010101_00010_00100,
1712 },
1713 .{ // lsl x4, x2, #63
1714 .inst = Instruction.lslImmediate(.x4, .x2, 63),
1715 .expected = 0b1_10_100110_1_000001_000000_00010_00100,
1716 },
1717 .{ // lsr x4, x2, #42
1718 .inst = Instruction.lsrImmediate(.x4, .x2, 42),
1719 .expected = 0b1_10_100110_1_101010_111111_00010_00100,
1720 },
1721 .{ // lsr x4, x2, #63
1722 .inst = Instruction.lsrImmediate(.x4, .x2, 63),
1723 .expected = 0b1_10_100110_1_111111_111111_00010_00100,
1724 },
1625 };1725 };
16261726
1627 for (testcases) |case| {1727 for (testcases) |case| {
test/behavior/math.zig+1-1
...@@ -573,7 +573,7 @@ test "bit shift a u1" {...@@ -573,7 +573,7 @@ test "bit shift a u1" {
573573
574test "truncating shift right" {574test "truncating shift right" {
575 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO575 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO576// if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
577577
578 try testShrTrunc(maxInt(u16));578 try testShrTrunc(maxInt(u16));
579 comptime try testShrTrunc(maxInt(u16));579 comptime try testShrTrunc(maxInt(u16));