authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:04:18-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:21:39-07:00
logb2cb090c3790dd10a784f9e291230cf6052b514c
treeea100c2fcb20b1b8f73856bc01f25fdbc1a07c13
parent031d8248e02f019a4c689dfa2913b30ec796dfa5
signaturelock-open Commit is signed but in an unrecognized format.

riscv: float args


6 files changed, 116 insertions(+), 65 deletions(-)

src/arch/riscv64/CodeGen.zig+22-9
......@@ -5226,13 +5226,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
52265226
52275227 const src_reg_class = src_reg.class();
52285228
5229 if (src_reg_class == .float) {
5230 if (dst_reg_class == .float) {
5231 return self.fail("TODO: genSetReg float -> float", .{});
5232 }
5233
5234 assert(dst_reg_class == .int); // a bit of future proofing
5235
5229 if (src_reg_class == .float and dst_reg_class == .int) {
52365230 // to move from float -> int, we use FMV.X.W
52375231 return self.fail("TODO: genSetReg float -> int", .{});
52385232 }
......@@ -6031,6 +6025,7 @@ fn resolveCallingConventionValues(
60316025 } else {
60326026 var ret_tracking: [2]InstTracking = undefined;
60336027 var ret_tracking_i: usize = 0;
6028 var ret_float_reg_i: usize = 0;
60346029
60356030 const classes = mem.sliceTo(&abi.classifySystem(ret_ty, zcu), .none);
60366031
......@@ -6042,6 +6037,13 @@ fn resolveCallingConventionValues(
60426037 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
60436038 ret_tracking_i += 1;
60446039 },
6040 .float => {
6041 const ret_float_reg = abi.Registers.Float.function_ret_regs[ret_float_reg_i];
6042 ret_float_reg_i += 1;
6043
6044 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_float_reg });
6045 ret_tracking_i += 1;
6046 },
60456047 .memory => {
60466048 const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
60476049 ret_int_reg_i += 1;
......@@ -6076,6 +6078,8 @@ fn resolveCallingConventionValues(
60766078 var arg_mcv: [2]MCValue = undefined;
60776079 var arg_mcv_i: usize = 0;
60786080
6081 var param_float_reg_i: usize = 0;
6082
60796083 const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);
60806084
60816085 for (classes) |class| switch (class) {
......@@ -6089,6 +6093,16 @@ fn resolveCallingConventionValues(
60896093 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
60906094 arg_mcv_i += 1;
60916095 },
6096 .float => {
6097 const param_float_regs = abi.Registers.Float.function_arg_regs;
6098 if (param_float_reg_i >= param_float_regs.len) break;
6099
6100 const param_float_reg = param_float_regs[param_float_reg_i];
6101 param_float_reg_i += 1;
6102
6103 arg_mcv[arg_mcv_i] = .{ .register = param_float_reg };
6104 arg_mcv_i += 1;
6105 },
60926106 .memory => {
60936107 const param_int_regs = abi.Registers.Integer.function_arg_regs;
60946108
......@@ -6118,9 +6132,8 @@ fn resolveCallingConventionValues(
61186132 return result;
61196133}
61206134
6121/// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
61226135fn wantSafety(self: *Self) bool {
6123 return switch (self.bin_file.comp.root_mod.optimize_mode) {
6136 return switch (self.mod.optimize_mode) {
61246137 .Debug => true,
61256138 .ReleaseSafe => true,
61266139 .ReleaseFast => false,
src/arch/riscv64/Encoding.zig+48-43
......@@ -124,115 +124,119 @@ pub const Mnemonic = enum {
124124 fsd,
125125 fsw,
126126
127 fsgnjns,
128
127129 pub fn encoding(mnem: Mnemonic) Enc {
128130 return switch (mnem) {
129131 // zig fmt: off
130132
131133 // OP
132134
133 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
134 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
135 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
136 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
135137
136 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
137 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
138 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
138 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
139 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
140 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
139141
140 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
141 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
142 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
143 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
142144
143 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
145 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
144146
145147
146148 // OP_IMM
147149
148 .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
149 .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
150 .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
150 .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
151 .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
152 .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
151153
152 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
154 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
153155
154 .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
155 .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
156 .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
156 .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
157 .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
158 .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
157159
158160
159161 // OP_FP
160162
161 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
162 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
163 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
164 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
165
166 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
167 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
163168
164 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
165 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
169 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
166170
167171 // LOAD
168172
169 .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
170 .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
171 .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
172 .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
173 .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
174 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
175 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
173 .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
174 .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
175 .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
176 .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
177 .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
178 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
179 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
176180
177181
178182 // STORE
179183
180 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
181 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
182 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
183 .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
184 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
185 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
186 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
187 .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
184188
185189
186190 // LOAD_FP
187191
188 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
189 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
192 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
193 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
190194
191195 // STORE_FP
192196
193 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
194 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
197 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
198 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
195199
196200
197201 // JALR
198202
199 .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
203 .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
200204
201205
202206 // OP_32
203207
204 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
208 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
205209
206210
207211 // LUI
208212
209 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
213 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
210214
211215
212216 // AUIPC
213217
214 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
218 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
215219
216220
217221 // JAL
218222
219 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
223 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
220224
221225
222226 // BRANCH
223227
224 .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
228 .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
225229
226230
227231 // SYSTEM
228232
229 .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
230 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
233 .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
234 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
231235
232236
233237 // NONE
234238
235 .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
239 .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
236240
237241
238242 // zig fmt: on
......@@ -308,6 +312,7 @@ pub const InstEnc = enum {
308312 .faddd,
309313 .feqs,
310314 .feqd,
315 .fsgnjns,
311316 => .R,
312317
313318 .ecall,
src/arch/riscv64/Lower.zig+21-5
......@@ -132,11 +132,27 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
132132 .pseudo_mv => {
133133 const rr = inst.data.rr;
134134
135 try lower.emit(.addi, &.{
136 .{ .reg = rr.rd },
137 .{ .reg = rr.rs },
138 .{ .imm = Immediate.s(0) },
139 });
135 const dst_class = rr.rd.class();
136 const src_class = rr.rs.class();
137
138 assert(dst_class == src_class);
139
140 switch (dst_class) {
141 .float => {
142 try lower.emit(.fsgnjns, &.{
143 .{ .reg = rr.rd },
144 .{ .reg = rr.rs },
145 .{ .reg = rr.rs },
146 });
147 },
148 .int => {
149 try lower.emit(.addi, &.{
150 .{ .reg = rr.rd },
151 .{ .reg = rr.rs },
152 .{ .imm = Immediate.s(0) },
153 });
154 },
155 }
140156 },
141157
142158 .pseudo_ret => {
src/arch/riscv64/abi.zig+18-4
......@@ -7,7 +7,7 @@ const InternPool = @import("../../InternPool.zig");
77const Module = @import("../../Module.zig");
88const assert = std.debug.assert;
99
10pub const Class = enum { memory, byval, integer, double_integer, fields, none };
10pub const Class = enum { memory, byval, integer, double_integer, fields };
1111
1212pub fn classifyType(ty: Type, mod: *Module) Class {
1313 const target = mod.getTarget();
......@@ -93,11 +93,13 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
9393 }
9494}
9595
96pub const SystemClass = enum { integer, float, memory, none };
97
9698/// There are a maximum of 8 possible return slots. Returned values are in
9799/// the beginning of the array; unused slots are filled with .none.
98pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
99 var result = [1]Class{.none} ** 8;
100 const memory_class = [_]Class{
100pub fn classifySystem(ty: Type, zcu: *Module) [8]SystemClass {
101 var result = [1]SystemClass{.none} ** 8;
102 const memory_class = [_]SystemClass{
101103 .memory, .none, .none, .none,
102104 .none, .none, .none, .none,
103105 };
......@@ -139,6 +141,18 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
139141 }
140142 unreachable; // support > 128 bit int arguments
141143 },
144 .Float => {
145 const target = zcu.getTarget();
146 const features = target.cpu.features;
147
148 const float_bits = ty.floatBits(zcu.getTarget());
149 const float_reg_size: u32 = if (std.Target.riscv.featureSetHas(features, .d)) 64 else 32;
150 if (float_bits <= float_reg_size) {
151 result[0] = .float;
152 return result;
153 }
154 unreachable; // support split float args
155 },
142156 .ErrorUnion => {
143157 const payload_ty = ty.errorUnionPayload(zcu);
144158 const payload_bits = payload_ty.bitSize(zcu);
src/arch/riscv64/bits.zig+7-2
......@@ -2,6 +2,9 @@ const std = @import("std");
22const DW = std.dwarf;
33const assert = std.debug.assert;
44const testing = std.testing;
5const Target = std.Target;
6
7const Module = @import("../../Module.zig");
58const Encoding = @import("Encoding.zig");
69const Mir = @import("Mir.zig");
710const abi = @import("abi.zig");
......@@ -227,11 +230,13 @@ pub const Register = enum(u8) {
227230 return @as(u8, reg.id());
228231 }
229232
230 pub fn bitSize(reg: Register) u32 {
233 pub fn bitSize(reg: Register, zcu: Module) u32 {
234 const features = zcu.getTarget().cpu.features;
235
231236 return switch (@intFromEnum(reg)) {
232237 // zig fmt: off
233238 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
234 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => 32,
239 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
235240 else => unreachable,
236241 // zig fmt: on
237242 };
src/codegen/llvm.zig-2
......@@ -11148,7 +11148,6 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
1114811148 }
1114911149 return o.builder.structType(.normal, types[0..types_len]);
1115011150 },
11151 .none => unreachable,
1115211151 }
1115311152 },
1115411153 // TODO investigate C ABI for other architectures
......@@ -11406,7 +11405,6 @@ const ParamTypeIterator = struct {
1140611405 it.llvm_index += it.types_len - 1;
1140711406 return .multiple_llvm_types;
1140811407 },
11409 .none => unreachable,
1141011408 }
1141111409 },
1141211410 // TODO investigate C ABI for other architectures