| author | |
| committer | |
| log | d112cd52f36cbb00e18009417044ab1e4496dd80 |
| tree | c9e34928674e6434c5a75171f6cb97d375293add |
| parent | f4421c01e8a8793a7c02fce870bacbb710bb1e12 |
4 files changed, 224 insertions(+), 37 deletions(-)
src/arch/aarch64/CodeGen.zig+46-32| ... | ... | @@ -1294,29 +1294,23 @@ fn binOpRegister( |
| 1294 | 1294 | }; |
| 1295 | 1295 | defer self.register_manager.unfreezeRegs(&.{rhs_reg}); |
| 1296 | 1296 | |
| 1297 | const dest_reg: Register = reg: { | |
| 1298 | const dest_reg = switch (mir_tag) { | |
| 1299 | .cmp_shifted_register => undefined, // cmp has no destination register | |
| 1300 | else => if (maybe_inst) |inst| blk: { | |
| 1301 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1302 | ||
| 1303 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | |
| 1304 | break :blk lhs_reg; | |
| 1305 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { | |
| 1306 | break :blk rhs_reg; | |
| 1307 | } else { | |
| 1308 | const raw_reg = try self.register_manager.allocReg(inst); | |
| 1309 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); | |
| 1310 | } | |
| 1311 | } else blk: { | |
| 1312 | const raw_reg = try self.register_manager.allocReg(null); | |
| 1297 | const dest_reg = switch (mir_tag) { | |
| 1298 | .cmp_shifted_register => undefined, // cmp has no destination register | |
| 1299 | else => if (maybe_inst) |inst| blk: { | |
| 1300 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1301 | ||
| 1302 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | |
| 1303 | break :blk lhs_reg; | |
| 1304 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { | |
| 1305 | break :blk rhs_reg; | |
| 1306 | } else { | |
| 1307 | const raw_reg = try self.register_manager.allocReg(inst); | |
| 1313 | 1308 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1314 | }, | |
| 1315 | }; | |
| 1316 | break :reg switch (mir_tag) { | |
| 1317 | .smull, .umull => dest_reg.to64(), | |
| 1318 | else => dest_reg, | |
| 1319 | }; | |
| 1309 | } | |
| 1310 | } else blk: { | |
| 1311 | const raw_reg = try self.register_manager.allocReg(null); | |
| 1312 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); | |
| 1313 | }, | |
| 1320 | 1314 | }; |
| 1321 | 1315 | |
| 1322 | 1316 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| ... | ... | @@ -1341,9 +1335,7 @@ fn binOpRegister( |
| 1341 | 1335 | .shift = .lsl, |
| 1342 | 1336 | } }, |
| 1343 | 1337 | .mul, |
| 1344 | .smulh, | |
| 1345 | 1338 | .smull, |
| 1346 | .umulh, | |
| 1347 | 1339 | .umull, |
| 1348 | 1340 | .lsl_register, |
| 1349 | 1341 | .asr_register, |
| ... | ... | @@ -1932,16 +1924,38 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1932 | 1924 | self.register_manager.freezeRegs(&.{truncated_reg}); |
| 1933 | 1925 | defer self.register_manager.unfreezeRegs(&.{truncated_reg}); |
| 1934 | 1926 | |
| 1935 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | |
| 1936 | _ = try self.binOp( | |
| 1937 | .cmp_eq, | |
| 1938 | null, | |
| 1939 | dest, | |
| 1940 | .{ .register = truncated_reg }, | |
| 1941 | Type.usize, | |
| 1942 | Type.usize, | |
| 1927 | try self.truncRegister( | |
| 1928 | dest_reg.to32(), | |
| 1929 | truncated_reg.to32(), | |
| 1930 | int_info.signedness, | |
| 1931 | int_info.bits, | |
| 1943 | 1932 | ); |
| 1944 | 1933 | |
| 1934 | switch (int_info.signedness) { | |
| 1935 | .signed => { | |
| 1936 | _ = try self.addInst(.{ | |
| 1937 | .tag = .cmp_extended_register, | |
| 1938 | .data = .{ .rr_extend_shift = .{ | |
| 1939 | .rn = dest_reg.to64(), | |
| 1940 | .rm = truncated_reg.to32(), | |
| 1941 | .ext_type = .sxtw, | |
| 1942 | .imm3 = 0, | |
| 1943 | } }, | |
| 1944 | }); | |
| 1945 | }, | |
| 1946 | .unsigned => { | |
| 1947 | _ = try self.addInst(.{ | |
| 1948 | .tag = .cmp_extended_register, | |
| 1949 | .data = .{ .rr_extend_shift = .{ | |
| 1950 | .rn = dest_reg.to64(), | |
| 1951 | .rm = truncated_reg.to32(), | |
| 1952 | .ext_type = .uxtw, | |
| 1953 | .imm3 = 0, | |
| 1954 | } }, | |
| 1955 | }); | |
| 1956 | }, | |
| 1957 | } | |
| 1958 | ||
| 1945 | 1959 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1946 | 1960 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ |
| 1947 | 1961 | .compare_flags_unsigned = .neq, |
src/arch/aarch64/Emit.zig+51-4| ... | ... | @@ -114,6 +114,12 @@ pub fn emitMir( |
| 114 | 114 | .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), |
| 115 | 115 | .subs_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), |
| 116 | 116 | |
| 117 | .add_extended_register => try emit.mirAddSubtractExtendedRegister(inst), | |
| 118 | .adds_extended_register => try emit.mirAddSubtractExtendedRegister(inst), | |
| 119 | .sub_extended_register => try emit.mirAddSubtractExtendedRegister(inst), | |
| 120 | .subs_extended_register => try emit.mirAddSubtractExtendedRegister(inst), | |
| 121 | .cmp_extended_register => try emit.mirAddSubtractExtendedRegister(inst), | |
| 122 | ||
| 117 | 123 | .cset => try emit.mirConditionalSelect(inst), |
| 118 | 124 | |
| 119 | 125 | .dbg_line => try emit.mirDbgLine(inst), |
| ... | ... | @@ -732,6 +738,47 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 732 | 738 | } |
| 733 | 739 | } |
| 734 | 740 | |
| 741 | fn mirAddSubtractExtendedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 742 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 743 | switch (tag) { | |
| 744 | .add_extended_register, | |
| 745 | .adds_extended_register, | |
| 746 | .sub_extended_register, | |
| 747 | .subs_extended_register, | |
| 748 | => { | |
| 749 | const rrr_extend_shift = emit.mir.instructions.items(.data)[inst].rrr_extend_shift; | |
| 750 | const rd = rrr_extend_shift.rd; | |
| 751 | const rn = rrr_extend_shift.rn; | |
| 752 | const rm = rrr_extend_shift.rm; | |
| 753 | const ext_type = rrr_extend_shift.ext_type; | |
| 754 | const imm3 = rrr_extend_shift.imm3; | |
| 755 | ||
| 756 | switch (tag) { | |
| 757 | .add_extended_register => try emit.writeInstruction(Instruction.addExtendedRegister(rd, rn, rm, ext_type, imm3)), | |
| 758 | .adds_extended_register => try emit.writeInstruction(Instruction.addsExtendedRegister(rd, rn, rm, ext_type, imm3)), | |
| 759 | .sub_extended_register => try emit.writeInstruction(Instruction.subExtendedRegister(rd, rn, rm, ext_type, imm3)), | |
| 760 | .subs_extended_register => try emit.writeInstruction(Instruction.subsExtendedRegister(rd, rn, rm, ext_type, imm3)), | |
| 761 | else => unreachable, | |
| 762 | } | |
| 763 | }, | |
| 764 | .cmp_extended_register => { | |
| 765 | const rr_extend_shift = emit.mir.instructions.items(.data)[inst].rr_extend_shift; | |
| 766 | const rn = rr_extend_shift.rn; | |
| 767 | const rm = rr_extend_shift.rm; | |
| 768 | const ext_type = rr_extend_shift.ext_type; | |
| 769 | const imm3 = rr_extend_shift.imm3; | |
| 770 | const zr: Register = switch (rn.size()) { | |
| 771 | 32 => .wzr, | |
| 772 | 64 => .xzr, | |
| 773 | else => unreachable, | |
| 774 | }; | |
| 775 | ||
| 776 | try emit.writeInstruction(Instruction.subsExtendedRegister(zr, rn, rm, ext_type, imm3)); | |
| 777 | }, | |
| 778 | else => unreachable, | |
| 779 | } | |
| 780 | } | |
| 781 | ||
| 735 | 782 | fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 736 | 783 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 737 | 784 | switch (tag) { |
| ... | ... | @@ -1013,10 +1060,10 @@ fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 1013 | 1060 | |
| 1014 | 1061 | switch (tag) { |
| 1015 | 1062 | .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)), |
| 1016 | .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)), | |
| 1017 | .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)), | |
| 1018 | .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)), | |
| 1019 | .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)), | |
| 1063 | .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd.to64(), rrr.rn.to64(), rrr.rm.to64())), | |
| 1064 | .smull => try emit.writeInstruction(Instruction.smull(rrr.rd.to64(), rrr.rn.to32(), rrr.rm.to32())), | |
| 1065 | .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd.to64(), rrr.rn.to64(), rrr.rm.to64())), | |
| 1066 | .umull => try emit.writeInstruction(Instruction.umull(rrr.rd.to64(), rrr.rn.to32(), rrr.rm.to32())), | |
| 1020 | 1067 | else => unreachable, |
| 1021 | 1068 | } |
| 1022 | 1069 | } |
src/arch/aarch64/Mir.zig+29| ... | ... | @@ -32,6 +32,10 @@ pub const Inst = struct { |
| 32 | 32 | add_shifted_register, |
| 33 | 33 | /// Add, update condition flags (shifted register) |
| 34 | 34 | adds_shifted_register, |
| 35 | /// Add (extended register) | |
| 36 | add_extended_register, | |
| 37 | /// Add, update condition flags (extended register) | |
| 38 | adds_extended_register, | |
| 35 | 39 | /// Bitwise AND (shifted register) |
| 36 | 40 | and_shifted_register, |
| 37 | 41 | /// Arithmetic Shift Right (immediate) |
| ... | ... | @@ -56,6 +60,8 @@ pub const Inst = struct { |
| 56 | 60 | cmp_immediate, |
| 57 | 61 | /// Compare (shifted register) |
| 58 | 62 | cmp_shifted_register, |
| 63 | /// Compare (extended register) | |
| 64 | cmp_extended_register, | |
| 59 | 65 | /// Conditional set |
| 60 | 66 | cset, |
| 61 | 67 | /// Pseudo-instruction: End of prologue |
| ... | ... | @@ -184,6 +190,10 @@ pub const Inst = struct { |
| 184 | 190 | sub_shifted_register, |
| 185 | 191 | /// Subtract, update condition flags (shifted register) |
| 186 | 192 | subs_shifted_register, |
| 193 | /// Subtract (extended register) | |
| 194 | sub_extended_register, | |
| 195 | /// Subtract, update condition flags (extended register) | |
| 196 | subs_extended_register, | |
| 187 | 197 | /// Supervisor Call |
| 188 | 198 | svc, |
| 189 | 199 | /// Test bits (immediate) |
| ... | ... | @@ -300,6 +310,15 @@ pub const Inst = struct { |
| 300 | 310 | imm6: u6, |
| 301 | 311 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, |
| 302 | 312 | }, |
| 313 | /// Two registers with sign-extension (extension type and 3-bit shift amount) | |
| 314 | /// | |
| 315 | /// Used by e.g. cmp_extended_register | |
| 316 | rr_extend_shift: struct { | |
| 317 | rn: Register, | |
| 318 | rm: Register, | |
| 319 | ext_type: bits.Instruction.AddSubtractExtendedRegisterOption, | |
| 320 | imm3: u3, | |
| 321 | }, | |
| 303 | 322 | /// Two registers and a shift (logical instruction version) |
| 304 | 323 | /// (shift type and 6-bit amount) |
| 305 | 324 | /// |
| ... | ... | @@ -356,6 +375,16 @@ pub const Inst = struct { |
| 356 | 375 | imm6: u6, |
| 357 | 376 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, |
| 358 | 377 | }, |
| 378 | /// Three registers with sign-extension (extension type and 3-bit shift amount) | |
| 379 | /// | |
| 380 | /// Used by e.g. add_extended_register | |
| 381 | rrr_extend_shift: struct { | |
| 382 | rd: Register, | |
| 383 | rn: Register, | |
| 384 | rm: Register, | |
| 385 | ext_type: bits.Instruction.AddSubtractExtendedRegisterOption, | |
| 386 | imm3: u3, | |
| 387 | }, | |
| 359 | 388 | /// Three registers and a shift (logical instruction version) |
| 360 | 389 | /// (shift type and 6-bit amount) |
| 361 | 390 | /// |
src/arch/aarch64/bits.zig+98-1| ... | ... | @@ -330,6 +330,17 @@ pub const Instruction = union(enum) { |
| 330 | 330 | op: u1, |
| 331 | 331 | sf: u1, |
| 332 | 332 | }, |
| 333 | add_subtract_extended_register: packed struct { | |
| 334 | rd: u5, | |
| 335 | rn: u5, | |
| 336 | imm3: u3, | |
| 337 | option: u3, | |
| 338 | rm: u5, | |
| 339 | fixed: u8 = 0b01011_00_1, | |
| 340 | s: u1, | |
| 341 | op: u1, | |
| 342 | sf: u1, | |
| 343 | }, | |
| 333 | 344 | conditional_branch: struct { |
| 334 | 345 | cond: u4, |
| 335 | 346 | o0: u1, |
| ... | ... | @@ -495,6 +506,7 @@ pub const Instruction = union(enum) { |
| 495 | 506 | .logical_immediate => |v| @bitCast(u32, v), |
| 496 | 507 | .bitfield => |v| @bitCast(u32, v), |
| 497 | 508 | .add_subtract_shifted_register => |v| @bitCast(u32, v), |
| 509 | .add_subtract_extended_register => |v| @bitCast(u32, v), | |
| 498 | 510 | // TODO once packed structs work, this can be refactored |
| 499 | 511 | .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), |
| 500 | 512 | .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), |
| ... | ... | @@ -1006,6 +1018,44 @@ pub const Instruction = union(enum) { |
| 1006 | 1018 | }; |
| 1007 | 1019 | } |
| 1008 | 1020 | |
| 1021 | pub const AddSubtractExtendedRegisterOption = enum(u3) { | |
| 1022 | uxtb, | |
| 1023 | uxth, | |
| 1024 | uxtw, | |
| 1025 | uxtx, // serves also as lsl | |
| 1026 | sxtb, | |
| 1027 | sxth, | |
| 1028 | sxtw, | |
| 1029 | sxtx, | |
| 1030 | }; | |
| 1031 | ||
| 1032 | fn addSubtractExtendedRegister( | |
| 1033 | op: u1, | |
| 1034 | s: u1, | |
| 1035 | rd: Register, | |
| 1036 | rn: Register, | |
| 1037 | rm: Register, | |
| 1038 | extend: AddSubtractExtendedRegisterOption, | |
| 1039 | imm3: u3, | |
| 1040 | ) Instruction { | |
| 1041 | return Instruction{ | |
| 1042 | .add_subtract_extended_register = .{ | |
| 1043 | .rd = rd.enc(), | |
| 1044 | .rn = rn.enc(), | |
| 1045 | .imm3 = imm3, | |
| 1046 | .option = @enumToInt(extend), | |
| 1047 | .rm = rm.enc(), | |
| 1048 | .s = s, | |
| 1049 | .op = op, | |
| 1050 | .sf = switch (rd.size()) { | |
| 1051 | 32 => 0b0, | |
| 1052 | 64 => 0b1, | |
| 1053 | else => unreachable, // unexpected register size | |
| 1054 | }, | |
| 1055 | }, | |
| 1056 | }; | |
| 1057 | } | |
| 1058 | ||
| 1009 | 1059 | fn conditionalBranch( |
| 1010 | 1060 | o0: u1, |
| 1011 | 1061 | o1: u1, |
| ... | ... | @@ -1524,6 +1574,48 @@ pub const Instruction = union(enum) { |
| 1524 | 1574 | return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6); |
| 1525 | 1575 | } |
| 1526 | 1576 | |
| 1577 | // Add/subtract (extended register) | |
| 1578 | ||
| 1579 | pub fn addExtendedRegister( | |
| 1580 | rd: Register, | |
| 1581 | rn: Register, | |
| 1582 | rm: Register, | |
| 1583 | extend: AddSubtractExtendedRegisterOption, | |
| 1584 | imm3: u3, | |
| 1585 | ) Instruction { | |
| 1586 | return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3); | |
| 1587 | } | |
| 1588 | ||
| 1589 | pub fn addsExtendedRegister( | |
| 1590 | rd: Register, | |
| 1591 | rn: Register, | |
| 1592 | rm: Register, | |
| 1593 | extend: AddSubtractExtendedRegisterOption, | |
| 1594 | imm3: u3, | |
| 1595 | ) Instruction { | |
| 1596 | return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3); | |
| 1597 | } | |
| 1598 | ||
| 1599 | pub fn subExtendedRegister( | |
| 1600 | rd: Register, | |
| 1601 | rn: Register, | |
| 1602 | rm: Register, | |
| 1603 | extend: AddSubtractExtendedRegisterOption, | |
| 1604 | imm3: u3, | |
| 1605 | ) Instruction { | |
| 1606 | return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3); | |
| 1607 | } | |
| 1608 | ||
| 1609 | pub fn subsExtendedRegister( | |
| 1610 | rd: Register, | |
| 1611 | rn: Register, | |
| 1612 | rm: Register, | |
| 1613 | extend: AddSubtractExtendedRegisterOption, | |
| 1614 | imm3: u3, | |
| 1615 | ) Instruction { | |
| 1616 | return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3); | |
| 1617 | } | |
| 1618 | ||
| 1527 | 1619 | // Conditional branch |
| 1528 | 1620 | |
| 1529 | 1621 | pub fn bCond(cond: Condition, offset: i21) Instruction { |
| ... | ... | @@ -1565,11 +1657,12 @@ pub const Instruction = union(enum) { |
| 1565 | 1657 | } |
| 1566 | 1658 | |
| 1567 | 1659 | pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1660 | assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); | |
| 1568 | 1661 | return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra); |
| 1569 | 1662 | } |
| 1570 | 1663 | |
| 1571 | 1664 | pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1572 | assert(rd.size() == 64); | |
| 1665 | assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); | |
| 1573 | 1666 | return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra); |
| 1574 | 1667 | } |
| 1575 | 1668 | |
| ... | ... | @@ -1837,6 +1930,10 @@ test "serialize instructions" { |
| 1837 | 1930 | .inst = Instruction.smulh(.x0, .x1, .x2), |
| 1838 | 1931 | .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000, |
| 1839 | 1932 | }, |
| 1933 | .{ // adds x0, x1, x2, sxtx | |
| 1934 | .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0), | |
| 1935 | .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000, | |
| 1936 | }, | |
| 1840 | 1937 | }; |
| 1841 | 1938 | |
| 1842 | 1939 | for (testcases) |case| { |