mirror of
https://github.com/ziglang/zig.git
synced 2025-12-27 00:23:22 +00:00
stage2 AArch64: implement bit shifts with register operands
This commit is contained in:
parent
2036af94e9
commit
03dddc8d9c
@ -541,7 +541,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.mul_sat => try self.airMulSat(inst),
|
||||
.rem => try self.airRem(inst),
|
||||
.mod => try self.airMod(inst),
|
||||
.shl, .shl_exact => try self.airShl(inst),
|
||||
.shl, .shl_exact => try self.airBinOp(inst),
|
||||
.shl_sat => try self.airShlSat(inst),
|
||||
.min => try self.airMin(inst),
|
||||
.max => try self.airMax(inst),
|
||||
@ -581,7 +581,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.bit_and => try self.airBinOp(inst),
|
||||
.bit_or => try self.airBinOp(inst),
|
||||
.xor => try self.airBinOp(inst),
|
||||
.shr, .shr_exact => try self.airShr(inst),
|
||||
.shr, .shr_exact => try self.airBinOp(inst),
|
||||
|
||||
.alloc => try self.airAlloc(inst),
|
||||
.ret_ptr => try self.airRetPtr(inst),
|
||||
@ -1156,6 +1156,15 @@ fn binOpRegister(
|
||||
.bit_or,
|
||||
.bool_or,
|
||||
=> .orr_shifted_register,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
=> .lsl_register,
|
||||
.shr,
|
||||
.shr_exact,
|
||||
=> switch (lhs_ty.intInfo(self.target.*).signedness) {
|
||||
.signed => Mir.Inst.Tag.asr_register,
|
||||
.unsigned => Mir.Inst.Tag.lsr_register,
|
||||
},
|
||||
.xor => .eor_shifted_register,
|
||||
else => unreachable,
|
||||
};
|
||||
@ -1171,7 +1180,12 @@ fn binOpRegister(
|
||||
.imm6 = 0,
|
||||
.shift = .lsl,
|
||||
} },
|
||||
.mul => .{ .rrr = .{
|
||||
.mul,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shr,
|
||||
.shr_exact,
|
||||
=> .{ .rrr = .{
|
||||
.rd = dest_reg,
|
||||
.rn = lhs_reg,
|
||||
.rm = rhs_reg,
|
||||
@ -1385,6 +1399,23 @@ fn binOp(
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.shl,
|
||||
.shr,
|
||||
=> {
|
||||
switch (lhs_ty.zigTypeTag()) {
|
||||
.Vector => return self.fail("TODO binary operations on vectors", .{}),
|
||||
.Int => {
|
||||
const int_info = lhs_ty.intInfo(self.target.*);
|
||||
if (int_info.bits <= 64) {
|
||||
// TODO immediate shifts
|
||||
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
|
||||
} else {
|
||||
return self.fail("TODO binary operations on int with bits > 64", .{});
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
=> {
|
||||
@ -1514,24 +1545,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airShl(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airShr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch});
|
||||
|
||||
@ -80,6 +80,10 @@ pub fn emitMir(
|
||||
.cmp_immediate => try emit.mirAddSubtractImmediate(inst),
|
||||
.sub_immediate => try emit.mirAddSubtractImmediate(inst),
|
||||
|
||||
.asr_register => try emit.mirShiftRegister(inst),
|
||||
.lsl_register => try emit.mirShiftRegister(inst),
|
||||
.lsr_register => try emit.mirShiftRegister(inst),
|
||||
|
||||
.b_cond => try emit.mirConditionalBranchImmediate(inst),
|
||||
|
||||
.b => try emit.mirBranch(inst),
|
||||
@ -469,6 +473,21 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const rrr = emit.mir.instructions.items(.data)[inst].rrr;
|
||||
const rd = rrr.rd;
|
||||
const rn = rrr.rn;
|
||||
const rm = rrr.rm;
|
||||
|
||||
switch (tag) {
|
||||
.asr_register => try emit.writeInstruction(Instruction.asrv(rd, rn, rm)),
|
||||
.lsl_register => try emit.writeInstruction(Instruction.lslv(rd, rn, rm)),
|
||||
.lsr_register => try emit.writeInstruction(Instruction.lsrv(rd, rn, rm)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond;
|
||||
|
||||
@ -30,6 +30,8 @@ pub const Inst = struct {
|
||||
add_shifted_register,
|
||||
/// Bitwise AND (shifted register)
|
||||
and_shifted_register,
|
||||
/// Arithmetic Shift Right (register)
|
||||
asr_register,
|
||||
/// Branch conditionally
|
||||
b_cond,
|
||||
/// Branch
|
||||
@ -96,6 +98,10 @@ pub const Inst = struct {
|
||||
ldrh_immediate,
|
||||
/// Load Register Halfword (register)
|
||||
ldrh_register,
|
||||
/// Logical Shift Left (register)
|
||||
lsl_register,
|
||||
/// Logical Shift Right (register)
|
||||
lsr_register,
|
||||
/// Move (to/from SP)
|
||||
mov_to_from_sp,
|
||||
/// Move (register)
|
||||
|
||||
@ -356,6 +356,16 @@ pub const Instruction = union(enum) {
|
||||
op54: u2,
|
||||
sf: u1,
|
||||
},
|
||||
data_processing_2_source: packed struct {
|
||||
rd: u5,
|
||||
rn: u5,
|
||||
opcode: u6,
|
||||
rm: u5,
|
||||
fixed_1: u8 = 0b11010110,
|
||||
s: u1,
|
||||
fixed_2: u1 = 0b0,
|
||||
sf: u1,
|
||||
},
|
||||
|
||||
pub const Condition = enum(u4) {
|
||||
/// Integer: Equal
|
||||
@ -479,6 +489,7 @@ pub const Instruction = union(enum) {
|
||||
.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),
|
||||
.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,
|
||||
.data_processing_3_source => |v| @bitCast(u32, v),
|
||||
.data_processing_2_source => |v| @bitCast(u32, v),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
fn dataProcessing2Source(
|
||||
s: u1,
|
||||
opcode: u6,
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
) Instruction {
|
||||
return Instruction{
|
||||
.data_processing_2_source = .{
|
||||
.rd = rd.enc(),
|
||||
.rn = rn.enc(),
|
||||
.opcode = opcode,
|
||||
.rm = rm.enc(),
|
||||
.s = s,
|
||||
.sf = switch (rd.size()) {
|
||||
32 => 0b0,
|
||||
64 => 0b1,
|
||||
else => unreachable, // unexpected register size
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Helper functions for assembly syntax functions
|
||||
|
||||
// Move wide (immediate)
|
||||
@ -1393,6 +1427,20 @@ pub const Instruction = union(enum) {
|
||||
pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
|
||||
return msub(rd, rn, rm, .xzr);
|
||||
}
|
||||
|
||||
// Data processing (2 source)
|
||||
|
||||
pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
|
||||
return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
|
||||
}
|
||||
|
||||
pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction {
|
||||
return dataProcessing2Source(0b0, 0b001001, rd, rn, rm);
|
||||
}
|
||||
|
||||
pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
|
||||
return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
|
||||
}
|
||||
};
|
||||
|
||||
test {
|
||||
@ -1570,6 +1618,10 @@ test "serialize instructions" {
|
||||
.inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
|
||||
.expected = 0b1_10_100100_1_000000_000000_00101_00011,
|
||||
},
|
||||
.{ // lslv x6, x9, x10
|
||||
.inst = Instruction.lslv(.x6, .x9, .x10),
|
||||
.expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
|
||||
},
|
||||
};
|
||||
|
||||
for (testcases) |case| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user