mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
riscv: actually working test runner
This commit is contained in:
parent
d19b77d63f
commit
e622485df8
@ -266,4 +266,6 @@ pub fn mainExtraSimple() !void {
|
||||
};
|
||||
pass_count += 1;
|
||||
}
|
||||
|
||||
std.posix.exit(pass_count);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)}),
|
||||
});
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)}),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user