riscv: actually working test runner

This commit is contained in:
David Rubin 2024-04-13 21:12:26 -07:00
parent d19b77d63f
commit e622485df8
6 changed files with 239 additions and 256 deletions

View File

@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
};
pass_count += 1;
}
std.posix.exit(pass_count);
}

View File

@ -1601,7 +1601,6 @@ fn allocReg(self: *Self) !struct { Register, RegisterLock } {
}
fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
log.debug("elemOffset: {}", .{index});
const reg: Register = blk: {
switch (index) {
.immediate => |imm| {
@ -1616,14 +1615,14 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi
const lock = self.register_manager.lockRegAssumeUnused(reg);
defer self.register_manager.unlockReg(lock);
try self.binOpMir(
const result = try self.binOp(
.mul,
null,
index_ty,
.{ .register = reg },
index_ty,
.{ .immediate = elem_size },
index_ty,
);
break :blk reg;
break :blk result.register;
},
}
};
@ -1817,24 +1816,10 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const lhs_ty = self.typeOf(bin_op.lhs);
const rhs_ty = self.typeOf(bin_op.rhs);
const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn supportImmediate(tag: Air.Inst.Tag) bool {
return switch (tag) {
.add,
.sub,
.cmp_eq,
.cmp_neq,
.cmp_gt,
.cmp_gte,
.cmp_lt,
.cmp_lte,
=> true,
else => false,
const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
/// For all your binary operation needs, this function will generate
@ -1854,10 +1839,9 @@ fn supportImmediate(tag: Air.Inst.Tag) bool {
fn binOp(
self: *Self,
tag: Air.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
lhs: MCValue,
rhs: MCValue,
lhs_ty: Type,
rhs: MCValue,
rhs_ty: Type,
) InnerError!MCValue {
const zcu = self.bin_file.comp.module.?;
@ -1881,15 +1865,12 @@ fn binOp(
assert(lhs_ty.eql(rhs_ty, zcu));
const int_info = lhs_ty.intInfo(zcu);
if (int_info.bits <= 64) {
if (rhs == .immediate and supportImmediate(tag)) {
return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
}
return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
} else {
return self.fail("TODO binary operations on int with bits > 64", .{});
}
},
else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}),
else => |x| return std.debug.panic("TOOD: binOp {s}", .{@tagName(x)}),
}
},
@ -1912,23 +1893,21 @@ fn binOp(
else => unreachable,
};
return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
return try self.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty);
} else {
const offset = try self.binOp(
.mul,
null,
rhs,
.{ .immediate = elem_size },
Type.usize,
.{ .immediate = elem_size },
Type.usize,
);
const addr = try self.binOp(
tag,
null,
lhs,
offset,
Type.manyptr_u8,
offset,
Type.usize,
);
return addr;
@ -1948,10 +1927,7 @@ fn binOp(
.Int => {
const int_info = lhs_ty.intInfo(zcu);
if (int_info.bits <= 64) {
if (rhs == .immediate) {
return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
}
return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
} else {
return self.fail("TODO binary operations on int with bits > 64", .{});
}
@ -1973,14 +1949,11 @@ fn binOp(
fn binOpRegister(
self: *Self,
tag: Air.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
lhs: MCValue,
rhs: MCValue,
lhs_ty: Type,
rhs: MCValue,
rhs_ty: Type,
) !MCValue {
_ = maybe_inst;
const lhs_reg, const lhs_lock = blk: {
if (lhs == .register) break :blk .{ lhs.register, null };
@ -2006,164 +1979,79 @@ fn binOpRegister(
.add => .add,
.sub => .sub,
.mul => .mul,
.cmp_eq => .cmp_eq,
.cmp_neq => .cmp_neq,
.cmp_gt => .cmp_gt,
.cmp_gte => .cmp_gte,
.cmp_lt => .cmp_lt,
.shl => .sllw,
.shr => .srlw,
.cmp_eq,
.cmp_neq,
.cmp_gt,
.cmp_gte,
.cmp_lt,
=> .pseudo,
else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
};
_ = try self.addInst(.{
.tag = mir_tag,
.ops = .rrr,
.data = .{
.r_type = .{
.rd = dest_reg,
.rs1 = lhs_reg,
.rs2 = rhs_reg,
},
},
});
// generate the struct for OF checks
return MCValue{ .register = dest_reg };
}
/// Don't call this function directly. Use binOp instead.
///
/// Call this function if rhs is an immediate. Generates I version of binops.
///
/// Asserts that rhs is an immediate MCValue
fn binOpImm(
self: *Self,
tag: Air.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
lhs: MCValue,
rhs: MCValue,
lhs_ty: Type,
rhs_ty: Type,
) !MCValue {
assert(rhs == .immediate);
_ = maybe_inst;
// TODO: use `maybe_inst` to track instead of forcing a lock.
const lhs_reg, const lhs_lock = blk: {
if (lhs == .register) break :blk .{ lhs.register, null };
const lhs_reg, const lhs_lock = try self.allocReg();
try self.genSetReg(lhs_ty, lhs_reg, lhs);
break :blk .{ lhs_reg, lhs_lock };
};
defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
const dest_reg, const dest_lock = try self.allocReg();
defer self.register_manager.unlockReg(dest_lock);
const mir_tag: Mir.Inst.Tag = switch (tag) {
.shl => .slli,
.shr => .srli,
.cmp_gte => .cmp_imm_gte,
.cmp_eq => .cmp_imm_eq,
.cmp_neq => .cmp_imm_neq,
.cmp_lte => .cmp_imm_lte,
.cmp_lt => .cmp_imm_lt,
.add => .addi,
.sub => .addiw,
else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),
};
// apply some special operations needed
switch (mir_tag) {
.slli,
.srli,
.addi,
.cmp_imm_eq,
.cmp_imm_neq,
.cmp_imm_lte,
.cmp_imm_lt,
.add,
.sub,
.mul,
.sllw,
.srlw,
=> {
_ = try self.addInst(.{
.tag = mir_tag,
.ops = .rri,
.data = .{ .i_type = .{
.rd = dest_reg,
.rs1 = lhs_reg,
.imm12 = Immediate.s(math.cast(i12, rhs.immediate) orelse {
return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
}),
} },
});
},
.addiw => {
_ = try self.addInst(.{
.tag = mir_tag,
.ops = .rri,
.data = .{ .i_type = .{
.rd = dest_reg,
.rs1 = lhs_reg,
.imm12 = Immediate.s(-(math.cast(i12, rhs.immediate) orelse {
return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
})),
} },
});
},
.cmp_imm_gte => {
const imm_reg = try self.copyToTmpRegister(rhs_ty, .{ .immediate = rhs.immediate - 1 });
_ = try self.addInst(.{
.tag = mir_tag,
.ops = .rrr,
.data = .{ .r_type = .{
.rd = dest_reg,
.rs1 = imm_reg,
.rs2 = lhs_reg,
} },
});
},
else => unreachable,
}
return MCValue{ .register = dest_reg };
}
fn binOpMir(
self: *Self,
mir_tag: Mir.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
ty: Type,
dst_mcv: MCValue,
src_mcv: MCValue,
) !void {
const zcu = self.bin_file.comp.module.?;
const abi_size: u32 = @intCast(ty.abiSize(zcu));
_ = abi_size;
_ = maybe_inst;
switch (dst_mcv) {
.register => |dst_reg| {
const src_reg = try self.copyToTmpRegister(ty, src_mcv);
_ = try self.addInst(.{
.tag = mir_tag,
.ops = .rrr,
.data = .{
.r_type = .{
.rd = dst_reg,
.rs1 = dst_reg,
.rs2 = src_reg,
.rd = dest_reg,
.rs1 = lhs_reg,
.rs2 = rhs_reg,
},
},
});
},
else => return self.fail("TODO: binOpMir {s}", .{@tagName(dst_mcv)}),
.pseudo => {
const pseudo_op = switch (tag) {
.cmp_eq,
.cmp_neq,
.cmp_gt,
.cmp_gte,
.cmp_lt,
=> .pseudo_compare,
else => unreachable,
};
_ = try self.addInst(.{
.tag = .pseudo,
.ops = pseudo_op,
.data = .{
.compare = .{
.rd = dest_reg,
.rs1 = lhs_reg,
.rs2 = rhs_reg,
.op = switch (tag) {
.cmp_eq => .eq,
.cmp_neq => .neq,
.cmp_gt => .gt,
.cmp_gte => .gte,
.cmp_lt => .lt,
.cmp_lte => .lte,
else => unreachable,
},
},
},
});
},
else => unreachable,
}
// generate the struct for OF checks
return MCValue{ .register = dest_reg };
}
fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
@ -2174,7 +2062,9 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
const lhs_ty = self.typeOf(bin_op.lhs);
const rhs_ty = self.typeOf(bin_op.rhs);
const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@ -2200,7 +2090,7 @@ fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
const lhs_ty = self.typeOf(bin_op.lhs);
const rhs_ty = self.typeOf(bin_op.rhs);
break :result try self.binOp(.sub, inst, lhs, rhs, lhs_ty, rhs_ty);
break :result try self.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty);
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@ -2240,7 +2130,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const lhs_ty = self.typeOf(extra.lhs);
const rhs_ty = self.typeOf(extra.rhs);
const add_result_mcv = try self.binOp(.add, null, lhs, rhs, lhs_ty, rhs_ty);
const add_result_mcv = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
const add_result_lock = self.register_manager.lockRegAssumeUnused(add_result_mcv.register);
defer self.register_manager.unlockReg(add_result_lock);
@ -2291,10 +2181,9 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const overflow_mcv = try self.binOp(
.cmp_neq,
null,
.{ .register = overflow_reg },
.{ .register = add_reg },
lhs_ty,
.{ .register = add_reg },
lhs_ty,
);
@ -2347,7 +2236,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
switch (int_info.bits) {
1...32 => {
if (self.hasFeature(.m)) {
const dest = try self.binOp(.mul, null, lhs, rhs, lhs_ty, rhs_ty);
const dest = try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);
defer self.register_manager.unlockReg(add_result_lock);
@ -2393,10 +2282,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const overflow_mcv = try self.binOp(
.cmp_neq,
null,
.{ .register = overflow_reg },
.{ .register = add_reg },
lhs_ty,
.{ .register = add_reg },
lhs_ty,
);
@ -2479,7 +2367,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
const lhs_ty = self.typeOf(bin_op.lhs);
const rhs_ty = self.typeOf(bin_op.rhs);
break :result try self.binOp(.shl, inst, lhs, rhs, lhs_ty, rhs_ty);
break :result try self.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty);
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@ -2543,10 +2431,9 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
if (err_off > 0) {
result = try self.binOp(
.shr,
null,
result,
.{ .immediate = @as(u6, @intCast(err_off * 8)) },
err_union_ty,
.{ .immediate = @as(u6, @intCast(err_off * 8)) },
Type.u8,
);
}
@ -2593,10 +2480,9 @@ fn genUnwrapErrUnionPayloadMir(
if (payload_off > 0) {
result = try self.binOp(
.shr,
null,
result,
.{ .immediate = @as(u6, @intCast(payload_off * 8)) },
err_union_ty,
.{ .immediate = @as(u6, @intCast(payload_off * 8)) },
Type.u8,
);
}
@ -2837,7 +2723,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
};
const dest = try self.allocRegOrMem(inst, true);
const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);
const addr = try self.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize);
try self.load(dest, addr, slice_ptr_field_type);
break :result dest;
@ -2885,13 +2771,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
defer self.register_manager.unlockReg(offset_lock);
const dst_mcv = try self.allocRegOrMem(inst, false);
try self.binOpMir(
.add,
null,
Type.usize,
.{ .register = addr_reg },
.{ .register = offset_reg },
);
_ = try self.addInst(.{
.tag = .add,
.ops = .rr,
.data = .{ .rr = .{
.rd = addr_reg,
.rs = offset_reg,
} },
});
try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
break :result dst_mcv;
};
@ -3046,7 +2933,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
switch (int_bits) {
16 => {
const temp = try self.binOp(.shr, null, dest_mcv, .{ .immediate = 8 }, ty, Type.u8);
const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);
assert(temp == .register);
_ = try self.addInst(.{
.tag = .slli,
@ -3752,7 +3639,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
const int_info = int_ty.intInfo(zcu);
if (int_info.bits <= 64) {
break :result try self.binOp(tag, null, lhs, rhs, int_ty, int_ty);
break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
} else {
return self.fail("TODO riscv cmp for ints > 64 bits", .{});
}
@ -4033,20 +3920,19 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
if (err_off > 0) {
return_mcv = try self.binOp(
.shr,
null,
return_mcv,
.{ .immediate = @as(u6, @intCast(err_off * 8)) },
eu_ty,
.{ .immediate = @as(u6, @intCast(err_off * 8)) },
Type.u8,
);
}
try self.binOpMir(
return_mcv = try self.binOp(
.cmp_neq,
null,
Type.anyerror,
return_mcv,
Type.u16,
.{ .immediate = 0 },
Type.u16,
);
return return_mcv;
@ -4070,8 +3956,8 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
switch (is_err_res) {
.register => |reg| {
_ = try self.addInst(.{
.tag = .not,
.ops = .rr,
.tag = .pseudo,
.ops = .pseudo_not,
.data = .{
.rr = .{
.rd = reg,
@ -4440,9 +4326,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
dst_mcv,
try self.resolveInst(src_ref),
),
else => return self.fail("TODO implement genCopy for {s} of {}", .{
@tagName(src_mcv), ty.fmt(zcu),
}),
else => unreachable,
};
defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);

View File

@ -2,9 +2,6 @@ mnemonic: Mnemonic,
data: Data,
pub const Mnemonic = enum {
// R Type
add,
// I Type
ld,
lw,
@ -13,6 +10,10 @@ pub const Mnemonic = enum {
lhu,
lb,
lbu,
sltiu,
sltu,
xori,
andi,
addi,
jalr,
@ -32,6 +33,12 @@ pub const Mnemonic = enum {
// B Type
beq,
// R Type
add,
slt,
mul,
xor,
// System
ecall,
ebreak,
@ -50,8 +57,11 @@ pub const Mnemonic = enum {
.lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },
.lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },
.sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },
.addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },
.andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },
.xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },
.jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },
.lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
@ -65,6 +75,13 @@ pub const Mnemonic = enum {
.beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },
.slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },
.sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
.xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },
.mul => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 },
.ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
.ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
.unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },
@ -98,6 +115,9 @@ pub const InstEnc = enum {
.lb,
.lbu,
.jalr,
.sltiu,
.xori,
.andi,
=> .I,
.lui,
@ -115,6 +135,12 @@ pub const InstEnc = enum {
.beq,
=> .B,
.slt,
.sltu,
.mul,
.xor,
=> .R,
.ecall,
.ebreak,
.unimp,

View File

@ -159,7 +159,83 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
});
},
else => return lower.fail("TODO Lower: psuedo {s}", .{@tagName(inst.ops)}),
.pseudo_compare => {
const compare = inst.data.compare;
const op = compare.op;
const rd = compare.rd;
const rs1 = compare.rs1;
const rs2 = compare.rs2;
switch (op) {
.eq => {
try lower.emit(.xor, &.{
.{ .reg = rd },
.{ .reg = rs1 },
.{ .reg = rs2 },
});
try lower.emit(.sltiu, &.{
.{ .reg = rd },
.{ .reg = rd },
.{ .imm = Immediate.s(1) },
});
},
.neq => {
try lower.emit(.xor, &.{
.{ .reg = rd },
.{ .reg = rs1 },
.{ .reg = rs2 },
});
try lower.emit(.sltu, &.{
.{ .reg = rd },
.{ .reg = .zero },
.{ .reg = rd },
});
},
.gt => {
try lower.emit(.sltu, &.{
.{ .reg = rd },
.{ .reg = rs1 },
.{ .reg = rs2 },
});
},
.gte => {
try lower.emit(.sltu, &.{
.{ .reg = rd },
.{ .reg = rs1 },
.{ .reg = rs2 },
});
try lower.emit(.xori, &.{
.{ .reg = rd },
.{ .reg = rd },
.{ .imm = Immediate.s(1) },
});
},
.lt => {
try lower.emit(.slt, &.{
.{ .reg = rd },
.{ .reg = rs1 },
.{ .reg = rs2 },
});
},
else => return lower.fail("TODO lower: pseudo_compare {s}", .{@tagName(op)}),
}
},
.pseudo_not => {
const rr = inst.data.rr;
try lower.emit(.xori, &.{
.{ .reg = rr.rd },
.{ .reg = rr.rs },
.{ .imm = Immediate.s(1) },
});
},
else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
},
}
@ -192,6 +268,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.{ .reg = inst.data.b_type.rs2 },
.{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },
},
.rrr => &.{
.{ .reg = inst.data.r_type.rd },
.{ .reg = inst.data.r_type.rs1 },
.{ .reg = inst.data.r_type.rs2 },
},
else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
});
}

View File

@ -67,36 +67,6 @@ pub const Inst = struct {
/// Immediate AND, uses i_type payload
andi,
// NOTE: Maybe create a special data for compares that includes the ops
/// Register `==`, uses r_type
cmp_eq,
/// Register `!=`, uses r_type
cmp_neq,
/// Register `>`, uses r_type
cmp_gt,
/// Register `<`, uses r_type
cmp_lt,
/// Register `>=`, uses r_type
cmp_gte,
/// Immediate `>=`, uses r_type
///
/// Note: this uses r_type because RISC-V does not provide a good way
/// to do `>=` comparisons on immediates. Usually we would just subtract
/// 1 from the immediate and do a `>` comparison, however there is no `>`
/// register to immedate comparison in RISC-V. This leads us to need to
/// allocate a register for temporary use.
cmp_imm_gte,
/// Immediate `==`, uses i_type
cmp_imm_eq,
/// Immediate `!=`, uses i_type.
cmp_imm_neq,
/// Immediate `<=`, uses i_type
cmp_imm_lte,
/// Immediate `<`, uses i_type
cmp_imm_lt,
/// Branch if equal, Uses b_type
beq,
/// Branch if not equal, Uses b_type
@ -213,6 +183,20 @@ pub const Inst = struct {
rd: Register,
rs: Register,
},
compare: struct {
rd: Register,
rs1: Register,
rs2: Register,
op: enum {
eq,
neq,
gt,
gte,
lt,
lte,
},
},
};
pub const Ops = enum {
@ -291,6 +275,9 @@ pub const Inst = struct {
pseudo_restore_regs,
pseudo_spill_regs,
pseudo_compare,
pseudo_not,
};
// Make sure we don't accidentally make instructions bigger than expected.

View File

@ -130,13 +130,16 @@ pub fn classifySystem(ty: Type, mod: *Module) [8]Class {
unreachable; // support > 128 bit int arguments
},
.ErrorUnion => {
const payload = ty.errorUnionPayload(mod);
const payload_bits = payload.bitSize(mod);
if (payload_bits <= 64) {
result[0] = .integer;
result[1] = .integer;
}
unreachable; // support > 64 bit error payloads
const payload_ty = ty.errorUnionPayload(mod);
const payload_bits = payload_ty.bitSize(mod);
// the error union itself
result[0] = .integer;
// anyerror!void can fit into one register
if (payload_bits == 0) return result;
std.debug.panic("support ErrorUnion payload {}", .{payload_ty.fmt(mod)});
},
else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
}