authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-12 13:46:49-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:22:05-07:00
logc10d1c6a75f818eda092ef7912fd3c2b996632f0
treebfaf9037294f5d140ee03facfa39ec935dfe1c08
parent083b7b483e1ad83d62ed7029822a82fff14953c5
signaturelock-open Commit is signed but in an unrecognized format.

riscv: implement more arithmetic instructions


7 files changed, 366 insertions(+), 128 deletions(-)

src/arch/riscv64/CodeGen.zig+108-26
......@@ -2075,6 +2075,7 @@ fn binOp(
20752075 .add,
20762076 .sub,
20772077 .mul,
2078 .div_float,
20782079 .cmp_eq,
20792080 .cmp_neq,
20802081 .cmp_gt,
......@@ -2086,10 +2087,11 @@ fn binOp(
20862087 switch (lhs_ty.zigTypeTag(zcu)) {
20872088 .Float => {
20882089 const float_bits = lhs_ty.floatBits(zcu.getTarget());
2089 if (float_bits <= 32) {
2090 const float_reg_bits: u32 = if (self.hasFeature(.d)) 64 else 32;
2091 if (float_bits <= float_reg_bits) {
20902092 return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty);
20912093 } else {
2092 return self.fail("TODO: binary operations for floats with bits > 32", .{});
2094 return self.fail("TODO: binary operations for floats with bits > {d}", .{float_reg_bits});
20932095 }
20942096 },
20952097 .Vector => return self.fail("TODO binary operations on vectors", .{}),
......@@ -2255,6 +2257,7 @@ fn binOpRegister(
22552257 .cmp_lte => .lte,
22562258 else => unreachable,
22572259 },
2260 .size = self.memSize(lhs_ty),
22582261 },
22592262 },
22602263 });
......@@ -2285,28 +2288,90 @@ fn binOpFloat(
22852288
22862289 const mir_tag: Mir.Inst.Tag = switch (tag) {
22872290 .add => if (float_bits == 32) .fadds else .faddd,
2288 .cmp_eq => if (float_bits == 32) .feqs else .feqd,
2291 .sub => if (float_bits == 32) .fsubs else .fsubd,
2292 .mul => if (float_bits == 32) .fmuls else .fmuld,
2293 .div_float => if (float_bits == 32) .fdivs else .fdivd,
2294
2295 .cmp_eq,
2296 .cmp_neq,
2297 .cmp_gt,
2298 .cmp_gte,
2299 .cmp_lt,
2300 .cmp_lte,
2301 => .pseudo,
2302
22892303 else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}),
22902304 };
22912305
22922306 const return_class: abi.RegisterClass = switch (tag) {
2293 .add => .float,
2294 .cmp_eq => .int,
2307 .add,
2308 .sub,
2309 .mul,
2310 .div_float,
2311 => .float,
2312
2313 .cmp_eq,
2314 .cmp_neq,
2315 .cmp_gt,
2316 .cmp_gte,
2317 .cmp_lt,
2318 .cmp_lte,
2319 => .int,
22952320 else => unreachable,
22962321 };
22972322
22982323 const dest_reg, const dest_lock = try self.allocReg(return_class);
22992324 defer self.register_manager.unlockReg(dest_lock);
23002325
2301 _ = try self.addInst(.{
2302 .tag = mir_tag,
2303 .ops = .rrr,
2304 .data = .{ .r_type = .{
2305 .rd = dest_reg,
2306 .rs1 = lhs_reg,
2307 .rs2 = rhs_reg,
2308 } },
2309 });
2326 switch (tag) {
2327 .add,
2328 .sub,
2329 .mul,
2330 .div_float,
2331 => {
2332 _ = try self.addInst(.{
2333 .tag = mir_tag,
2334 .ops = .rrr,
2335 .data = .{ .r_type = .{
2336 .rd = dest_reg,
2337 .rs1 = lhs_reg,
2338 .rs2 = rhs_reg,
2339 } },
2340 });
2341 },
2342
2343 .cmp_eq,
2344 .cmp_neq,
2345 .cmp_gt,
2346 .cmp_gte,
2347 .cmp_lt,
2348 .cmp_lte,
2349 => {
2350 _ = try self.addInst(.{
2351 .tag = .pseudo,
2352 .ops = .pseudo_compare,
2353 .data = .{
2354 .compare = .{
2355 .rd = dest_reg,
2356 .rs1 = lhs_reg,
2357 .rs2 = rhs_reg,
2358 .op = switch (tag) {
2359 .cmp_eq => .eq,
2360 .cmp_neq => .neq,
2361 .cmp_gt => .gt,
2362 .cmp_gte => .gte,
2363 .cmp_lt => .lt,
2364 .cmp_lte => .lte,
2365 else => unreachable,
2366 },
2367 .size = self.memSize(lhs_ty),
2368 },
2369 },
2370 });
2371 },
2372
2373 else => unreachable,
2374 }
23102375
23112376 return MCValue{ .register = dest_reg };
23122377}
......@@ -2360,7 +2425,27 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
23602425
23612426fn airMul(self: *Self, inst: Air.Inst.Index) !void {
23622427 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2363 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mul for {}", .{self.target.cpu.arch});
2428 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2429 const lhs = try self.resolveInst(bin_op.lhs);
2430 const rhs = try self.resolveInst(bin_op.rhs);
2431 const lhs_ty = self.typeOf(bin_op.lhs);
2432 const rhs_ty = self.typeOf(bin_op.rhs);
2433
2434 break :result try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
2435 };
2436 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2437}
2438
2439fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
2440 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2441 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2442 const lhs = try self.resolveInst(bin_op.lhs);
2443 const rhs = try self.resolveInst(bin_op.rhs);
2444 const lhs_ty = self.typeOf(bin_op.lhs);
2445 const rhs_ty = self.typeOf(bin_op.rhs);
2446
2447 break :result try self.binOp(.div_float, lhs, lhs_ty, rhs, rhs_ty);
2448 };
23642449 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
23652450}
23662451
......@@ -2672,12 +2757,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
26722757 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
26732758}
26742759
2675fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
2676 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2677 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
2678 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2679}
2680
26812760fn airRem(self: *Self, inst: Air.Inst.Index) !void {
26822761 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
26832762 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});
......@@ -3742,6 +3821,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
37423821 const arg_ty = self.typeOfIndex(inst);
37433822
37443823 const dst_mcv = try self.allocRegOrMem(inst, false);
3824
3825 log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv });
3826
37453827 try self.genCopy(arg_ty, dst_mcv, src_mcv);
37463828
37473829 try self.genArgDbgInfo(inst, src_mcv);
......@@ -4135,10 +4217,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
41354217 },
41364218 .Float => {
41374219 const float_bits = lhs_ty.floatBits(self.target.*);
4138 if (float_bits > 32) {
4139 return self.fail("TODO: airCmp float > 32 bits", .{});
4220 const float_reg_size: u32 = if (self.hasFeature(.d)) 64 else 32;
4221 if (float_bits > float_reg_size) {
4222 return self.fail("TODO: airCmp float > 64/32 bits", .{});
41404223 }
4141
41424224 break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);
41434225 },
41444226 else => unreachable,
......@@ -6141,6 +6223,8 @@ fn resolveCallingConventionValues(
61416223 };
61426224 }
61436225
6226 var param_float_reg_i: usize = 0;
6227
61446228 for (param_types, result.args) |ty, *arg| {
61456229 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
61466230 assert(cc == .Unspecified);
......@@ -6151,8 +6235,6 @@ fn resolveCallingConventionValues(
61516235 var arg_mcv: [2]MCValue = undefined;
61526236 var arg_mcv_i: usize = 0;
61536237
6154 var param_float_reg_i: usize = 0;
6155
61566238 const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);
61576239
61586240 for (classes) |class| switch (class) {
src/arch/riscv64/Encoding.zig+97-18
......@@ -111,21 +111,46 @@ pub const Mnemonic = enum {
111111 ebreak,
112112 unimp,
113113
114 // float mnemonics
114 // F extension (32-bit float)
115115 fadds,
116 faddd,
116 fsubs,
117 fmuls,
118 fdivs,
117119
118 feqs,
119 feqd,
120 fmins,
121 fmaxs,
120122
121 fld,
122 flw,
123 fsqrts,
123124
124 fsd,
125 flw,
125126 fsw,
126127
128 feqs,
129 flts,
130 fles,
131
127132 fsgnjns,
128133
134 // D extension (64-bit float)
135 faddd,
136 fsubd,
137 fmuld,
138 fdivd,
139
140 fmind,
141 fmaxd,
142
143 fsqrtd,
144
145 fld,
146 fsd,
147
148 feqd,
149 fltd,
150 fled,
151
152 fsgnjnd,
153
129154 pub fn encoding(mnem: Mnemonic) Enc {
130155 return switch (mnem) {
131156 // zig fmt: off
......@@ -163,39 +188,66 @@ pub const Mnemonic = enum {
163188 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
164189 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
165190
191 .fsubs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
192 .fsubd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
193
194 .fmuls => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
195 .fmuld => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
196
197 .fdivs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
198 .fdivd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
199
200 .fmins => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
201 .fmind => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
202
203 .fmaxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
204 .fmaxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
205
206 .fsqrts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
207 .fsqrtd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
208
209 .fles => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
210 .fled => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
211
212 .flts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
213 .fltd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
214
166215 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
167216 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
168217
169218 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
219 .fsgnjnd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
220
170221
171222 // LOAD
172223
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 } } },
178224 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
225 .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
226 .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
227 .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
179228 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
229 .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
230 .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
180231
181232
182233 // STORE
183
184 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
185 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
186 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
234
187235 .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
236 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
237 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
238 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
188239
189240
190241 // LOAD_FP
191242
192 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
193243 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
244 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
245
194246
195247 // STORE_FP
196248
197 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
198249 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
250 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
199251
200252
201253 // JALR
......@@ -310,9 +362,36 @@ pub const InstEnc = enum {
310362
311363 .fadds,
312364 .faddd,
365
366 .fsubs,
367 .fsubd,
368
369 .fmuls,
370 .fmuld,
371
372 .fdivs,
373 .fdivd,
374
375 .fmins,
376 .fmind,
377
378 .fmaxs,
379 .fmaxd,
380
381 .fsqrts,
382 .fsqrtd,
383
384 .fles,
385 .fled,
386
387 .flts,
388 .fltd,
389
313390 .feqs,
314391 .feqd,
392
315393 .fsgnjns,
394 .fsgnjnd,
316395 => .R,
317396
318397 .ecall,
src/arch/riscv64/Lower.zig+136-69
......@@ -139,7 +139,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
139139
140140 switch (dst_class) {
141141 .float => {
142 try lower.emit(.fsgnjns, &.{
142 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
143143 .{ .reg = rr.rd },
144144 .{ .reg = rr.rs },
145145 .{ .reg = rr.rs },
......@@ -176,9 +176,11 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
176176 .pseudo_load_symbol => {
177177 const payload = inst.data.payload;
178178 const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data;
179 const dst_reg: bits.Register = @enumFromInt(data.register);
180 assert(dst_reg.class() == .int);
179181
180182 try lower.emit(.lui, &.{
181 .{ .reg = @enumFromInt(data.register) },
183 .{ .reg = dst_reg },
182184 .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{
183185 .atom_index = data.atom_index,
184186 .sym_index = data.sym_index,
......@@ -187,14 +189,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
187189
188190 // the above reloc implies this one
189191 try lower.emit(.addi, &.{
190 .{ .reg = @enumFromInt(data.register) },
191 .{ .reg = @enumFromInt(data.register) },
192 .{ .reg = dst_reg },
193 .{ .reg = dst_reg },
192194 .{ .imm = Immediate.s(0) },
193195 });
194196 },
195197
196198 .pseudo_lea_rm => {
197199 const rm = inst.data.rm;
200 assert(rm.r.class() == .int);
201
198202 const frame = rm.m.toFrameLoc(lower.mir);
199203
200204 try lower.emit(.addi, &.{
......@@ -212,78 +216,135 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
212216 const rs1 = compare.rs1;
213217 const rs2 = compare.rs2;
214218
215 switch (op) {
216 .eq => {
217 try lower.emit(.xor, &.{
218 .{ .reg = rd },
219 .{ .reg = rs1 },
220 .{ .reg = rs2 },
221 });
222
223 try lower.emit(.sltiu, &.{
224 .{ .reg = rd },
225 .{ .reg = rd },
226 .{ .imm = Immediate.s(1) },
227 });
219 const class = rs1.class();
220 const size = compare.size.bitSize();
221
222 switch (class) {
223 .int => switch (op) {
224 .eq => {
225 try lower.emit(.xor, &.{
226 .{ .reg = rd },
227 .{ .reg = rs1 },
228 .{ .reg = rs2 },
229 });
230
231 try lower.emit(.sltiu, &.{
232 .{ .reg = rd },
233 .{ .reg = rd },
234 .{ .imm = Immediate.s(1) },
235 });
236 },
237 .neq => {
238 try lower.emit(.xor, &.{
239 .{ .reg = rd },
240 .{ .reg = rs1 },
241 .{ .reg = rs2 },
242 });
243
244 try lower.emit(.sltu, &.{
245 .{ .reg = rd },
246 .{ .reg = .zero },
247 .{ .reg = rd },
248 });
249 },
250 .gt => {
251 try lower.emit(.sltu, &.{
252 .{ .reg = rd },
253 .{ .reg = rs1 },
254 .{ .reg = rs2 },
255 });
256 },
257 .gte => {
258 try lower.emit(.sltu, &.{
259 .{ .reg = rd },
260 .{ .reg = rs1 },
261 .{ .reg = rs2 },
262 });
263
264 try lower.emit(.xori, &.{
265 .{ .reg = rd },
266 .{ .reg = rd },
267 .{ .imm = Immediate.s(1) },
268 });
269 },
270 .lt => {
271 try lower.emit(.slt, &.{
272 .{ .reg = rd },
273 .{ .reg = rs1 },
274 .{ .reg = rs2 },
275 });
276 },
277 .lte => {
278 try lower.emit(.slt, &.{
279 .{ .reg = rd },
280 .{ .reg = rs2 },
281 .{ .reg = rs1 },
282 });
283
284 try lower.emit(.xori, &.{
285 .{ .reg = rd },
286 .{ .reg = rd },
287 .{ .imm = Immediate.s(1) },
288 });
289 },
228290 },
229 .neq => {
230 try lower.emit(.xor, &.{
231 .{ .reg = rd },
232 .{ .reg = rs1 },
233 .{ .reg = rs2 },
234 });
235
236 try lower.emit(.sltu, &.{
237 .{ .reg = rd },
238 .{ .reg = .zero },
239 .{ .reg = rd },
240 });
241 },
242 .gt => {
243 try lower.emit(.sltu, &.{
244 .{ .reg = rd },
245 .{ .reg = rs1 },
246 .{ .reg = rs2 },
247 });
248 },
249 .gte => {
250 try lower.emit(.sltu, &.{
251 .{ .reg = rd },
252 .{ .reg = rs1 },
253 .{ .reg = rs2 },
254 });
255
256 try lower.emit(.xori, &.{
257 .{ .reg = rd },
258 .{ .reg = rd },
259 .{ .imm = Immediate.s(1) },
260 });
261 },
262 .lt => {
263 try lower.emit(.slt, &.{
264 .{ .reg = rd },
265 .{ .reg = rs1 },
266 .{ .reg = rs2 },
267 });
268 },
269 .lte => {
270 try lower.emit(.slt, &.{
271 .{ .reg = rd },
272 .{ .reg = rs2 },
273 .{ .reg = rs1 },
274 });
275
276 try lower.emit(.xori, &.{
277 .{ .reg = rd },
278 .{ .reg = rd },
279 .{ .imm = Immediate.s(1) },
280 });
291 .float => switch (op) {
292 // eq
293 .eq => {
294 try lower.emit(if (size == 64) .feqd else .feqs, &.{
295 .{ .reg = rd },
296 .{ .reg = rs1 },
297 .{ .reg = rs2 },
298 });
299 },
300 // !(eq)
301 .neq => {
302 try lower.emit(if (size == 64) .feqd else .feqs, &.{
303 .{ .reg = rd },
304 .{ .reg = rs1 },
305 .{ .reg = rs2 },
306 });
307 try lower.emit(.xori, &.{
308 .{ .reg = rd },
309 .{ .reg = rd },
310 .{ .imm = Immediate.s(1) },
311 });
312 },
313 .lt => {
314 try lower.emit(if (size == 64) .fltd else .flts, &.{
315 .{ .reg = rd },
316 .{ .reg = rs1 },
317 .{ .reg = rs2 },
318 });
319 },
320 .lte => {
321 try lower.emit(if (size == 64) .fled else .fles, &.{
322 .{ .reg = rd },
323 .{ .reg = rs1 },
324 .{ .reg = rs2 },
325 });
326 },
327 .gt => {
328 try lower.emit(if (size == 64) .fltd else .flts, &.{
329 .{ .reg = rd },
330 .{ .reg = rs2 },
331 .{ .reg = rs1 },
332 });
333 },
334 .gte => {
335 try lower.emit(if (size == 64) .fled else .fles, &.{
336 .{ .reg = rd },
337 .{ .reg = rs2 },
338 .{ .reg = rs1 },
339 });
340 },
281341 },
282342 }
283343 },
284344
285345 .pseudo_not => {
286346 const rr = inst.data.rr;
347 assert(rr.rs.class() == .int and rr.rd.class() == .int);
287348
288349 try lower.emit(.xori, &.{
289350 .{ .reg = rr.rd },
......@@ -408,6 +469,12 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
408469 return error.LowerFail;
409470}
410471
472fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool {
473 const target = lower.bin_file.comp.module.?.getTarget();
474 const features = target.cpu.features;
475 return std.Target.riscv.featureSetHas(features, feature);
476}
477
411478const Lower = @This();
412479
413480const abi = @import("abi.zig");
src/arch/riscv64/Mir.zig+25
......@@ -72,15 +72,39 @@ pub const Inst = struct {
7272
7373 // F extension (32-bit float)
7474 fadds,
75 fsubs,
76 fmuls,
77 fdivs,
78
79 fmins,
80 fmaxs,
81
82 fsqrts,
83
7584 flw,
7685 fsw,
86
7787 feqs,
88 flts,
89 fles,
7890
7991 // D extension (64-bit float)
8092 faddd,
93 fsubd,
94 fmuld,
95 fdivd,
96
97 fmind,
98 fmaxd,
99
100 fsqrtd,
101
81102 fld,
82103 fsd,
104
83105 feqd,
106 fltd,
107 fled,
84108
85109 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
86110 /// assembly instruction.
......@@ -182,6 +206,7 @@ pub const Inst = struct {
182206 lt,
183207 lte,
184208 },
209 size: Memory.Size,
185210 },
186211
187212 reloc: struct {
test/behavior/cast.zig-2
......@@ -1717,7 +1717,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
17171717 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17181718 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17191719 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1720 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17211720
17221721 const i: u8 = 100;
17231722 var f: f32 = 1.234;
......@@ -2586,7 +2585,6 @@ test "@intFromBool on vector" {
25862585
25872586test "numeric coercions with undefined" {
25882587 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
2589 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
25902588
25912589 const from: i32 = undefined;
25922590 var to: f32 = from;
test/behavior/floatop.zig-12
......@@ -22,8 +22,6 @@ test "add f16" {
2222}
2323
2424test "add f32/f64" {
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26
2725 try testAdd(f32);
2826 try comptime testAdd(f32);
2927 try testAdd(f64);
......@@ -60,8 +58,6 @@ test "sub f16" {
6058}
6159
6260test "sub f32/f64" {
63 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
64
6561 try testSub(f32);
6662 try comptime testSub(f32);
6763 try testSub(f64);
......@@ -98,8 +94,6 @@ test "mul f16" {
9894}
9995
10096test "mul f32/f64" {
101 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
102
10397 try testMul(f32);
10498 try comptime testMul(f32);
10599 try testMul(f64);
......@@ -1622,7 +1616,6 @@ test "comptime inf >= runtime 1" {
16221616test "comptime isNan(nan * 1)" {
16231617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16241618 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16261619
16271620 const nan_times_one = comptime std.math.nan(f64) * 1;
16281621 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -1630,7 +1623,6 @@ test "comptime isNan(nan * 1)" {
16301623test "runtime isNan(nan * 1)" {
16311624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16321625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16341626
16351627 const nan_times_one = std.math.nan(f64) * 1;
16361628 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -1638,7 +1630,6 @@ test "runtime isNan(nan * 1)" {
16381630test "comptime isNan(nan * 0)" {
16391631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16401632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1641 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16421633
16431634 const nan_times_zero = comptime std.math.nan(f64) * 0;
16441635 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -1648,7 +1639,6 @@ test "comptime isNan(nan * 0)" {
16481639test "runtime isNan(nan * 0)" {
16491640 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16501641 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16521642
16531643 const nan_times_zero = std.math.nan(f64) * 0;
16541644 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -1658,7 +1648,6 @@ test "runtime isNan(nan * 0)" {
16581648test "comptime isNan(inf * 0)" {
16591649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16601650 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1661 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16621651
16631652 const inf_times_zero = comptime std.math.inf(f64) * 0;
16641653 try std.testing.expect(std.math.isNan(inf_times_zero));
......@@ -1668,7 +1657,6 @@ test "comptime isNan(inf * 0)" {
16681657test "runtime isNan(inf * 0)" {
16691658 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16701659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1671 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16721660
16731661 const inf_times_zero = std.math.inf(f64) * 0;
16741662 try std.testing.expect(std.math.isNan(inf_times_zero));
test/behavior/math.zig-1
......@@ -236,7 +236,6 @@ test "float equality" {
236236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
237237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
240239
241240 const x: f64 = 0.012;
242241 const y: f64 = x + 1.0;