| author | |
| committer | |
| log | 1c37622659f70115b698b5924472c2268bca63a8 |
| tree | 1d3d09e920a7c9b01954744c1990702dd544e360 |
| parent | 3a33f313347f3fa151ba3a90c1c3b14eee3d1d1e |
| signature |
4 files changed, 162 insertions(+), 48 deletions(-)
src/arch/aarch64/CodeGen.zig+31-1| ... | ... | @@ -894,6 +894,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 894 | 894 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 895 | 895 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 896 | 896 | const operand = try self.resolveInst(ty_op.operand); |
| 897 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 897 | 898 | switch (operand) { |
| 898 | 899 | .dead => unreachable, |
| 899 | 900 | .unreach => unreachable, |
| ... | ... | @@ -924,7 +925,14 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 924 | 925 | break :result r; |
| 925 | 926 | }, |
| 926 | 927 | else => { |
| 927 | return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); | |
| 928 | switch (operand_ty.zigTypeTag()) { | |
| 929 | .Bool => { | |
| 930 | // TODO convert this to mvn + and | |
| 931 | const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool); | |
| 932 | break :result dest; | |
| 933 | }, | |
| 934 | else => return self.fail("TODO bitwise not", .{}), | |
| 935 | } | |
| 928 | 936 | }, |
| 929 | 937 | } |
| 930 | 938 | }; |
| ... | ... | @@ -1013,6 +1021,7 @@ fn binOpRegister( |
| 1013 | 1021 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1014 | 1022 | .add => .add_shifted_register, |
| 1015 | 1023 | .sub => .sub_shifted_register, |
| 1024 | .xor => .eor_shifted_register, | |
| 1016 | 1025 | else => unreachable, |
| 1017 | 1026 | }; |
| 1018 | 1027 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | ... | @@ -1025,6 +1034,13 @@ fn binOpRegister( |
| 1025 | 1034 | .imm6 = 0, |
| 1026 | 1035 | .shift = .lsl, |
| 1027 | 1036 | } }, |
| 1037 | .xor => .{ .rrr_imm6_logical_shift = .{ | |
| 1038 | .rd = dest_reg, | |
| 1039 | .rn = lhs_reg, | |
| 1040 | .rm = rhs_reg, | |
| 1041 | .imm6 = 0, | |
| 1042 | .shift = .lsl, | |
| 1043 | } }, | |
| 1028 | 1044 | else => unreachable, |
| 1029 | 1045 | }; |
| 1030 | 1046 | |
| ... | ... | @@ -1137,6 +1153,7 @@ fn binOp( |
| 1137 | 1153 | rhs_ty: Type, |
| 1138 | 1154 | ) !MCValue { |
| 1139 | 1155 | switch (tag) { |
| 1156 | // Arithmetic operations on integers and floats | |
| 1140 | 1157 | .add, |
| 1141 | 1158 | .sub, |
| 1142 | 1159 | => { |
| ... | ... | @@ -1177,6 +1194,19 @@ fn binOp( |
| 1177 | 1194 | else => unreachable, |
| 1178 | 1195 | } |
| 1179 | 1196 | }, |
| 1197 | // Bitwise operations on integers | |
| 1198 | .xor => { | |
| 1199 | switch (lhs_ty.zigTypeTag()) { | |
| 1200 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | |
| 1201 | .Int => return self.fail("TODO binary operations on vectors", .{}), | |
| 1202 | .Bool => { | |
| 1203 | assert(lhs_ty.eql(rhs_ty)); | |
| 1204 | // TODO boolean operations with immediates | |
| 1205 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1206 | }, | |
| 1207 | else => unreachable, | |
| 1208 | } | |
| 1209 | }, | |
| 1180 | 1210 | .ptr_add, |
| 1181 | 1211 | .ptr_sub, |
| 1182 | 1212 | => return self.fail("TODO ptr_add, ptr_sub", .{}), |
src/arch/aarch64/Emit.zig+30-4| ... | ... | @@ -106,6 +106,8 @@ pub fn emitMir( |
| 106 | 106 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| 107 | 107 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), |
| 108 | 108 | |
| 109 | .eor_shifted_register => try emit.mirLogicalShiftedRegister(inst), | |
| 110 | ||
| 109 | 111 | .load_memory => try emit.mirLoadMemory(inst), |
| 110 | 112 | |
| 111 | 113 | .ldp => try emit.mirLoadStoreRegisterPair(inst), |
| ... | ... | @@ -134,6 +136,7 @@ pub fn emitMir( |
| 134 | 136 | |
| 135 | 137 | .mov_register => try emit.mirMoveRegister(inst), |
| 136 | 138 | .mov_to_from_sp => try emit.mirMoveRegister(inst), |
| 139 | .mvn => try emit.mirMoveRegister(inst), | |
| 137 | 140 | |
| 138 | 141 | .movk => try emit.mirMoveWideImmediate(inst), |
| 139 | 142 | .movz => try emit.mirMoveWideImmediate(inst), |
| ... | ... | @@ -638,6 +641,21 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 638 | 641 | } |
| 639 | 642 | } |
| 640 | 643 | |
| 644 | fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 645 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 646 | const rrr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_logical_shift; | |
| 647 | const rd = rrr_imm6_logical_shift.rd; | |
| 648 | const rn = rrr_imm6_logical_shift.rn; | |
| 649 | const rm = rrr_imm6_logical_shift.rm; | |
| 650 | const shift = rrr_imm6_logical_shift.shift; | |
| 651 | const imm6 = rrr_imm6_logical_shift.imm6; | |
| 652 | ||
| 653 | switch (tag) { | |
| 654 | .eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)), | |
| 655 | else => unreachable, | |
| 656 | } | |
| 657 | } | |
| 658 | ||
| 641 | 659 | fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 642 | 660 | assert(emit.mir.instructions.items(.tag)[inst] == .load_memory); |
| 643 | 661 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| ... | ... | @@ -821,11 +839,19 @@ fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 821 | 839 | |
| 822 | 840 | fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 823 | 841 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 824 | const rr = emit.mir.instructions.items(.data)[inst].rr; | |
| 825 | ||
| 826 | 842 | switch (tag) { |
| 827 | .mov_register => try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, Instruction.Shift.none)), | |
| 828 | .mov_to_from_sp => try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)), | |
| 843 | .mov_register => { | |
| 844 | const rr = emit.mir.instructions.items(.data)[inst].rr; | |
| 845 | try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0)); | |
| 846 | }, | |
| 847 | .mov_to_from_sp => { | |
| 848 | const rr = emit.mir.instructions.items(.data)[inst].rr; | |
| 849 | try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)); | |
| 850 | }, | |
| 851 | .mvn => { | |
| 852 | const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift; | |
| 853 | try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0)); | |
| 854 | }, | |
| 829 | 855 | else => unreachable, |
| 830 | 856 | } |
| 831 | 857 | } |
src/arch/aarch64/Mir.zig+24| ... | ... | @@ -54,6 +54,8 @@ pub const Inst = struct { |
| 54 | 54 | dbg_epilogue_begin, |
| 55 | 55 | /// Pseudo-instruction: Update debug line |
| 56 | 56 | dbg_line, |
| 57 | /// Bitwise Exclusive OR (shifted register) | |
| 58 | eor_shifted_register, | |
| 57 | 59 | /// Pseudo-instruction: Load memory |
| 58 | 60 | /// |
| 59 | 61 | /// Payload is `LoadMemory` |
| ... | ... | @@ -88,6 +90,8 @@ pub const Inst = struct { |
| 88 | 90 | movz, |
| 89 | 91 | /// Multiply |
| 90 | 92 | mul, |
| 93 | /// Bitwise NOT | |
| 94 | mvn, | |
| 91 | 95 | /// No Operation |
| 92 | 96 | nop, |
| 93 | 97 | /// Pseudo-instruction: Pop multiple registers |
| ... | ... | @@ -217,6 +221,15 @@ pub const Inst = struct { |
| 217 | 221 | imm12: u12, |
| 218 | 222 | sh: u1 = 0, |
| 219 | 223 | }, |
| 224 | /// Two registers and a shift (shift type and 6-bit amount) | |
| 225 | /// | |
| 226 | /// Used by e.g. mvn | |
| 227 | rr_imm6_shift: struct { | |
| 228 | rd: Register, | |
| 229 | rm: Register, | |
| 230 | imm6: u6, | |
| 231 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, | |
| 232 | }, | |
| 220 | 233 | /// Two registers |
| 221 | 234 | /// |
| 222 | 235 | /// Used by e.g. mul |
| ... | ... | @@ -235,6 +248,17 @@ pub const Inst = struct { |
| 235 | 248 | imm6: u6, |
| 236 | 249 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, |
| 237 | 250 | }, |
| 251 | /// Three registers and a shift (logical instruction version) | |
| 252 | /// (shift type and 6-bit amount) | |
| 253 | /// | |
| 254 | /// Used by e.g. eor_shifted_register | |
| 255 | rrr_imm6_logical_shift: struct { | |
| 256 | rd: Register, | |
| 257 | rn: Register, | |
| 258 | rm: Register, | |
| 259 | imm6: u6, | |
| 260 | shift: bits.Instruction.LogicalShiftedRegisterShift, | |
| 261 | }, | |
| 238 | 262 | /// Two registers and a LoadStoreOffsetImmediate |
| 239 | 263 | /// |
| 240 | 264 | /// Used by e.g. str_immediate |
src/arch/aarch64/bits.zig+77-43| ... | ... | @@ -344,23 +344,6 @@ pub const Instruction = union(enum) { |
| 344 | 344 | sf: u1, |
| 345 | 345 | }, |
| 346 | 346 | |
| 347 | pub const Shift = struct { | |
| 348 | shift: Type = .lsl, | |
| 349 | amount: u6 = 0, | |
| 350 | ||
| 351 | pub const Type = enum(u2) { | |
| 352 | lsl, | |
| 353 | lsr, | |
| 354 | asr, | |
| 355 | ror, | |
| 356 | }; | |
| 357 | ||
| 358 | pub const none = Shift{ | |
| 359 | .shift = .lsl, | |
| 360 | .amount = 0, | |
| 361 | }; | |
| 362 | }; | |
| 363 | ||
| 364 | 347 | pub const Condition = enum(u4) { |
| 365 | 348 | /// Integer: Equal |
| 366 | 349 | /// Floating point: Equal |
| ... | ... | @@ -819,25 +802,28 @@ pub const Instruction = union(enum) { |
| 819 | 802 | }; |
| 820 | 803 | } |
| 821 | 804 | |
| 805 | pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror }; | |
| 806 | ||
| 822 | 807 | fn logicalShiftedRegister( |
| 823 | 808 | opc: u2, |
| 824 | 809 | n: u1, |
| 825 | shift: Shift, | |
| 826 | 810 | rd: Register, |
| 827 | 811 | rn: Register, |
| 828 | 812 | rm: Register, |
| 813 | shift: LogicalShiftedRegisterShift, | |
| 814 | amount: u6, | |
| 829 | 815 | ) Instruction { |
| 830 | 816 | switch (rd.size()) { |
| 831 | 817 | 32 => { |
| 832 | assert(shift.amount < 32); | |
| 818 | assert(amount < 32); | |
| 833 | 819 | return Instruction{ |
| 834 | 820 | .logical_shifted_register = .{ |
| 835 | 821 | .rd = rd.id(), |
| 836 | 822 | .rn = rn.id(), |
| 837 | .imm6 = shift.amount, | |
| 823 | .imm6 = amount, | |
| 838 | 824 | .rm = rm.id(), |
| 839 | 825 | .n = n, |
| 840 | .shift = @enumToInt(shift.shift), | |
| 826 | .shift = @enumToInt(shift), | |
| 841 | 827 | .opc = opc, |
| 842 | 828 | .sf = 0b0, |
| 843 | 829 | }, |
| ... | ... | @@ -848,10 +834,10 @@ pub const Instruction = union(enum) { |
| 848 | 834 | .logical_shifted_register = .{ |
| 849 | 835 | .rd = rd.id(), |
| 850 | 836 | .rn = rn.id(), |
| 851 | .imm6 = shift.amount, | |
| 837 | .imm6 = amount, | |
| 852 | 838 | .rm = rm.id(), |
| 853 | 839 | .n = n, |
| 854 | .shift = @enumToInt(shift.shift), | |
| 840 | .shift = @enumToInt(shift), | |
| 855 | 841 | .opc = opc, |
| 856 | 842 | .sf = 0b1, |
| 857 | 843 | }, |
| ... | ... | @@ -1159,36 +1145,84 @@ pub const Instruction = union(enum) { |
| 1159 | 1145 | |
| 1160 | 1146 | // Logical (shifted register) |
| 1161 | 1147 | |
| 1162 | pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1163 | return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm); | |
| 1148 | pub fn @"and"( | |
| 1149 | rd: Register, | |
| 1150 | rn: Register, | |
| 1151 | rm: Register, | |
| 1152 | shift: LogicalShiftedRegisterShift, | |
| 1153 | amount: u6, | |
| 1154 | ) Instruction { | |
| 1155 | return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount); | |
| 1164 | 1156 | } |
| 1165 | 1157 | |
| 1166 | pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1167 | return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm); | |
| 1158 | pub fn bic( | |
| 1159 | rd: Register, | |
| 1160 | rn: Register, | |
| 1161 | rm: Register, | |
| 1162 | shift: LogicalShiftedRegisterShift, | |
| 1163 | amount: u6, | |
| 1164 | ) Instruction { | |
| 1165 | return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount); | |
| 1168 | 1166 | } |
| 1169 | 1167 | |
| 1170 | pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1171 | return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm); | |
| 1168 | pub fn orr( | |
| 1169 | rd: Register, | |
| 1170 | rn: Register, | |
| 1171 | rm: Register, | |
| 1172 | shift: LogicalShiftedRegisterShift, | |
| 1173 | amount: u6, | |
| 1174 | ) Instruction { | |
| 1175 | return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount); | |
| 1172 | 1176 | } |
| 1173 | 1177 | |
| 1174 | pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1175 | return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm); | |
| 1178 | pub fn orn( | |
| 1179 | rd: Register, | |
| 1180 | rn: Register, | |
| 1181 | rm: Register, | |
| 1182 | shift: LogicalShiftedRegisterShift, | |
| 1183 | amount: u6, | |
| 1184 | ) Instruction { | |
| 1185 | return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount); | |
| 1176 | 1186 | } |
| 1177 | 1187 | |
| 1178 | pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1179 | return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm); | |
| 1188 | pub fn eor( | |
| 1189 | rd: Register, | |
| 1190 | rn: Register, | |
| 1191 | rm: Register, | |
| 1192 | shift: LogicalShiftedRegisterShift, | |
| 1193 | amount: u6, | |
| 1194 | ) Instruction { | |
| 1195 | return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount); | |
| 1180 | 1196 | } |
| 1181 | 1197 | |
| 1182 | pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1183 | return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm); | |
| 1198 | pub fn eon( | |
| 1199 | rd: Register, | |
| 1200 | rn: Register, | |
| 1201 | rm: Register, | |
| 1202 | shift: LogicalShiftedRegisterShift, | |
| 1203 | amount: u6, | |
| 1204 | ) Instruction { | |
| 1205 | return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount); | |
| 1184 | 1206 | } |
| 1185 | 1207 | |
| 1186 | pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1187 | return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm); | |
| 1208 | pub fn ands( | |
| 1209 | rd: Register, | |
| 1210 | rn: Register, | |
| 1211 | rm: Register, | |
| 1212 | shift: LogicalShiftedRegisterShift, | |
| 1213 | amount: u6, | |
| 1214 | ) Instruction { | |
| 1215 | return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount); | |
| 1188 | 1216 | } |
| 1189 | 1217 | |
| 1190 | pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { | |
| 1191 | return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm); | |
| 1218 | pub fn bics( | |
| 1219 | rd: Register, | |
| 1220 | rn: Register, | |
| 1221 | rm: Register, | |
| 1222 | shift: LogicalShiftedRegisterShift, | |
| 1223 | amount: u6, | |
| 1224 | ) Instruction { | |
| 1225 | return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount); | |
| 1192 | 1226 | } |
| 1193 | 1227 | |
| 1194 | 1228 | // Add/subtract (immediate) |
| ... | ... | @@ -1316,11 +1350,11 @@ test "serialize instructions" { |
| 1316 | 1350 | |
| 1317 | 1351 | const testcases = [_]Testcase{ |
| 1318 | 1352 | .{ // orr x0, xzr, x1 |
| 1319 | .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none), | |
| 1353 | .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0), | |
| 1320 | 1354 | .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, |
| 1321 | 1355 | }, |
| 1322 | 1356 | .{ // orn x0, xzr, x1 |
| 1323 | .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none), | |
| 1357 | .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0), | |
| 1324 | 1358 | .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, |
| 1325 | 1359 | }, |
| 1326 | 1360 | .{ // movz x1, #4 |
| ... | ... | @@ -1440,11 +1474,11 @@ test "serialize instructions" { |
| 1440 | 1474 | .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, |
| 1441 | 1475 | }, |
| 1442 | 1476 | .{ // and x0, x4, x2 |
| 1443 | .inst = Instruction.@"and"(.x0, .x4, .x2, .{}), | |
| 1477 | .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0), | |
| 1444 | 1478 | .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, |
| 1445 | 1479 | }, |
| 1446 | 1480 | .{ // and x0, x4, x2, lsl #0x8 |
| 1447 | .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }), | |
| 1481 | .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8), | |
| 1448 | 1482 | .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, |
| 1449 | 1483 | }, |
| 1450 | 1484 | .{ // add x0, x10, #10 |