| author | |
| committer | |
| log | 03dddc8d9c7613aff877f0dcf0efe0193869ef73 |
| tree | e3aba1a4b859fe33aa29713801aee664cb3ac3f4 |
| parent | 2036af94e97f0ac16293556423c144ec9e1b8226 |
| signature |
4 files changed, 111 insertions(+), 15 deletions(-)
src/arch/aarch64/CodeGen.zig+34-15| ... | @@ -541,7 +541,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -541,7 +541,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 541 | .mul_sat => try self.airMulSat(inst), | 541 | .mul_sat => try self.airMulSat(inst), |
| 542 | .rem => try self.airRem(inst), | 542 | .rem => try self.airRem(inst), |
| 543 | .mod => try self.airMod(inst), | 543 | .mod => try self.airMod(inst), |
| 544 | .shl, .shl_exact => try self.airShl(inst), | 544 | .shl, .shl_exact => try self.airBinOp(inst), |
| 545 | .shl_sat => try self.airShlSat(inst), | 545 | .shl_sat => try self.airShlSat(inst), |
| 546 | .min => try self.airMin(inst), | 546 | .min => try self.airMin(inst), |
| 547 | .max => try self.airMax(inst), | 547 | .max => try self.airMax(inst), |
| ... | @@ -581,7 +581,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -581,7 +581,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 581 | .bit_and => try self.airBinOp(inst), | 581 | .bit_and => try self.airBinOp(inst), |
| 582 | .bit_or => try self.airBinOp(inst), | 582 | .bit_or => try self.airBinOp(inst), |
| 583 | .xor => try self.airBinOp(inst), | 583 | .xor => try self.airBinOp(inst), |
| 584 | .shr, .shr_exact => try self.airShr(inst), | 584 | .shr, .shr_exact => try self.airBinOp(inst), |
| 585 | 585 | ||
| 586 | .alloc => try self.airAlloc(inst), | 586 | .alloc => try self.airAlloc(inst), |
| 587 | .ret_ptr => try self.airRetPtr(inst), | 587 | .ret_ptr => try self.airRetPtr(inst), |
| ... | @@ -1156,6 +1156,15 @@ fn binOpRegister( | ... | @@ -1156,6 +1156,15 @@ fn binOpRegister( |
| 1156 | .bit_or, | 1156 | .bit_or, |
| 1157 | .bool_or, | 1157 | .bool_or, |
| 1158 | => .orr_shifted_register, | 1158 | => .orr_shifted_register, |
| 1159 | .shl, | ||
| 1160 | .shl_exact, | ||
| 1161 | => .lsl_register, | ||
| 1162 | .shr, | ||
| 1163 | .shr_exact, | ||
| 1164 | => switch (lhs_ty.intInfo(self.target.*).signedness) { | ||
| 1165 | .signed => Mir.Inst.Tag.asr_register, | ||
| 1166 | .unsigned => Mir.Inst.Tag.lsr_register, | ||
| 1167 | }, | ||
| 1159 | .xor => .eor_shifted_register, | 1168 | .xor => .eor_shifted_register, |
| 1160 | else => unreachable, | 1169 | else => unreachable, |
| 1161 | }; | 1170 | }; |
| ... | @@ -1171,7 +1180,12 @@ fn binOpRegister( | ... | @@ -1171,7 +1180,12 @@ fn binOpRegister( |
| 1171 | .imm6 = 0, | 1180 | .imm6 = 0, |
| 1172 | .shift = .lsl, | 1181 | .shift = .lsl, |
| 1173 | } }, | 1182 | } }, |
| 1174 | .mul => .{ .rrr = .{ | 1183 | .mul, |
| 1184 | .shl, | ||
| 1185 | .shl_exact, | ||
| 1186 | .shr, | ||
| 1187 | .shr_exact, | ||
| 1188 | => .{ .rrr = .{ | ||
| 1175 | .rd = dest_reg, | 1189 | .rd = dest_reg, |
| 1176 | .rn = lhs_reg, | 1190 | .rn = lhs_reg, |
| 1177 | .rm = rhs_reg, | 1191 | .rm = rhs_reg, |
| ... | @@ -1385,6 +1399,23 @@ fn binOp( | ... | @@ -1385,6 +1399,23 @@ fn binOp( |
| 1385 | else => unreachable, | 1399 | else => unreachable, |
| 1386 | } | 1400 | } |
| 1387 | }, | 1401 | }, |
| 1402 | .shl, | ||
| 1403 | .shr, | ||
| 1404 | => { | ||
| 1405 | switch (lhs_ty.zigTypeTag()) { | ||
| 1406 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | ||
| 1407 | .Int => { | ||
| 1408 | const int_info = lhs_ty.intInfo(self.target.*); | ||
| 1409 | if (int_info.bits <= 64) { | ||
| 1410 | // TODO immediate shifts | ||
| 1411 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | ||
| 1412 | } else { | ||
| 1413 | return self.fail("TODO binary operations on int with bits > 64", .{}); | ||
| 1414 | } | ||
| 1415 | }, | ||
| 1416 | else => unreachable, | ||
| 1417 | } | ||
| 1418 | }, | ||
| 1388 | .bool_and, | 1419 | .bool_and, |
| 1389 | .bool_or, | 1420 | .bool_or, |
| 1390 | => { | 1421 | => { |
| ... | @@ -1514,24 +1545,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1514,24 +1545,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1514 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1545 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1515 | } | 1546 | } |
| 1516 | 1547 | ||
| 1517 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1518 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | ||
| 1519 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}); | ||
| 1520 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | 1548 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1524 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1549 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1525 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); | 1550 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| 1526 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1551 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1527 | } | 1552 | } |
| 1528 | 1553 | ||
| 1529 | fn airShr(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1530 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | ||
| 1531 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}); | ||
| 1532 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 1554 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1536 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1555 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1537 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); | 1556 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); |
src/arch/aarch64/Emit.zig+19| ... | @@ -80,6 +80,10 @@ pub fn emitMir( | ... | @@ -80,6 +80,10 @@ pub fn emitMir( |
| 80 | .cmp_immediate => try emit.mirAddSubtractImmediate(inst), | 80 | .cmp_immediate => try emit.mirAddSubtractImmediate(inst), |
| 81 | .sub_immediate => try emit.mirAddSubtractImmediate(inst), | 81 | .sub_immediate => try emit.mirAddSubtractImmediate(inst), |
| 82 | 82 | ||
| 83 | .asr_register => try emit.mirShiftRegister(inst), | ||
| 84 | .lsl_register => try emit.mirShiftRegister(inst), | ||
| 85 | .lsr_register => try emit.mirShiftRegister(inst), | ||
| 86 | |||
| 83 | .b_cond => try emit.mirConditionalBranchImmediate(inst), | 87 | .b_cond => try emit.mirConditionalBranchImmediate(inst), |
| 84 | 88 | ||
| 85 | .b => try emit.mirBranch(inst), | 89 | .b => try emit.mirBranch(inst), |
| ... | @@ -469,6 +473,21 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -469,6 +473,21 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 469 | } | 473 | } |
| 470 | } | 474 | } |
| 471 | 475 | ||
| 476 | fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | ||
| 477 | const tag = emit.mir.instructions.items(.tag)[inst]; | ||
| 478 | const rrr = emit.mir.instructions.items(.data)[inst].rrr; | ||
| 479 | const rd = rrr.rd; | ||
| 480 | const rn = rrr.rn; | ||
| 481 | const rm = rrr.rm; | ||
| 482 | |||
| 483 | 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)), | ||
| 487 | else => unreachable, | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 472 | fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { | 491 | fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 473 | const tag = emit.mir.instructions.items(.tag)[inst]; | 492 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 474 | const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond; | 493 | const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond; |
src/arch/aarch64/Mir.zig+6| ... | @@ -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 (register) | ||
| 34 | asr_register, | ||
| 33 | /// Branch conditionally | 35 | /// Branch conditionally |
| 34 | b_cond, | 36 | b_cond, |
| 35 | /// Branch | 37 | /// Branch |
| ... | @@ -96,6 +98,10 @@ pub const Inst = struct { | ... | @@ -96,6 +98,10 @@ pub const Inst = struct { |
| 96 | ldrh_immediate, | 98 | ldrh_immediate, |
| 97 | /// Load Register Halfword (register) | 99 | /// Load Register Halfword (register) |
| 98 | ldrh_register, | 100 | ldrh_register, |
| 101 | /// Logical Shift Left (register) | ||
| 102 | lsl_register, | ||
| 103 | /// Logical Shift Right (register) | ||
| 104 | lsr_register, | ||
| 99 | /// Move (to/from SP) | 105 | /// Move (to/from SP) |
| 100 | mov_to_from_sp, | 106 | mov_to_from_sp, |
| 101 | /// Move (register) | 107 | /// Move (register) |
src/arch/aarch64/bits.zig+52| ... | @@ -356,6 +356,16 @@ pub const Instruction = union(enum) { | ... | @@ -356,6 +356,16 @@ pub const Instruction = union(enum) { |
| 356 | op54: u2, | 356 | op54: u2, |
| 357 | sf: u1, | 357 | sf: u1, |
| 358 | }, | 358 | }, |
| 359 | data_processing_2_source: packed struct { | ||
| 360 | rd: u5, | ||
| 361 | rn: u5, | ||
| 362 | opcode: u6, | ||
| 363 | rm: u5, | ||
| 364 | fixed_1: u8 = 0b11010110, | ||
| 365 | s: u1, | ||
| 366 | fixed_2: u1 = 0b0, | ||
| 367 | sf: u1, | ||
| 368 | }, | ||
| 359 | 369 | ||
| 360 | pub const Condition = enum(u4) { | 370 | pub const Condition = enum(u4) { |
| 361 | /// Integer: Equal | 371 | /// Integer: Equal |
| ... | @@ -479,6 +489,7 @@ pub const Instruction = union(enum) { | ... | @@ -479,6 +489,7 @@ pub const Instruction = union(enum) { |
| 479 | .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), | 489 | .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), |
| 480 | .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, | 490 | .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, |
| 481 | .data_processing_3_source => |v| @bitCast(u32, v), | 491 | .data_processing_3_source => |v| @bitCast(u32, v), |
| 492 | .data_processing_2_source => |v| @bitCast(u32, v), | ||
| 482 | }; | 493 | }; |
| 483 | } | 494 | } |
| 484 | 495 | ||
| ... | @@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) { | ... | @@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) { |
| 1031 | }; | 1042 | }; |
| 1032 | } | 1043 | } |
| 1033 | 1044 | ||
| 1045 | fn dataProcessing2Source( | ||
| 1046 | s: u1, | ||
| 1047 | opcode: u6, | ||
| 1048 | rd: Register, | ||
| 1049 | rn: Register, | ||
| 1050 | rm: Register, | ||
| 1051 | ) Instruction { | ||
| 1052 | return Instruction{ | ||
| 1053 | .data_processing_2_source = .{ | ||
| 1054 | .rd = rd.enc(), | ||
| 1055 | .rn = rn.enc(), | ||
| 1056 | .opcode = opcode, | ||
| 1057 | .rm = rm.enc(), | ||
| 1058 | .s = s, | ||
| 1059 | .sf = switch (rd.size()) { | ||
| 1060 | 32 => 0b0, | ||
| 1061 | 64 => 0b1, | ||
| 1062 | else => unreachable, // unexpected register size | ||
| 1063 | }, | ||
| 1064 | }, | ||
| 1065 | }; | ||
| 1066 | } | ||
| 1067 | |||
| 1034 | // Helper functions for assembly syntax functions | 1068 | // Helper functions for assembly syntax functions |
| 1035 | 1069 | ||
| 1036 | // Move wide (immediate) | 1070 | // Move wide (immediate) |
| ... | @@ -1393,6 +1427,20 @@ pub const Instruction = union(enum) { | ... | @@ -1393,6 +1427,20 @@ pub const Instruction = union(enum) { |
| 1393 | pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { | 1427 | pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { |
| 1394 | return msub(rd, rn, rm, .xzr); | 1428 | return msub(rd, rn, rm, .xzr); |
| 1395 | } | 1429 | } |
| 1430 | |||
| 1431 | // Data processing (2 source) | ||
| 1432 | |||
| 1433 | pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction { | ||
| 1434 | return dataProcessing2Source(0b0, 0b001000, rd, rn, rm); | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction { | ||
| 1438 | return dataProcessing2Source(0b0, 0b001001, rd, rn, rm); | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction { | ||
| 1442 | return dataProcessing2Source(0b0, 0b001010, rd, rn, rm); | ||
| 1443 | } | ||
| 1396 | }; | 1444 | }; |
| 1397 | 1445 | ||
| 1398 | test { | 1446 | test { |
| ... | @@ -1570,6 +1618,10 @@ test "serialize instructions" { | ... | @@ -1570,6 +1618,10 @@ test "serialize instructions" { |
| 1570 | .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), | 1618 | .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), |
| 1571 | .expected = 0b1_10_100100_1_000000_000000_00101_00011, | 1619 | .expected = 0b1_10_100100_1_000000_000000_00101_00011, |
| 1572 | }, | 1620 | }, |
| 1621 | .{ // lslv x6, x9, x10 | ||
| 1622 | .inst = Instruction.lslv(.x6, .x9, .x10), | ||
| 1623 | .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110, | ||
| 1624 | }, | ||
| 1573 | }; | 1625 | }; |
| 1574 | 1626 | ||
| 1575 | for (testcases) |case| { | 1627 | for (testcases) |case| { |