| author | |
| committer | |
| log | 12207bbbd620903c81b0134816e71e373751b2d6 |
| tree | c25e83b31f83f1ddc182b36c1ae0309b1e3e1024 |
| parent | 03dddc8d9c7613aff877f0dcf0efe0193869ef73 |
| signature |
5 files changed, 163 insertions(+), 21 deletions(-)
src/arch/aarch64/CodeGen.zig+25-2| ... | ... | @@ -1277,6 +1277,15 @@ fn binOpImmediate( |
| 1277 | 1277 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1278 | 1278 | .add => .add_immediate, |
| 1279 | 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 | 1289 | else => unreachable, |
| 1281 | 1290 | }; |
| 1282 | 1291 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | ... | @@ -1287,6 +1296,15 @@ fn binOpImmediate( |
| 1287 | 1296 | .rn = lhs_reg, |
| 1288 | 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 | 1308 | else => unreachable, |
| 1291 | 1309 | }; |
| 1292 | 1310 | |
| ... | ... | @@ -1407,8 +1425,13 @@ fn binOp( |
| 1407 | 1425 | .Int => { |
| 1408 | 1426 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1409 | 1427 | if (int_info.bits <= 64) { |
| 1410 | // TODO immediate shifts | |
| 1411 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1428 | const rhs_immediate_ok = rhs == .immediate; | |
| 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 | 1435 | } else { |
| 1413 | 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 | 84 | .lsl_register => try emit.mirShiftRegister(inst), |
| 85 | 85 | .lsr_register => try emit.mirShiftRegister(inst), |
| 86 | 86 | |
| 87 | .asr_immediate => try emit.mirShiftImmediate(inst), | |
| 88 | .lsl_immediate => try emit.mirShiftImmediate(inst), | |
| 89 | .lsr_immediate => try emit.mirShiftImmediate(inst), | |
| 90 | ||
| 87 | 91 | .b_cond => try emit.mirConditionalBranchImmediate(inst), |
| 88 | 92 | |
| 89 | 93 | .b => try emit.mirBranch(inst), |
| ... | ... | @@ -378,20 +382,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 378 | 382 | return error.EmitFail; |
| 379 | 383 | } |
| 380 | 384 | |
| 381 | fn 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 | ||
| 395 | 385 | fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 396 | 386 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 397 | 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 | 471 | const rm = rrr.rm; |
| 482 | 472 | |
| 483 | 473 | switch (tag) { |
| 484 | .asr_register => try emit.writeInstruction(Instruction.asrv(rd, rn, rm)), | |
| 485 | .lsl_register => try emit.writeInstruction(Instruction.lslv(rd, rn, rm)), | |
| 486 | .lsr_register => try emit.writeInstruction(Instruction.lsrv(rd, rn, rm)), | |
| 474 | .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)), | |
| 475 | .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)), | |
| 476 | .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)), | |
| 477 | else => unreachable, | |
| 478 | } | |
| 479 | } | |
| 480 | ||
| 481 | fn 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 | 492 | else => unreachable, |
| 488 | 493 | } |
| 489 | 494 | } |
src/arch/aarch64/Mir.zig+15-1| ... | ... | @@ -30,6 +30,8 @@ pub const Inst = struct { |
| 30 | 30 | add_shifted_register, |
| 31 | 31 | /// Bitwise AND (shifted register) |
| 32 | 32 | and_shifted_register, |
| 33 | /// Arithmetic Shift Right (immediate) | |
| 34 | asr_immediate, | |
| 33 | 35 | /// Arithmetic Shift Right (register) |
| 34 | 36 | asr_register, |
| 35 | 37 | /// Branch conditionally |
| ... | ... | @@ -98,8 +100,12 @@ pub const Inst = struct { |
| 98 | 100 | ldrh_immediate, |
| 99 | 101 | /// Load Register Halfword (register) |
| 100 | 102 | ldrh_register, |
| 103 | /// Logical Shift Left (immediate) | |
| 104 | lsl_immediate, | |
| 101 | 105 | /// Logical Shift Left (register) |
| 102 | 106 | lsl_register, |
| 107 | /// Logical Shift Right (immediate) | |
| 108 | lsr_immediate, | |
| 103 | 109 | /// Logical Shift Right (register) |
| 104 | 110 | lsr_register, |
| 105 | 111 | /// Move (to/from SP) |
| ... | ... | @@ -263,7 +269,15 @@ pub const Inst = struct { |
| 263 | 269 | immr: u6, |
| 264 | 270 | n: u1, |
| 265 | 271 | }, |
| 266 | /// Two registers | |
| 272 | /// 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 | 282 | /// Used by e.g. mul |
| 269 | 283 | rrr: struct { |
src/arch/aarch64/bits.zig+100| ... | ... | @@ -308,6 +308,16 @@ pub const Instruction = union(enum) { |
| 308 | 308 | opc: u2, |
| 309 | 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 | 321 | add_subtract_shifted_register: packed struct { |
| 312 | 322 | rd: u5, |
| 313 | 323 | rn: u5, |
| ... | ... | @@ -483,6 +493,7 @@ pub const Instruction = union(enum) { |
| 483 | 493 | .logical_shifted_register => |v| @bitCast(u32, v), |
| 484 | 494 | .add_subtract_immediate => |v| @bitCast(u32, v), |
| 485 | 495 | .logical_immediate => |v| @bitCast(u32, v), |
| 496 | .bitfield => |v| @bitCast(u32, v), | |
| 486 | 497 | .add_subtract_shifted_register => |v| @bitCast(u32, v), |
| 487 | 498 | // TODO once packed structs work, this can be refactored |
| 488 | 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 | 933 | }; |
| 923 | 934 | } |
| 924 | 935 | |
| 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 | 961 | pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ }; |
| 926 | 962 | |
| 927 | 963 | fn addSubtractShiftedRegister( |
| ... | ... | @@ -1334,6 +1370,50 @@ pub const Instruction = union(enum) { |
| 1334 | 1370 | return logicalImmediate(0b11, rd, rn, imms, immr, n); |
| 1335 | 1371 | } |
| 1336 | 1372 | |
| 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 | 1417 | // Add/subtract (shifted register) |
| 1338 | 1418 | |
| 1339 | 1419 | pub fn addShiftedRegister( |
| ... | ... | @@ -1441,6 +1521,10 @@ pub const Instruction = union(enum) { |
| 1441 | 1521 | pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction { |
| 1442 | 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 | }; |
| 1445 | 1529 | |
| 1446 | 1530 | test { |
| ... | ... | @@ -1622,6 +1706,22 @@ test "serialize instructions" { |
| 1622 | 1706 | .inst = Instruction.lslv(.x6, .x9, .x10), |
| 1623 | 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 | }; |
| 1626 | 1726 | |
| 1627 | 1727 | for (testcases) |case| { |
test/behavior/math.zig+1-1| ... | ... | @@ -573,7 +573,7 @@ test "bit shift a u1" { |
| 573 | 573 | |
| 574 | 574 | test "truncating shift right" { |
| 575 | 575 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 576 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 576 | // if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 577 | 577 | |
| 578 | 578 | try testShrTrunc(maxInt(u16)); |
| 579 | 579 | comptime try testShrTrunc(maxInt(u16)); |