authorgravatar for pfg@pfg.pwpfg <pfg@pfg.pw> 2020-08-04 02:33:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-04 14:38:33-07:00
log0b53a2d996e7cad9f69ca04c5747f601f89468ef
tree8080c69e244f8b2ee9c23fe1bae71eedb2aea3e6
parent1fd99ed32427be59567130c0304c743a22e6eb60

stage2: riscv 0 argument non-nested function calls


2 files changed, 76 insertions(+), 14 deletions(-)

src-self-hosted/codegen.zig+49-11
...@@ -1024,8 +1024,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1024,8 +1024,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1024 try self.code.append(0xcc); // int31024 try self.code.append(0xcc); // int3
1025 },1025 },
1026 .riscv64 => {1026 .riscv64 => {
1027 const full = @bitCast(u32, Instructions.CallBreak{1027 const full = @bitCast(u32, instructions.CallBreak{
1028 .mode = @enumToInt(Instructions.CallBreak.Mode.ebreak),1028 .mode = @enumToInt(instructions.CallBreak.Mode.ebreak),
1029 });1029 });
10301030
1031 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full);1031 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full);
...@@ -1092,6 +1092,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1092,6 +1092,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1092 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});1092 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1093 }1093 }
1094 },1094 },
1095 .riscv64 => {
1096 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1097
1098 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1099 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1100 const func = func_val.func;
1101 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
1102 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1103 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1104 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
1105
1106 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
1107 const jalr = instructions.Jalr{
1108 .rd = Register.ra.id(),
1109 .rs1 = Register.ra.id(),
1110 .offset = 0,
1111 };
1112 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), @bitCast(u32, jalr));
1113 } else {
1114 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1115 }
1116 } else {
1117 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1118 }
1119 },
1095 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),1120 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
1096 }1121 }
10971122
...@@ -1140,6 +1165,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1140,6 +1165,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1140 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel321165 self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
1141 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);1166 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
1142 },1167 },
1168 .riscv64 => {
1169 const jalr = instructions.Jalr{
1170 .rd = Register.zero.id(),
1171 .rs1 = Register.ra.id(),
1172 .offset = 0,
1173 };
1174 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), @bitCast(u32, jalr));
1175 },
1143 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),1176 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
1144 }1177 }
1145 return .unreach;1178 return .unreach;
...@@ -1346,8 +1379,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1346,8 +1379,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1346 }1379 }
13471380
1348 if (mem.eql(u8, inst.asm_source, "ecall")) {1381 if (mem.eql(u8, inst.asm_source, "ecall")) {
1349 const full = @bitCast(u32, Instructions.CallBreak{1382 const full = @bitCast(u32, instructions.CallBreak{
1350 .mode = @enumToInt(Instructions.CallBreak.Mode.ecall),1383 .mode = @enumToInt(instructions.CallBreak.Mode.ecall),
1351 });1384 });
13521385
1353 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full);1386 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), full);
...@@ -1560,8 +1593,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1560,8 +1593,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1560 .immediate => |unsigned_x| {1593 .immediate => |unsigned_x| {
1561 const x = @bitCast(i64, unsigned_x);1594 const x = @bitCast(i64, unsigned_x);
1562 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {1595 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
1563 const instruction = @bitCast(u32, Instructions.Addi{1596 const instruction = @bitCast(u32, instructions.Addi{
1564 .mode = @enumToInt(Instructions.Addi.Mode.addi),1597 .mode = @enumToInt(instructions.Addi.Mode.addi),
1565 .imm = @truncate(i12, x),1598 .imm = @truncate(i12, x),
1566 .rs1 = Register.zero.id(),1599 .rs1 = Register.zero.id(),
1567 .rd = reg.id(),1600 .rd = reg.id(),
...@@ -1577,14 +1610,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1577,14 +1610,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1577 }, @truncate(i32, x));1610 }, @truncate(i32, x));
1578 if (split.low12 < 0) return self.fail(src, "TODO support riscv64 genSetReg i32 immediates with 12th bit set to 1", .{});1611 if (split.low12 < 0) return self.fail(src, "TODO support riscv64 genSetReg i32 immediates with 12th bit set to 1", .{});
15791612
1580 const lui = @bitCast(u32, Instructions.Lui{1613 const lui = @bitCast(u32, instructions.Lui{
1581 .imm = split.up20,1614 .imm = split.up20,
1582 .rd = reg.id(),1615 .rd = reg.id(),
1583 });1616 });
1584 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), lui);1617 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), lui);
15851618
1586 const addi = @bitCast(u32, Instructions.Addi{1619 const addi = @bitCast(u32, instructions.Addi{
1587 .mode = @enumToInt(Instructions.Addi.Mode.addi),1620 .mode = @enumToInt(instructions.Addi.Mode.addi),
1588 .imm = @truncate(i12, split.low12),1621 .imm = @truncate(i12, split.low12),
1589 .rs1 = reg.id(),1622 .rs1 = reg.id(),
1590 .rd = reg.id(),1623 .rd = reg.id(),
...@@ -1592,6 +1625,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1592,6 +1625,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1592 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), addi);1625 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), addi);
1593 return;1626 return;
1594 }1627 }
1628 // li rd, immediate
1629 // "Myriad sequences"
1595 return self.fail(src, "TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf1630 return self.fail(src, "TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf
1596 },1631 },
1597 .memory => |addr| {1632 .memory => |addr| {
...@@ -1599,8 +1634,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1599,8 +1634,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1599 // If the type is a pointer, it means the pointer address is at this memory location.1634 // If the type is a pointer, it means the pointer address is at this memory location.
1600 try self.genSetReg(src, reg, .{ .immediate = addr });1635 try self.genSetReg(src, reg, .{ .immediate = addr });
16011636
1602 const ld = @bitCast(u32, Instructions.Load{1637 const ld = @bitCast(u32, instructions.Load{
1603 .mode = @enumToInt(Instructions.Load.Mode.ld),1638 .mode = @enumToInt(instructions.Load.Mode.ld),
1604 .rs1 = reg.id(),1639 .rs1 = reg.id(),
1605 .rd = reg.id(),1640 .rd = reg.id(),
1606 .offset = 0,1641 .offset = 0,
...@@ -2046,6 +2081,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2046,6 +2081,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2046 const FreeRegInt = @Type(.{ .Int = .{ .is_signed = false, .bits = callee_preserved_regs.len } });2081 const FreeRegInt = @Type(.{ .Int = .{ .is_signed = false, .bits = callee_preserved_regs.len } });
20472082
2048 fn parseRegName(name: []const u8) ?Register {2083 fn parseRegName(name: []const u8) ?Register {
2084 if (@hasDecl(Register, "parseRegName")) {
2085 return Register.parseRegName(name);
2086 }
2049 return std.meta.stringToEnum(Register, name);2087 return std.meta.stringToEnum(Register, name);
2050 }2088 }
20512089
src-self-hosted/codegen/riscv64.zig+27-3
...@@ -1,4 +1,6 @@...@@ -1,4 +1,6 @@
1pub const Instructions = struct {1const std = @import("std");
2
3pub const instructions = struct {
2 pub const CallBreak = packed struct {4 pub const CallBreak = packed struct {
3 pub const Mode = packed enum(u12) { ecall, ebreak };5 pub const Mode = packed enum(u12) { ecall, ebreak };
4 opcode: u7 = 0b1110011,6 opcode: u7 = 0b1110011,
...@@ -7,6 +9,7 @@ pub const Instructions = struct {...@@ -7,6 +9,7 @@ pub const Instructions = struct {
7 unused3: u5 = 0,9 unused3: u5 = 0,
8 mode: u12, //: Mode10 mode: u12, //: Mode
9 };11 };
12 // I-type
10 pub const Addi = packed struct {13 pub const Addi = packed struct {
11 pub const Mode = packed enum(u3) { addi = 0b000, slti = 0b010, sltiu = 0b011, xori = 0b100, ori = 0b110, andi = 0b111 };14 pub const Mode = packed enum(u3) { addi = 0b000, slti = 0b010, sltiu = 0b011, xori = 0b100, ori = 0b110, andi = 0b111 };
12 opcode: u7 = 0b0010011,15 opcode: u7 = 0b0010011,
...@@ -20,6 +23,7 @@ pub const Instructions = struct {...@@ -20,6 +23,7 @@ pub const Instructions = struct {
20 rd: u5,23 rd: u5,
21 imm: i20,24 imm: i20,
22 };25 };
26 // I_type
23 pub const Load = packed struct {27 pub const Load = packed struct {
24 pub const Mode = packed enum(u3) { ld = 0b011, lwu = 0b110 };28 pub const Mode = packed enum(u3) { ld = 0b011, lwu = 0b110 };
25 opcode: u7 = 0b0000011,29 opcode: u7 = 0b0000011,
...@@ -28,9 +32,24 @@ pub const Instructions = struct {...@@ -28,9 +32,24 @@ pub const Instructions = struct {
28 rs1: u5,32 rs1: u5,
29 offset: i12,33 offset: i12,
30 };34 };
35 // I-type
36 pub const Jalr = packed struct {
37 opcode: u7 = 0b1100111,
38 rd: u5,
39 mode: u3 = 0,
40 rs1: u5,
41 offset: i12,
42 };
31};43};
3244
33// zig fmt: off45// zig fmt: off
46pub const RawRegister = enum(u8) {
47 x0, x1, x2, x3, x4, x5, x6, x7,
48 x8, x9, x10, x11, x12, x13, x14, x15,
49 x16, x17, x18, x19, x20, x21, x22, x23,
50 x24, x25, x26, x27, x28, x29, x30, x31,
51};
52
34pub const Register = enum(u8) {53pub const Register = enum(u8) {
35 // 64 bit registers54 // 64 bit registers
36 zero, // zero55 zero, // zero
...@@ -45,6 +64,12 @@ pub const Register = enum(u8) {...@@ -45,6 +64,12 @@ pub const Register = enum(u8) {
45 a2, a3, a4, a5, a6, a7, // fn args. caller saved.64 a2, a3, a4, a5, a6, a7, // fn args. caller saved.
46 s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, // saved registers. callee saved.65 s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, // saved registers. callee saved.
47 t3, t4, t5, t6, // caller saved66 t3, t4, t5, t6, // caller saved
67
68 pub fn parseRegName(name: []const u8) ?Register {
69 if(std.meta.stringToEnum(Register, name)) |reg| return reg;
70 if(std.meta.stringToEnum(RawRegister, name)) |rawreg| return @intToEnum(Register, @enumToInt(rawreg));
71 return null;
72 }
4873
49 /// Returns the bit-width of the register.74 /// Returns the bit-width of the register.
50 pub fn size(self: @This()) u7 {75 pub fn size(self: @This()) u7 {
...@@ -58,8 +83,7 @@ pub const Register = enum(u8) {...@@ -58,8 +83,7 @@ pub const Register = enum(u8) {
58 return self;83 return self;
59 }84 }
6085
61 /// Returns the register's id. This is used in practically every opcode the86 /// Returns the register's id.
62 /// riscv64 has.
63 pub fn id(self: @This()) u5 {87 pub fn id(self: @This()) u5 {
64 return @truncate(u5, @enumToInt(self));88 return @truncate(u5, @enumToInt(self));
65 }89 }