authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-13 21:02:15-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log28df64cba45595a201f8c2312656922a8c28a67c
tree13679895113da1e2fa0199e1b117060bbed880cf
parent060c475fcd358eb9d05d14ec9f1bb7bfc47e4423

riscv: implement `@abs`

- add the `abs` MIR instruction - implement `@abs` by shifting to the right by `bits - 1`, and xoring.

6 files changed, 54 insertions(+), 12 deletions(-)

lib/std/builtin.zig+1-3
......@@ -760,9 +760,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
760760 @setCold(true);
761761
762762 // stage2_riscv64 backend doesn't support loops yet.
763 if (builtin.zig_backend == .stage2_riscv64 or
764 builtin.cpu.arch == .riscv64)
765 {
763 if (builtin.zig_backend == .stage2_riscv64) {
766764 unreachable;
767765 }
768766
src/arch/riscv64/CodeGen.zig+37-3
......@@ -1385,8 +1385,44 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
13851385}
13861386
13871387fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
1388 const mod = self.bin_file.comp.module.?;
13881389 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1389 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch});
1390 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1391 const ty = self.typeOf(ty_op.operand);
1392 const scalar_ty = ty.scalarType(mod);
1393 const operand = try self.resolveInst(ty_op.operand);
1394
1395 switch (scalar_ty.zigTypeTag(mod)) {
1396 .Int => if (ty.zigTypeTag(mod) == .Vector) {
1397 return self.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});
1398 } else {
1399 const int_bits = ty.intInfo(mod).bits;
1400
1401 if (int_bits > 32) {
1402 return self.fail("TODO: airAbs for larger than 32 bits", .{});
1403 }
1404
1405 // promote the src into a register
1406 const src_mcv = try self.copyToNewRegister(inst, operand);
1407 // temp register for shift
1408 const temp_reg = try self.register_manager.allocReg(inst, gp);
1409
1410 _ = try self.addInst(.{
1411 .tag = .abs,
1412 .data = .{
1413 .i_type = .{
1414 .rs1 = src_mcv.register,
1415 .rd = temp_reg,
1416 .imm12 = @intCast(int_bits - 1),
1417 },
1418 },
1419 });
1420
1421 break :result src_mcv;
1422 },
1423 else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(mod)}),
1424 }
1425 };
13901426 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13911427}
13921428
......@@ -1603,8 +1639,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
16031639 self.register_manager.getRegAssumeFree(src_reg, inst);
16041640 break :dst src_mcv;
16051641 },
1606 // don't need to allocate anything, can just be used immediately.
1607 .stack_offset => src_mcv,
16081642 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
16091643 };
16101644
src/arch/riscv64/Emit.zig+7
......@@ -58,6 +58,7 @@ pub fn emitMir(
5858
5959 .addi => try emit.mirIType(inst),
6060 .jalr => try emit.mirIType(inst),
61 .abs => try emit.mirIType(inst),
6162
6263 .jal => try emit.mirJType(inst),
6364
......@@ -200,6 +201,12 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
200201
201202 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),
202203
204 .abs => {
205 try emit.writeInstruction(Instruction.sraiw(i_type.rd, i_type.rs1, @intCast(i_type.imm12)));
206 try emit.writeInstruction(Instruction.xor(i_type.rs1, i_type.rs1, i_type.rd));
207 try emit.writeInstruction(Instruction.subw(i_type.rs1, i_type.rs1, i_type.rd));
208 },
209
203210 else => unreachable,
204211 }
205212}
src/arch/riscv64/Mir.zig+3
......@@ -38,6 +38,9 @@ pub const Inst = struct {
3838 /// Subtraction
3939 sub,
4040
41 /// Absolute Value, uses i_type payload.
42 abs,
43
4144 jal,
4245 /// Jumps. Uses `inst` payload.
4346 j,
src/arch/riscv64/bits.zig+5-5
......@@ -250,7 +250,7 @@ pub const Instruction = union(enum) {
250250 }
251251
252252 pub fn srai(rd: Register, r1: Register, shamt: u6) Instruction {
253 return iType(0b0010011, 0b101, rd, r1, (1 << 10) + shamt);
253 return iType(0b0010011, 0b101, rd, r1, (@as(i12, 1) << 10) + shamt);
254254 }
255255
256256 pub fn slti(rd: Register, r1: Register, imm: i12) Instruction {
......@@ -267,16 +267,16 @@ pub const Instruction = union(enum) {
267267 return iType(0b0011011, 0b000, rd, r1, imm);
268268 }
269269
270 pub fn slliw(rd: Register, r1: Register, shamt: u5) Instruction {
270 pub fn slliw(rd: Register, r1: Register, shamt: u6) Instruction {
271271 return iType(0b0011011, 0b001, rd, r1, shamt);
272272 }
273273
274 pub fn srliw(rd: Register, r1: Register, shamt: u5) Instruction {
274 pub fn srliw(rd: Register, r1: Register, shamt: u6) Instruction {
275275 return iType(0b0011011, 0b101, rd, r1, shamt);
276276 }
277277
278 pub fn sraiw(rd: Register, r1: Register, shamt: u5) Instruction {
279 return iType(0b0011011, 0b101, rd, r1, (1 << 10) + shamt);
278 pub fn sraiw(rd: Register, r1: Register, shamt: u6) Instruction {
279 return iType(0b0011011, 0b101, rd, r1, (@as(i12, 1) << 10) + shamt);
280280 }
281281
282282 // Upper Immediate
src/target.zig+1-1
......@@ -507,7 +507,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
507507 if (use_llvm) return .stage2_llvm;
508508 if (target.ofmt == .c) return .stage2_c;
509509 return switch (target.cpu.arch) {
510 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
510 .wasm32, .wasm64 => .stage2_wasm,
511511 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
512512 .x86_64 => .stage2_x86_64,
513513 .x86 => .stage2_x86,