mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2 AArch64: Implement not for booleans
This commit is contained in:
parent
3a33f31334
commit
1c37622659
@ -894,6 +894,7 @@ fn airNot(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 result: {
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const operand_ty = self.air.typeOf(ty_op.operand);
|
||||
switch (operand) {
|
||||
.dead => unreachable,
|
||||
.unreach => unreachable,
|
||||
@ -924,7 +925,14 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
|
||||
break :result r;
|
||||
},
|
||||
else => {
|
||||
return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch});
|
||||
switch (operand_ty.zigTypeTag()) {
|
||||
.Bool => {
|
||||
// TODO convert this to mvn + and
|
||||
const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool);
|
||||
break :result dest;
|
||||
},
|
||||
else => return self.fail("TODO bitwise not", .{}),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
@ -1013,6 +1021,7 @@ fn binOpRegister(
|
||||
const mir_tag: Mir.Inst.Tag = switch (tag) {
|
||||
.add => .add_shifted_register,
|
||||
.sub => .sub_shifted_register,
|
||||
.xor => .eor_shifted_register,
|
||||
else => unreachable,
|
||||
};
|
||||
const mir_data: Mir.Inst.Data = switch (tag) {
|
||||
@ -1025,6 +1034,13 @@ fn binOpRegister(
|
||||
.imm6 = 0,
|
||||
.shift = .lsl,
|
||||
} },
|
||||
.xor => .{ .rrr_imm6_logical_shift = .{
|
||||
.rd = dest_reg,
|
||||
.rn = lhs_reg,
|
||||
.rm = rhs_reg,
|
||||
.imm6 = 0,
|
||||
.shift = .lsl,
|
||||
} },
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -1137,6 +1153,7 @@ fn binOp(
|
||||
rhs_ty: Type,
|
||||
) !MCValue {
|
||||
switch (tag) {
|
||||
// Arithmetic operations on integers and floats
|
||||
.add,
|
||||
.sub,
|
||||
=> {
|
||||
@ -1177,6 +1194,19 @@ fn binOp(
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
// Bitwise operations on integers
|
||||
.xor => {
|
||||
switch (lhs_ty.zigTypeTag()) {
|
||||
.Vector => return self.fail("TODO binary operations on vectors", .{}),
|
||||
.Int => return self.fail("TODO binary operations on vectors", .{}),
|
||||
.Bool => {
|
||||
assert(lhs_ty.eql(rhs_ty));
|
||||
// TODO boolean operations with immediates
|
||||
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
=> return self.fail("TODO ptr_add, ptr_sub", .{}),
|
||||
|
||||
@ -106,6 +106,8 @@ pub fn emitMir(
|
||||
.dbg_prologue_end => try emit.mirDebugPrologueEnd(),
|
||||
.dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
|
||||
|
||||
.eor_shifted_register => try emit.mirLogicalShiftedRegister(inst),
|
||||
|
||||
.load_memory => try emit.mirLoadMemory(inst),
|
||||
|
||||
.ldp => try emit.mirLoadStoreRegisterPair(inst),
|
||||
@ -134,6 +136,7 @@ pub fn emitMir(
|
||||
|
||||
.mov_register => try emit.mirMoveRegister(inst),
|
||||
.mov_to_from_sp => try emit.mirMoveRegister(inst),
|
||||
.mvn => try emit.mirMoveRegister(inst),
|
||||
|
||||
.movk => try emit.mirMoveWideImmediate(inst),
|
||||
.movz => try emit.mirMoveWideImmediate(inst),
|
||||
@ -638,6 +641,21 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const rrr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_logical_shift;
|
||||
const rd = rrr_imm6_logical_shift.rd;
|
||||
const rn = rrr_imm6_logical_shift.rn;
|
||||
const rm = rrr_imm6_logical_shift.rm;
|
||||
const shift = rrr_imm6_logical_shift.shift;
|
||||
const imm6 = rrr_imm6_logical_shift.imm6;
|
||||
|
||||
switch (tag) {
|
||||
.eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);
|
||||
const payload = emit.mir.instructions.items(.data)[inst].payload;
|
||||
@ -821,11 +839,19 @@ fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
|
||||
fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const rr = emit.mir.instructions.items(.data)[inst].rr;
|
||||
|
||||
switch (tag) {
|
||||
.mov_register => try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, Instruction.Shift.none)),
|
||||
.mov_to_from_sp => try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)),
|
||||
.mov_register => {
|
||||
const rr = emit.mir.instructions.items(.data)[inst].rr;
|
||||
try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0));
|
||||
},
|
||||
.mov_to_from_sp => {
|
||||
const rr = emit.mir.instructions.items(.data)[inst].rr;
|
||||
try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false));
|
||||
},
|
||||
.mvn => {
|
||||
const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;
|
||||
try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,6 +54,8 @@ pub const Inst = struct {
|
||||
dbg_epilogue_begin,
|
||||
/// Pseudo-instruction: Update debug line
|
||||
dbg_line,
|
||||
/// Bitwise Exclusive OR (shifted register)
|
||||
eor_shifted_register,
|
||||
/// Pseudo-instruction: Load memory
|
||||
///
|
||||
/// Payload is `LoadMemory`
|
||||
@ -88,6 +90,8 @@ pub const Inst = struct {
|
||||
movz,
|
||||
/// Multiply
|
||||
mul,
|
||||
/// Bitwise NOT
|
||||
mvn,
|
||||
/// No Operation
|
||||
nop,
|
||||
/// Pseudo-instruction: Pop multiple registers
|
||||
@ -217,6 +221,15 @@ pub const Inst = struct {
|
||||
imm12: u12,
|
||||
sh: u1 = 0,
|
||||
},
|
||||
/// Two registers and a shift (shift type and 6-bit amount)
|
||||
///
|
||||
/// Used by e.g. mvn
|
||||
rr_imm6_shift: struct {
|
||||
rd: Register,
|
||||
rm: Register,
|
||||
imm6: u6,
|
||||
shift: bits.Instruction.AddSubtractShiftedRegisterShift,
|
||||
},
|
||||
/// Two registers
|
||||
///
|
||||
/// Used by e.g. mul
|
||||
@ -235,6 +248,17 @@ pub const Inst = struct {
|
||||
imm6: u6,
|
||||
shift: bits.Instruction.AddSubtractShiftedRegisterShift,
|
||||
},
|
||||
/// Three registers and a shift (logical instruction version)
|
||||
/// (shift type and 6-bit amount)
|
||||
///
|
||||
/// Used by e.g. eor_shifted_register
|
||||
rrr_imm6_logical_shift: struct {
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
imm6: u6,
|
||||
shift: bits.Instruction.LogicalShiftedRegisterShift,
|
||||
},
|
||||
/// Two registers and a LoadStoreOffsetImmediate
|
||||
///
|
||||
/// Used by e.g. str_immediate
|
||||
|
||||
@ -344,23 +344,6 @@ pub const Instruction = union(enum) {
|
||||
sf: u1,
|
||||
},
|
||||
|
||||
pub const Shift = struct {
|
||||
shift: Type = .lsl,
|
||||
amount: u6 = 0,
|
||||
|
||||
pub const Type = enum(u2) {
|
||||
lsl,
|
||||
lsr,
|
||||
asr,
|
||||
ror,
|
||||
};
|
||||
|
||||
pub const none = Shift{
|
||||
.shift = .lsl,
|
||||
.amount = 0,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Condition = enum(u4) {
|
||||
/// Integer: Equal
|
||||
/// Floating point: Equal
|
||||
@ -819,25 +802,28 @@ pub const Instruction = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror };
|
||||
|
||||
fn logicalShiftedRegister(
|
||||
opc: u2,
|
||||
n: u1,
|
||||
shift: Shift,
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
switch (rd.size()) {
|
||||
32 => {
|
||||
assert(shift.amount < 32);
|
||||
assert(amount < 32);
|
||||
return Instruction{
|
||||
.logical_shifted_register = .{
|
||||
.rd = rd.id(),
|
||||
.rn = rn.id(),
|
||||
.imm6 = shift.amount,
|
||||
.imm6 = amount,
|
||||
.rm = rm.id(),
|
||||
.n = n,
|
||||
.shift = @enumToInt(shift.shift),
|
||||
.shift = @enumToInt(shift),
|
||||
.opc = opc,
|
||||
.sf = 0b0,
|
||||
},
|
||||
@ -848,10 +834,10 @@ pub const Instruction = union(enum) {
|
||||
.logical_shifted_register = .{
|
||||
.rd = rd.id(),
|
||||
.rn = rn.id(),
|
||||
.imm6 = shift.amount,
|
||||
.imm6 = amount,
|
||||
.rm = rm.id(),
|
||||
.n = n,
|
||||
.shift = @enumToInt(shift.shift),
|
||||
.shift = @enumToInt(shift),
|
||||
.opc = opc,
|
||||
.sf = 0b1,
|
||||
},
|
||||
@ -1159,36 +1145,84 @@ pub const Instruction = union(enum) {
|
||||
|
||||
// Logical (shifted register)
|
||||
|
||||
pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm);
|
||||
pub fn @"and"(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm);
|
||||
pub fn bic(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm);
|
||||
pub fn orr(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm);
|
||||
pub fn orn(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm);
|
||||
pub fn eor(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm);
|
||||
pub fn eon(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm);
|
||||
pub fn ands(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
|
||||
return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm);
|
||||
pub fn bics(
|
||||
rd: Register,
|
||||
rn: Register,
|
||||
rm: Register,
|
||||
shift: LogicalShiftedRegisterShift,
|
||||
amount: u6,
|
||||
) Instruction {
|
||||
return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount);
|
||||
}
|
||||
|
||||
// Add/subtract (immediate)
|
||||
@ -1316,11 +1350,11 @@ test "serialize instructions" {
|
||||
|
||||
const testcases = [_]Testcase{
|
||||
.{ // orr x0, xzr, x1
|
||||
.inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none),
|
||||
.inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0),
|
||||
.expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
|
||||
},
|
||||
.{ // orn x0, xzr, x1
|
||||
.inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none),
|
||||
.inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0),
|
||||
.expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
|
||||
},
|
||||
.{ // movz x1, #4
|
||||
@ -1440,11 +1474,11 @@ test "serialize instructions" {
|
||||
.expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
|
||||
},
|
||||
.{ // and x0, x4, x2
|
||||
.inst = Instruction.@"and"(.x0, .x4, .x2, .{}),
|
||||
.inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0),
|
||||
.expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
|
||||
},
|
||||
.{ // and x0, x4, x2, lsl #0x8
|
||||
.inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }),
|
||||
.inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8),
|
||||
.expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
|
||||
},
|
||||
.{ // add x0, x10, #10
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user