Commit e622485df8
Changed files (6)
lib
compiler
src
arch
lib/compiler/test_runner.zig
@@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
};
pass_count += 1;
}
+
+ std.posix.exit(pass_count);
}
src/arch/riscv64/abi.zig
@@ -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)}),
}
src/arch/riscv64/CodeGen.zig
@@ -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,
- 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);
+ .cmp_eq,
+ .cmp_neq,
+ .cmp_gt,
+ .cmp_gte,
+ .cmp_lt,
+ => .pseudo,
- 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)}),
+ else => return self.fail("TODO: binOpRegister {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,
- } },
+ .data = .{
+ .r_type = .{
+ .rd = dest_reg,
+ .rs1 = lhs_reg,
+ .rs2 = rhs_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);
+ .pseudo => {
+ const pseudo_op = switch (tag) {
+ .cmp_eq,
+ .cmp_neq,
+ .cmp_gt,
+ .cmp_gte,
+ .cmp_lt,
+ => .pseudo_compare,
+ else => unreachable,
+ };
_ = try self.addInst(.{
- .tag = mir_tag,
- .ops = .rrr,
+ .tag = .pseudo,
+ .ops = pseudo_op,
.data = .{
- .r_type = .{
- .rd = dst_reg,
- .rs1 = dst_reg,
- .rs2 = src_reg,
+ .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 => return self.fail("TODO: binOpMir {s}", .{@tagName(dst_mcv)}),
+ 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);
src/arch/riscv64/Encoding.zig
@@ -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,
src/arch/riscv64/Lower.zig
@@ -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)}),
});
}
src/arch/riscv64/Mir.zig
@@ -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.