diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 9c63125da0..67176dad08 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -1028,8 +1028,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .mode = @enumToInt(Instructions.CallBreak.Mode.ebreak), }); - try self.code.resize(self.code.items.len + 4); - mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full); }, else => return self.fail(src, "TODO implement @breakpoint() for {}", .{self.target.cpu.arch}), } @@ -1351,8 +1350,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .mode = @enumToInt(Instructions.CallBreak.Mode.ecall), }); - try self.code.resize(self.code.items.len + 4); - mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full); } else { return self.fail(inst.base.src, "TODO implement support for more riscv64 assembly instructions", .{}); } @@ -1546,29 +1544,74 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) InnerError!void { switch (arch) { .riscv64 => switch (mcv) { - .immediate => |x| { - if (x > math.maxInt(u11)) { - return self.fail(src, "TODO genSetReg 12+ bit immediates for riscv64", .{}); + .dead => unreachable, + .ptr_stack_offset => unreachable, + .ptr_embedded_in_code => unreachable, + .unreach, .none => return, // Nothing to do. + .undef => { + if (!self.wantSafety()) + return; // The already existing value will do just fine. + // Write the debug undefined value. + switch (reg.size()) { + 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), + else => unreachable, } - const Instruction = packed struct { - opcode: u7, - rd: u5, - mode: u3, - rsi1: u5, - imm: u11, - signextend: u1 = 0, - }; - const full = @bitCast(u32, Instructions.Addi{ - .imm = @intCast(u11, x), - .rsi1 = Register.zero.id(), - .mode = @enumToInt(Instructions.Addi.Mode.addi), + }, + .immediate => |unsigned_x| { + const x = @bitCast(i64, unsigned_x); + if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { + const instruction = @bitCast(u32, Instructions.Addi{ + .mode = @enumToInt(Instructions.Addi.Mode.addi), + .imm = @truncate(i12, x), + .rs1 = Register.zero.id(), + .rd = reg.id(), + }); + + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), instruction); + return; + } + if (math.minInt(i32) <= x and x <= math.maxInt(i32)) { + const split = @bitCast(packed struct { + low12: i12, + up20: i20, + }, @truncate(i32, x)); + if (split.low12 < 0) return self.fail(src, "TODO support riscv64 genSetReg i32 immediates with 12th bit set to 1", .{}); + + const lui = @bitCast(u32, Instructions.Lui{ + .imm = split.up20, + .rd = reg.id(), + }); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), lui); + + const addi = @bitCast(u32, Instructions.Addi{ + .mode = @enumToInt(Instructions.Addi.Mode.addi), + .imm = @truncate(i12, split.low12), + .rs1 = reg.id(), + .rd = reg.id(), + }); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), addi); + return; + } + return self.fail(src, "TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf + }, + .memory => |addr| { + // The value is in memory at a hard-coded address. + // If the type is a pointer, it means the pointer address is at this memory location. + try self.genSetReg(src, reg, .{ .immediate = addr }); + + const ld = @bitCast(u32, Instructions.Load{ + .mode = @enumToInt(Instructions.Load.Mode.ld), + .rs1 = reg.id(), .rd = reg.id(), + .offset = 0, }); - try self.code.resize(self.code.items.len + 4); - mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), ld); + // LOAD imm=[i12 offset = 0], rs1 = + + // return self.fail("TODO implement genSetReg memory for riscv64"); }, - else => return self.fail(src, "TODO implement getSetReg for riscv64 MCValue {}", .{mcv}), + else => return self.fail(src, "TODO implement getSetReg for riscv64 {}", .{mcv}), }, .x86_64 => switch (mcv) { .dead => unreachable, diff --git a/src-self-hosted/codegen/riscv64.zig b/src-self-hosted/codegen/riscv64.zig index b6b4e099fc..1dab289010 100644 --- a/src-self-hosted/codegen/riscv64.zig +++ b/src-self-hosted/codegen/riscv64.zig @@ -5,29 +5,41 @@ pub const Instructions = struct { unused1: u5 = 0, unused2: u3 = 0, unused3: u5 = 0, - mode: u12, + mode: u12, //: Mode }; pub const Addi = packed struct { pub const Mode = packed enum(u3) { addi = 0b000, slti = 0b010, sltiu = 0b011, xori = 0b100, ori = 0b110, andi = 0b111 }; opcode: u7 = 0b0010011, rd: u5, - mode: u3, - rsi1: u5, - imm: u11, - signextend: u1 = 0, + mode: u3, //: Mode + rs1: u5, + imm: i12, + }; + pub const Lui = packed struct { + opcode: u7 = 0b0110111, + rd: u5, + imm: i20, + }; + pub const Load = packed struct { + pub const Mode = packed enum(u3) { ld = 0b011, lwu = 0b110 }; + opcode: u7 = 0b0000011, + rd: u5, + mode: u3, //: Mode + rs1: u5, + offset: i12, }; }; // zig fmt: off pub const Register = enum(u8) { // 64 bit registers - zero = 0, // zero - ra = 1, // return address. caller saved - sp = 2, // stack pointer. callee saved. - gp = 3, // global pointer - tp = 4, // thread pointer - t0 = 5, t1 = 6, t2 = 7, // temporaries. caller saved. - s0 = 8, // s0/fp, callee saved. + zero, // zero + ra, // return address. caller saved + sp, // stack pointer. callee saved. + gp, // global pointer + tp, // thread pointer + t0, t1, t2, // temporaries. caller saved. + s0, // s0/fp, callee saved. s1, // callee saved. a0, a1, // fn args/return values. caller saved. a2, a3, a4, a5, a6, a7, // fn args. caller saved.