From 0b53a2d996e7cad9f69ca04c5747f601f89468ef Mon Sep 17 00:00:00 2001 From: pfg Date: Tue, 4 Aug 2020 02:33:40 -0700 Subject: [PATCH] stage2: riscv 0 argument non-nested function calls --- src-self-hosted/codegen.zig | 60 +++++++++++++++++++++++------ src-self-hosted/codegen/riscv64.zig | 30 +++++++++++++-- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 67176dad08..74404d706e 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -1024,8 +1024,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.code.append(0xcc); // int3 }, .riscv64 => { - const full = @bitCast(u32, Instructions.CallBreak{ - .mode = @enumToInt(Instructions.CallBreak.Mode.ebreak), + const full = @bitCast(u32, instructions.CallBreak{ + .mode = @enumToInt(instructions.CallBreak.Mode.ebreak), }); mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full); @@ -1092,6 +1092,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); } }, + .riscv64 => { + if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch}); + + if (inst.func.cast(ir.Inst.Constant)) |func_inst| { + if (func_inst.val.cast(Value.Payload.Function)) |func_val| { + const func = func_val.func; + const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes); + + try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); + const jalr = instructions.Jalr{ + .rd = Register.ra.id(), + .rs1 = Register.ra.id(), + .offset = 0, + }; + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), @bitCast(u32, jalr)); + } else { + return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); + } + } else { + return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); + } + }, else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), } @@ -1140,6 +1165,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); }, + .riscv64 => { + const jalr = instructions.Jalr{ + .rd = Register.zero.id(), + .rs1 = Register.ra.id(), + .offset = 0, + }; + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), @bitCast(u32, jalr)); + }, else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}), } return .unreach; @@ -1346,8 +1379,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } if (mem.eql(u8, inst.asm_source, "ecall")) { - const full = @bitCast(u32, Instructions.CallBreak{ - .mode = @enumToInt(Instructions.CallBreak.Mode.ecall), + const full = @bitCast(u32, instructions.CallBreak{ + .mode = @enumToInt(instructions.CallBreak.Mode.ecall), }); mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full); @@ -1560,8 +1593,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .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), + const instruction = @bitCast(u32, instructions.Addi{ + .mode = @enumToInt(instructions.Addi.Mode.addi), .imm = @truncate(i12, x), .rs1 = Register.zero.id(), .rd = reg.id(), @@ -1577,14 +1610,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { }, @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{ + 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), + const addi = @bitCast(u32, instructions.Addi{ + .mode = @enumToInt(instructions.Addi.Mode.addi), .imm = @truncate(i12, split.low12), .rs1 = reg.id(), .rd = reg.id(), @@ -1592,6 +1625,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { mem.writeIntLittle(u32, try self.code.addManyAsArray(4), addi); return; } + // li rd, immediate + // "Myriad sequences" return self.fail(src, "TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf }, .memory => |addr| { @@ -1599,8 +1634,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { // 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), + const ld = @bitCast(u32, instructions.Load{ + .mode = @enumToInt(instructions.Load.Mode.ld), .rs1 = reg.id(), .rd = reg.id(), .offset = 0, @@ -2046,6 +2081,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const FreeRegInt = @Type(.{ .Int = .{ .is_signed = false, .bits = callee_preserved_regs.len } }); fn parseRegName(name: []const u8) ?Register { + if (@hasDecl(Register, "parseRegName")) { + return Register.parseRegName(name); + } return std.meta.stringToEnum(Register, name); } diff --git a/src-self-hosted/codegen/riscv64.zig b/src-self-hosted/codegen/riscv64.zig index 1dab289010..4b311feaf9 100644 --- a/src-self-hosted/codegen/riscv64.zig +++ b/src-self-hosted/codegen/riscv64.zig @@ -1,4 +1,6 @@ -pub const Instructions = struct { +const std = @import("std"); + +pub const instructions = struct { pub const CallBreak = packed struct { pub const Mode = packed enum(u12) { ecall, ebreak }; opcode: u7 = 0b1110011, @@ -7,6 +9,7 @@ pub const Instructions = struct { unused3: u5 = 0, mode: u12, //: Mode }; + // I-type 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, @@ -20,6 +23,7 @@ pub const Instructions = struct { rd: u5, imm: i20, }; + // I_type pub const Load = packed struct { pub const Mode = packed enum(u3) { ld = 0b011, lwu = 0b110 }; opcode: u7 = 0b0000011, @@ -28,9 +32,24 @@ pub const Instructions = struct { rs1: u5, offset: i12, }; + // I-type + pub const Jalr = packed struct { + opcode: u7 = 0b1100111, + rd: u5, + mode: u3 = 0, + rs1: u5, + offset: i12, + }; }; // zig fmt: off +pub const RawRegister = enum(u8) { + x0, x1, x2, x3, x4, x5, x6, x7, + x8, x9, x10, x11, x12, x13, x14, x15, + x16, x17, x18, x19, x20, x21, x22, x23, + x24, x25, x26, x27, x28, x29, x30, x31, +}; + pub const Register = enum(u8) { // 64 bit registers zero, // zero @@ -45,6 +64,12 @@ pub const Register = enum(u8) { a2, a3, a4, a5, a6, a7, // fn args. caller saved. s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, // saved registers. callee saved. t3, t4, t5, t6, // caller saved + + pub fn parseRegName(name: []const u8) ?Register { + if(std.meta.stringToEnum(Register, name)) |reg| return reg; + if(std.meta.stringToEnum(RawRegister, name)) |rawreg| return @intToEnum(Register, @enumToInt(rawreg)); + return null; + } /// Returns the bit-width of the register. pub fn size(self: @This()) u7 { @@ -58,8 +83,7 @@ pub const Register = enum(u8) { return self; } - /// Returns the register's id. This is used in practically every opcode the - /// riscv64 has. + /// Returns the register's id. pub fn id(self: @This()) u5 { return @truncate(u5, @enumToInt(self)); }