authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-08 22:47:43+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-13 11:32:04+01:00
log03dddc8d9c7613aff877f0dcf0efe0193869ef73
treee3aba1a4b859fe33aa29713801aee664cb3ac3f4
parent2036af94e97f0ac16293556423c144ec9e1b8226
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement bit shifts with register operands


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),
585585
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}
15161547
1517fn 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
1523fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {1548fn 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}
15281553
1529fn 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
1535fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {1554fn 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),
8282
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),
8488
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}
471475
476fn 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
472fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {491fn 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 conditionally35 /// Branch conditionally
34 b_cond,36 b_cond,
35 /// Branch37 /// 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 },
359369
360 pub const Condition = enum(u4) {370 pub const Condition = enum(u4) {
361 /// Integer: Equal371 /// 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 }
484495
...@@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) {...@@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) {
1031 };1042 };
1032 }1043 }
10331044
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 functions1068 // Helper functions for assembly syntax functions
10351069
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};
13971445
1398test {1446test {
...@@ -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 };
15741626
1575 for (testcases) |case| {1627 for (testcases) |case| {