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...@@ -760,9 +760,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
760 @setCold(true);760 @setCold(true);
761761
762 // stage2_riscv64 backend doesn't support loops yet.762 // stage2_riscv64 backend doesn't support loops yet.
763 if (builtin.zig_backend == .stage2_riscv64 or763 if (builtin.zig_backend == .stage2_riscv64) {
764 builtin.cpu.arch == .riscv64)
765 {
766 unreachable;764 unreachable;
767 }765 }
768766
src/arch/riscv64/CodeGen.zig+37-3
...@@ -1385,8 +1385,44 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -1385,8 +1385,44 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
1385}1385}
13861386
1387fn airAbs(self: *Self, inst: Air.Inst.Index) !void {1387fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
1388 const mod = self.bin_file.comp.module.?;
1388 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;1389 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 };
1390 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1426 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1391}1427}
13921428
...@@ -1603,8 +1639,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -1603,8 +1639,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1603 self.register_manager.getRegAssumeFree(src_reg, inst);1639 self.register_manager.getRegAssumeFree(src_reg, inst);
1604 break :dst src_mcv;1640 break :dst src_mcv;
1605 },1641 },
1606 // don't need to allocate anything, can just be used immediately.
1607 .stack_offset => src_mcv,
1608 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),1642 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
1609 };1643 };
16101644
src/arch/riscv64/Emit.zig+7
...@@ -58,6 +58,7 @@ pub fn emitMir(...@@ -58,6 +58,7 @@ pub fn emitMir(
5858
59 .addi => try emit.mirIType(inst),59 .addi => try emit.mirIType(inst),
60 .jalr => try emit.mirIType(inst),60 .jalr => try emit.mirIType(inst),
61 .abs => try emit.mirIType(inst),
6162
62 .jal => try emit.mirJType(inst),63 .jal => try emit.mirJType(inst),
6364
...@@ -200,6 +201,12 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -200,6 +201,12 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
200201
201 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),202 .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
203 else => unreachable,210 else => unreachable,
204 }211 }
205}212}
src/arch/riscv64/Mir.zig+3
...@@ -38,6 +38,9 @@ pub const Inst = struct {...@@ -38,6 +38,9 @@ pub const Inst = struct {
38 /// Subtraction38 /// Subtraction
39 sub,39 sub,
4040
41 /// Absolute Value, uses i_type payload.
42 abs,
43
41 jal,44 jal,
42 /// Jumps. Uses `inst` payload.45 /// Jumps. Uses `inst` payload.
43 j,46 j,
src/arch/riscv64/bits.zig+5-5
...@@ -250,7 +250,7 @@ pub const Instruction = union(enum) {...@@ -250,7 +250,7 @@ pub const Instruction = union(enum) {
250 }250 }
251251
252 pub fn srai(rd: Register, r1: Register, shamt: u6) Instruction {252 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);
254 }254 }
255255
256 pub fn slti(rd: Register, r1: Register, imm: i12) Instruction {256 pub fn slti(rd: Register, r1: Register, imm: i12) Instruction {
...@@ -267,16 +267,16 @@ pub const Instruction = union(enum) {...@@ -267,16 +267,16 @@ pub const Instruction = union(enum) {
267 return iType(0b0011011, 0b000, rd, r1, imm);267 return iType(0b0011011, 0b000, rd, r1, imm);
268 }268 }
269269
270 pub fn slliw(rd: Register, r1: Register, shamt: u5) Instruction {270 pub fn slliw(rd: Register, r1: Register, shamt: u6) Instruction {
271 return iType(0b0011011, 0b001, rd, r1, shamt);271 return iType(0b0011011, 0b001, rd, r1, shamt);
272 }272 }
273273
274 pub fn srliw(rd: Register, r1: Register, shamt: u5) Instruction {274 pub fn srliw(rd: Register, r1: Register, shamt: u6) Instruction {
275 return iType(0b0011011, 0b101, rd, r1, shamt);275 return iType(0b0011011, 0b101, rd, r1, shamt);
276 }276 }
277277
278 pub fn sraiw(rd: Register, r1: Register, shamt: u5) Instruction {278 pub fn sraiw(rd: Register, r1: Register, shamt: u6) Instruction {
279 return iType(0b0011011, 0b101, rd, r1, (1 << 10) + shamt);279 return iType(0b0011011, 0b101, rd, r1, (@as(i12, 1) << 10) + shamt);
280 }280 }
281281
282 // Upper Immediate282 // Upper Immediate
src/target.zig+1-1
...@@ -507,7 +507,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken...@@ -507,7 +507,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
507 if (use_llvm) return .stage2_llvm;507 if (use_llvm) return .stage2_llvm;
508 if (target.ofmt == .c) return .stage2_c;508 if (target.ofmt == .c) return .stage2_c;
509 return switch (target.cpu.arch) {509 return switch (target.cpu.arch) {
510 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,510 .wasm32, .wasm64 => .stage2_wasm,
511 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,511 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
512 .x86_64 => .stage2_x86_64,512 .x86_64 => .stage2_x86_64,
513 .x86 => .stage2_x86,513 .x86 => .stage2_x86,