diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 5c674cecce..08633e54ca 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void { }; pass_count += 1; } + + std.posix.exit(pass_count); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 035ed1b611..f36613473b 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/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, + + .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); diff --git a/src/arch/riscv64/Encoding.zig b/src/arch/riscv64/Encoding.zig index ec113d9b91..d145e21603 100644 --- a/src/arch/riscv64/Encoding.zig +++ b/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, diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index 714f3a43ad..41bb5c6599 100644 --- a/src/arch/riscv64/Lower.zig +++ b/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)}), }); } diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index 162aeb23c4..9ecca44bd8 100644 --- a/src/arch/riscv64/Mir.zig +++ b/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. diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig index d09baab761..98de968142 100644 --- a/src/arch/riscv64/abi.zig +++ b/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)}), }