Commit 93e9c7a963
Changed files (5)
src
arch
src/arch/riscv64/CodeGen.zig
@@ -1123,6 +1123,7 @@ const required_features = [_]Target.riscv.Feature{
.a,
.zicsr,
.v,
+ .zbb,
};
fn gen(func: *Func) !void {
@@ -2385,20 +2386,24 @@ fn genBinOp(
.mul,
.mul_wrap,
.rem,
+ .div_trunc,
=> {
- if (!math.isPowerOfTwo(bit_size))
- return func.fail(
- "TODO: genBinOp {s} non-pow 2, found {}",
- .{ @tagName(tag), bit_size },
- );
-
switch (tag) {
.rem,
+ .div_trunc,
=> {
- try func.truncateRegister(lhs_ty, lhs_reg);
- try func.truncateRegister(rhs_ty, rhs_reg);
+ if (!math.isPowerOfTwo(bit_size)) {
+ try func.truncateRegister(lhs_ty, lhs_reg);
+ try func.truncateRegister(rhs_ty, rhs_reg);
+ }
+ },
+ else => {
+ if (!math.isPowerOfTwo(bit_size))
+ return func.fail(
+ "TODO: genBinOp verify {s} non-pow 2, found {}",
+ .{ @tagName(tag), bit_size },
+ );
},
- else => {},
}
switch (lhs_ty.zigTypeTag(zcu)) {
@@ -2420,8 +2425,12 @@ fn genBinOp(
else => unreachable,
},
.rem => switch (bit_size) {
- 64 => if (is_unsigned) .remu else .rem,
- else => if (is_unsigned) .remuw else .remu,
+ 8, 16, 32 => if (is_unsigned) .remuw else .remw,
+ else => if (is_unsigned) .remu else .rem,
+ },
+ .div_trunc => switch (bit_size) {
+ 8, 16, 32 => if (is_unsigned) .divuw else .divw,
+ else => if (is_unsigned) .divu else .div,
},
else => unreachable,
};
@@ -2455,7 +2464,7 @@ fn genBinOp(
64 => .fmuld,
else => unreachable,
},
- else => unreachable,
+ else => return func.fail("TODO: genBinOp {s} Float", .{@tagName(tag)}),
};
_ = try func.addInst(.{
@@ -2588,46 +2597,6 @@ fn genBinOp(
}
},
- .div_trunc,
- => {
- if (!math.isPowerOfTwo(bit_size))
- return func.fail(
- "TODO: genBinOp {s} non-pow 2, found {}",
- .{ @tagName(tag), bit_size },
- );
-
- const mir_tag: Mir.Inst.Tag = switch (tag) {
- .div_trunc => switch (bit_size) {
- 8, 16, 32 => if (is_unsigned) .divuw else .divw,
- 64 => if (is_unsigned) .divu else .div,
- else => unreachable,
- },
- else => unreachable,
- };
-
- _ = try func.addInst(.{
- .tag = mir_tag,
- .ops = .rrr,
- .data = .{
- .r_type = .{
- .rd = dst_reg,
- .rs1 = lhs_reg,
- .rs2 = rhs_reg,
- },
- },
- });
-
- if (!is_unsigned) {
- // truncate when the instruction is larger than the bit size.
- switch (bit_size) {
- 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
- 32 => {}, // divw affects the first 32-bits
- 64 => {}, // div affects the entire register
- else => unreachable,
- }
- }
- },
-
.shr,
.shr_exact,
.shl,
@@ -3740,7 +3709,59 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
fn airClz(func: *Func, inst: Air.Inst.Index) !void {
const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
- const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airClz for {}", .{func.target.cpu.arch});
+ const operand = try func.resolveInst(ty_op.operand);
+ const ty = func.typeOf(ty_op.operand);
+
+ const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
+ const src_reg, const src_lock = try func.promoteReg(ty, operand);
+ defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
+
+ const dst_reg: Register = if (func.reuseOperand(
+ inst,
+ ty_op.operand,
+ 0,
+ operand,
+ ) and operand == .register)
+ operand.register
+ else
+ (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
+
+ const bit_size = ty.bitSize(func.pt);
+ if (!math.isPowerOfTwo(bit_size)) try func.truncateRegister(ty, src_reg);
+
+ if (bit_size > 64) {
+ return func.fail("TODO: airClz > 64 bits, found {d}", .{bit_size});
+ }
+
+ _ = try func.addInst(.{
+ .tag = switch (bit_size) {
+ 32 => .clzw,
+ else => .clz,
+ },
+ .ops = .rrr,
+ .data = .{
+ .r_type = .{
+ .rs2 = .zero, // rs2 is 0 filled in the spec
+ .rs1 = src_reg,
+ .rd = dst_reg,
+ },
+ },
+ });
+
+ if (!(bit_size == 32 or bit_size == 64)) {
+ _ = try func.addInst(.{
+ .tag = .addi,
+ .ops = .rri,
+ .data = .{ .i_type = .{
+ .rd = dst_reg,
+ .rs1 = dst_reg,
+ .imm12 = Immediate.s(-@as(i12, @intCast(64 - bit_size % 64))),
+ } },
+ });
+ }
+
+ break :result .{ .register = dst_reg };
+ };
return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
src/arch/riscv64/Encoding.zig
@@ -135,6 +135,7 @@ const Enc = struct {
};
};
+// TODO: this is basically a copy of the MIR table, we should be able to de-dupe them somehow.
pub const Mnemonic = enum {
// base mnemonics
@@ -324,6 +325,10 @@ pub const Mnemonic = enum {
// TODO: Q extension
+ // Zbb Extension
+ clz,
+ clzw,
+
pub fn encoding(mnem: Mnemonic) Enc {
return switch (mnem) {
// zig fmt: off
@@ -368,6 +373,7 @@ pub const Mnemonic = enum {
.srli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
.srai => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
+ .clz => .{ .opcode = .OP_IMM, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
// OP_IMM_32
@@ -375,6 +381,7 @@ pub const Mnemonic = enum {
.srliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
.sraiw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
+ .clzw => .{ .opcode = .OP_IMM_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
// OP_32
@@ -722,6 +729,9 @@ pub const InstEnc = enum {
.vadcvv,
.vmvvx,
.vslidedownvx,
+
+ .clz,
+ .clzw,
=> .R,
.ecall,
src/arch/riscv64/Mir.zig
@@ -149,6 +149,10 @@ pub const Inst = struct {
vfmulvv,
vslidedownvx,
+ // Zbb Extension Instructions
+ clz,
+ clzw,
+
/// A pseudo-instruction. Used for anything that isn't 1:1 with an
/// assembly instruction.
pseudo,
test/behavior/math.zig
@@ -65,7 +65,6 @@ test "@clz" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try testClz();
try comptime testClz();
test/tests.zig
@@ -439,7 +439,7 @@ const test_targets = blk: {
.target = std.Target.Query.parse(
.{
.arch_os_abi = "riscv64-linux-musl",
- .cpu_features = "baseline+v",
+ .cpu_features = "baseline+v+zbb",
},
) catch @panic("OOM"),
.use_llvm = false,