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(...@@ -2075,6 +2075,7 @@ fn binOp(
2075 .add,2075 .add,
2076 .sub,2076 .sub,
2077 .mul,2077 .mul,
2078 .div_float,
2078 .cmp_eq,2079 .cmp_eq,
2079 .cmp_neq,2080 .cmp_neq,
2080 .cmp_gt,2081 .cmp_gt,
...@@ -2086,10 +2087,11 @@ fn binOp(...@@ -2086,10 +2087,11 @@ fn binOp(
2086 switch (lhs_ty.zigTypeTag(zcu)) {2087 switch (lhs_ty.zigTypeTag(zcu)) {
2087 .Float => {2088 .Float => {
2088 const float_bits = lhs_ty.floatBits(zcu.getTarget());2089 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) {
2090 return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty);2092 return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty);
2091 } else {2093 } 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});
2093 }2095 }
2094 },2096 },
2095 .Vector => return self.fail("TODO binary operations on vectors", .{}),2097 .Vector => return self.fail("TODO binary operations on vectors", .{}),
...@@ -2255,6 +2257,7 @@ fn binOpRegister(...@@ -2255,6 +2257,7 @@ fn binOpRegister(
2255 .cmp_lte => .lte,2257 .cmp_lte => .lte,
2256 else => unreachable,2258 else => unreachable,
2257 },2259 },
2260 .size = self.memSize(lhs_ty),
2258 },2261 },
2259 },2262 },
2260 });2263 });
...@@ -2285,28 +2288,90 @@ fn binOpFloat(...@@ -2285,28 +2288,90 @@ fn binOpFloat(
22852288
2286 const mir_tag: Mir.Inst.Tag = switch (tag) {2289 const mir_tag: Mir.Inst.Tag = switch (tag) {
2287 .add => if (float_bits == 32) .fadds else .faddd,2290 .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
2289 else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}),2303 else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}),
2290 };2304 };
22912305
2292 const return_class: abi.RegisterClass = switch (tag) {2306 const return_class: abi.RegisterClass = switch (tag) {
2293 .add => .float,2307 .add,
2294 .cmp_eq => .int,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,
2295 else => unreachable,2320 else => unreachable,
2296 };2321 };
22972322
2298 const dest_reg, const dest_lock = try self.allocReg(return_class);2323 const dest_reg, const dest_lock = try self.allocReg(return_class);
2299 defer self.register_manager.unlockReg(dest_lock);2324 defer self.register_manager.unlockReg(dest_lock);
23002325
2301 _ = try self.addInst(.{2326 switch (tag) {
2302 .tag = mir_tag,2327 .add,
2303 .ops = .rrr,2328 .sub,
2304 .data = .{ .r_type = .{2329 .mul,
2305 .rd = dest_reg,2330 .div_float,
2306 .rs1 = lhs_reg,2331 => {
2307 .rs2 = rhs_reg,2332 _ = try self.addInst(.{
2308 } },2333 .tag = mir_tag,
2309 });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
2311 return MCValue{ .register = dest_reg };2376 return MCValue{ .register = dest_reg };
2312}2377}
...@@ -2360,7 +2425,27 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2360,7 +2425,27 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
23602425
2361fn airMul(self: *Self, inst: Air.Inst.Index) !void {2426fn airMul(self: *Self, inst: Air.Inst.Index) !void {
2362 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2427 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 };
2364 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2449 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2365}2450}
23662451
...@@ -2672,12 +2757,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2672,12 +2757,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2672 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});2757 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
2673}2758}
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
2681fn airRem(self: *Self, inst: Air.Inst.Index) !void {2760fn airRem(self: *Self, inst: Air.Inst.Index) !void {
2682 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2761 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2683 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});2762 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 {...@@ -3742,6 +3821,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3742 const arg_ty = self.typeOfIndex(inst);3821 const arg_ty = self.typeOfIndex(inst);
37433822
3744 const dst_mcv = try self.allocRegOrMem(inst, false);3823 const dst_mcv = try self.allocRegOrMem(inst, false);
3824
3825 log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv });
3826
3745 try self.genCopy(arg_ty, dst_mcv, src_mcv);3827 try self.genCopy(arg_ty, dst_mcv, src_mcv);
37463828
3747 try self.genArgDbgInfo(inst, src_mcv);3829 try self.genArgDbgInfo(inst, src_mcv);
...@@ -4135,10 +4217,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {...@@ -4135,10 +4217,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
4135 },4217 },
4136 .Float => {4218 .Float => {
4137 const float_bits = lhs_ty.floatBits(self.target.*);4219 const float_bits = lhs_ty.floatBits(self.target.*);
4138 if (float_bits > 32) {4220 const float_reg_size: u32 = if (self.hasFeature(.d)) 64 else 32;
4139 return self.fail("TODO: airCmp float > 32 bits", .{});4221 if (float_bits > float_reg_size) {
4222 return self.fail("TODO: airCmp float > 64/32 bits", .{});
4140 }4223 }
4141
4142 break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);4224 break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);
4143 },4225 },
4144 else => unreachable,4226 else => unreachable,
...@@ -6141,6 +6223,8 @@ fn resolveCallingConventionValues(...@@ -6141,6 +6223,8 @@ fn resolveCallingConventionValues(
6141 };6223 };
6142 }6224 }
61436225
6226 var param_float_reg_i: usize = 0;
6227
6144 for (param_types, result.args) |ty, *arg| {6228 for (param_types, result.args) |ty, *arg| {
6145 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {6229 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
6146 assert(cc == .Unspecified);6230 assert(cc == .Unspecified);
...@@ -6151,8 +6235,6 @@ fn resolveCallingConventionValues(...@@ -6151,8 +6235,6 @@ fn resolveCallingConventionValues(
6151 var arg_mcv: [2]MCValue = undefined;6235 var arg_mcv: [2]MCValue = undefined;
6152 var arg_mcv_i: usize = 0;6236 var arg_mcv_i: usize = 0;
61536237
6154 var param_float_reg_i: usize = 0;
6155
6156 const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);6238 const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);
61576239
6158 for (classes) |class| switch (class) {6240 for (classes) |class| switch (class) {
src/arch/riscv64/Encoding.zig+97-18
...@@ -111,21 +111,46 @@ pub const Mnemonic = enum {...@@ -111,21 +111,46 @@ pub const Mnemonic = enum {
111 ebreak,111 ebreak,
112 unimp,112 unimp,
113113
114 // float mnemonics114 // F extension (32-bit float)
115 fadds,115 fadds,
116 faddd,116 fsubs,
117 fmuls,
118 fdivs,
117119
118 feqs,120 fmins,
119 feqd,121 fmaxs,
120122
121 fld,123 fsqrts,
122 flw,
123124
124 fsd,125 flw,
125 fsw,126 fsw,
126127
128 feqs,
129 flts,
130 fles,
131
127 fsgnjns,132 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
129 pub fn encoding(mnem: Mnemonic) Enc {154 pub fn encoding(mnem: Mnemonic) Enc {
130 return switch (mnem) {155 return switch (mnem) {
131 // zig fmt: off156 // zig fmt: off
...@@ -163,39 +188,66 @@ pub const Mnemonic = enum {...@@ -163,39 +188,66 @@ pub const Mnemonic = enum {
163 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },188 .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 } } },189 .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
166 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },215 .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 } } },216 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
168217
169 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },218 .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
171 // LOAD222 // 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 } } },
178 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },224 .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 } } },
179 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },228 .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
182 // STORE233 // STORE
183234
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 } } },235 .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
190 // LOAD_FP241 // LOAD_FP
191242
192 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
193 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },243 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
244 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
245
194246
195 // STORE_FP247 // STORE_FP
196248
197 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
198 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },249 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
250 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
199251
200252
201 // JALR253 // JALR
...@@ -310,9 +362,36 @@ pub const InstEnc = enum {...@@ -310,9 +362,36 @@ pub const InstEnc = enum {
310362
311 .fadds,363 .fadds,
312 .faddd,364 .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
313 .feqs,390 .feqs,
314 .feqd,391 .feqd,
392
315 .fsgnjns,393 .fsgnjns,
394 .fsgnjnd,
316 => .R,395 => .R,
317396
318 .ecall,397 .ecall,
src/arch/riscv64/Lower.zig+136-69
...@@ -139,7 +139,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -139,7 +139,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
139139
140 switch (dst_class) {140 switch (dst_class) {
141 .float => {141 .float => {
142 try lower.emit(.fsgnjns, &.{142 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
143 .{ .reg = rr.rd },143 .{ .reg = rr.rd },
144 .{ .reg = rr.rs },144 .{ .reg = rr.rs },
145 .{ .reg = rr.rs },145 .{ .reg = rr.rs },
...@@ -176,9 +176,11 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -176,9 +176,11 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
176 .pseudo_load_symbol => {176 .pseudo_load_symbol => {
177 const payload = inst.data.payload;177 const payload = inst.data.payload;
178 const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data;178 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
180 try lower.emit(.lui, &.{182 try lower.emit(.lui, &.{
181 .{ .reg = @enumFromInt(data.register) },183 .{ .reg = dst_reg },
182 .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{184 .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{
183 .atom_index = data.atom_index,185 .atom_index = data.atom_index,
184 .sym_index = data.sym_index,186 .sym_index = data.sym_index,
...@@ -187,14 +189,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -187,14 +189,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
187189
188 // the above reloc implies this one190 // the above reloc implies this one
189 try lower.emit(.addi, &.{191 try lower.emit(.addi, &.{
190 .{ .reg = @enumFromInt(data.register) },192 .{ .reg = dst_reg },
191 .{ .reg = @enumFromInt(data.register) },193 .{ .reg = dst_reg },
192 .{ .imm = Immediate.s(0) },194 .{ .imm = Immediate.s(0) },
193 });195 });
194 },196 },
195197
196 .pseudo_lea_rm => {198 .pseudo_lea_rm => {
197 const rm = inst.data.rm;199 const rm = inst.data.rm;
200 assert(rm.r.class() == .int);
201
198 const frame = rm.m.toFrameLoc(lower.mir);202 const frame = rm.m.toFrameLoc(lower.mir);
199203
200 try lower.emit(.addi, &.{204 try lower.emit(.addi, &.{
...@@ -212,78 +216,135 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -212,78 +216,135 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
212 const rs1 = compare.rs1;216 const rs1 = compare.rs1;
213 const rs2 = compare.rs2;217 const rs2 = compare.rs2;
214218
215 switch (op) {219 const class = rs1.class();
216 .eq => {220 const size = compare.size.bitSize();
217 try lower.emit(.xor, &.{221
218 .{ .reg = rd },222 switch (class) {
219 .{ .reg = rs1 },223 .int => switch (op) {
220 .{ .reg = rs2 },224 .eq => {
221 });225 try lower.emit(.xor, &.{
222226 .{ .reg = rd },
223 try lower.emit(.sltiu, &.{227 .{ .reg = rs1 },
224 .{ .reg = rd },228 .{ .reg = rs2 },
225 .{ .reg = rd },229 });
226 .{ .imm = Immediate.s(1) },230
227 });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 },
228 },290 },
229 .neq => {291 .float => switch (op) {
230 try lower.emit(.xor, &.{292 // eq
231 .{ .reg = rd },293 .eq => {
232 .{ .reg = rs1 },294 try lower.emit(if (size == 64) .feqd else .feqs, &.{
233 .{ .reg = rs2 },295 .{ .reg = rd },
234 });296 .{ .reg = rs1 },
235297 .{ .reg = rs2 },
236 try lower.emit(.sltu, &.{298 });
237 .{ .reg = rd },299 },
238 .{ .reg = .zero },300 // !(eq)
239 .{ .reg = rd },301 .neq => {
240 });302 try lower.emit(if (size == 64) .feqd else .feqs, &.{
241 },303 .{ .reg = rd },
242 .gt => {304 .{ .reg = rs1 },
243 try lower.emit(.sltu, &.{305 .{ .reg = rs2 },
244 .{ .reg = rd },306 });
245 .{ .reg = rs1 },307 try lower.emit(.xori, &.{
246 .{ .reg = rs2 },308 .{ .reg = rd },
247 });309 .{ .reg = rd },
248 },310 .{ .imm = Immediate.s(1) },
249 .gte => {311 });
250 try lower.emit(.sltu, &.{312 },
251 .{ .reg = rd },313 .lt => {
252 .{ .reg = rs1 },314 try lower.emit(if (size == 64) .fltd else .flts, &.{
253 .{ .reg = rs2 },315 .{ .reg = rd },
254 });316 .{ .reg = rs1 },
255317 .{ .reg = rs2 },
256 try lower.emit(.xori, &.{318 });
257 .{ .reg = rd },319 },
258 .{ .reg = rd },320 .lte => {
259 .{ .imm = Immediate.s(1) },321 try lower.emit(if (size == 64) .fled else .fles, &.{
260 });322 .{ .reg = rd },
261 },323 .{ .reg = rs1 },
262 .lt => {324 .{ .reg = rs2 },
263 try lower.emit(.slt, &.{325 });
264 .{ .reg = rd },326 },
265 .{ .reg = rs1 },327 .gt => {
266 .{ .reg = rs2 },328 try lower.emit(if (size == 64) .fltd else .flts, &.{
267 });329 .{ .reg = rd },
268 },330 .{ .reg = rs2 },
269 .lte => {331 .{ .reg = rs1 },
270 try lower.emit(.slt, &.{332 });
271 .{ .reg = rd },333 },
272 .{ .reg = rs2 },334 .gte => {
273 .{ .reg = rs1 },335 try lower.emit(if (size == 64) .fled else .fles, &.{
274 });336 .{ .reg = rd },
275337 .{ .reg = rs2 },
276 try lower.emit(.xori, &.{338 .{ .reg = rs1 },
277 .{ .reg = rd },339 });
278 .{ .reg = rd },340 },
279 .{ .imm = Immediate.s(1) },
280 });
281 },341 },
282 }342 }
283 },343 },
284344
285 .pseudo_not => {345 .pseudo_not => {
286 const rr = inst.data.rr;346 const rr = inst.data.rr;
347 assert(rr.rs.class() == .int and rr.rd.class() == .int);
287348
288 try lower.emit(.xori, &.{349 try lower.emit(.xori, &.{
289 .{ .reg = rr.rd },350 .{ .reg = rr.rd },
...@@ -408,6 +469,12 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {...@@ -408,6 +469,12 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
408 return error.LowerFail;469 return error.LowerFail;
409}470}
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
411const Lower = @This();478const Lower = @This();
412479
413const abi = @import("abi.zig");480const abi = @import("abi.zig");
src/arch/riscv64/Mir.zig+25
...@@ -72,15 +72,39 @@ pub const Inst = struct {...@@ -72,15 +72,39 @@ pub const Inst = struct {
7272
73 // F extension (32-bit float)73 // F extension (32-bit float)
74 fadds,74 fadds,
75 fsubs,
76 fmuls,
77 fdivs,
78
79 fmins,
80 fmaxs,
81
82 fsqrts,
83
75 flw,84 flw,
76 fsw,85 fsw,
86
77 feqs,87 feqs,
88 flts,
89 fles,
7890
79 // D extension (64-bit float)91 // D extension (64-bit float)
80 faddd,92 faddd,
93 fsubd,
94 fmuld,
95 fdivd,
96
97 fmind,
98 fmaxd,
99
100 fsqrtd,
101
81 fld,102 fld,
82 fsd,103 fsd,
104
83 feqd,105 feqd,
106 fltd,
107 fled,
84108
85 /// A pseudo-instruction. Used for anything that isn't 1:1 with an109 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
86 /// assembly instruction.110 /// assembly instruction.
...@@ -182,6 +206,7 @@ pub const Inst = struct {...@@ -182,6 +206,7 @@ pub const Inst = struct {
182 lt,206 lt,
183 lte,207 lte,
184 },208 },
209 size: Memory.Size,
185 },210 },
186211
187 reloc: struct {212 reloc: struct {
test/behavior/cast.zig-2
...@@ -1717,7 +1717,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" {...@@ -1717,7 +1717,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
1717 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1717 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1718 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1718 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1719 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1719 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
1722 const i: u8 = 100;1721 const i: u8 = 100;
1723 var f: f32 = 1.234;1722 var f: f32 = 1.234;
...@@ -2586,7 +2585,6 @@ test "@intFromBool on vector" {...@@ -2586,7 +2585,6 @@ test "@intFromBool on vector" {
25862585
2587test "numeric coercions with undefined" {2586test "numeric coercions with undefined" {
2588 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;2587 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
2591 const from: i32 = undefined;2589 const from: i32 = undefined;
2592 var to: f32 = from;2590 var to: f32 = from;
test/behavior/floatop.zig-12
...@@ -22,8 +22,6 @@ test "add f16" {...@@ -22,8 +22,6 @@ test "add f16" {
22}22}
2323
24test "add f32/f64" {24test "add f32/f64" {
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26
27 try testAdd(f32);25 try testAdd(f32);
28 try comptime testAdd(f32);26 try comptime testAdd(f32);
29 try testAdd(f64);27 try testAdd(f64);
...@@ -60,8 +58,6 @@ test "sub f16" {...@@ -60,8 +58,6 @@ test "sub f16" {
60}58}
6159
62test "sub f32/f64" {60test "sub f32/f64" {
63 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
64
65 try testSub(f32);61 try testSub(f32);
66 try comptime testSub(f32);62 try comptime testSub(f32);
67 try testSub(f64);63 try testSub(f64);
...@@ -98,8 +94,6 @@ test "mul f16" {...@@ -98,8 +94,6 @@ test "mul f16" {
98}94}
9995
100test "mul f32/f64" {96test "mul f32/f64" {
101 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
102
103 try testMul(f32);97 try testMul(f32);
104 try comptime testMul(f32);98 try comptime testMul(f32);
105 try testMul(f64);99 try testMul(f64);
...@@ -1622,7 +1616,6 @@ test "comptime inf >= runtime 1" {...@@ -1622,7 +1616,6 @@ test "comptime inf >= runtime 1" {
1622test "comptime isNan(nan * 1)" {1616test "comptime isNan(nan * 1)" {
1623 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1618 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16261619
1627 const nan_times_one = comptime std.math.nan(f64) * 1;1620 const nan_times_one = comptime std.math.nan(f64) * 1;
1628 try std.testing.expect(std.math.isNan(nan_times_one));1621 try std.testing.expect(std.math.isNan(nan_times_one));
...@@ -1630,7 +1623,6 @@ test "comptime isNan(nan * 1)" {...@@ -1630,7 +1623,6 @@ test "comptime isNan(nan * 1)" {
1630test "runtime isNan(nan * 1)" {1623test "runtime isNan(nan * 1)" {
1631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16341626
1635 const nan_times_one = std.math.nan(f64) * 1;1627 const nan_times_one = std.math.nan(f64) * 1;
1636 try std.testing.expect(std.math.isNan(nan_times_one));1628 try std.testing.expect(std.math.isNan(nan_times_one));
...@@ -1638,7 +1630,6 @@ test "runtime isNan(nan * 1)" {...@@ -1638,7 +1630,6 @@ test "runtime isNan(nan * 1)" {
1638test "comptime isNan(nan * 0)" {1630test "comptime isNan(nan * 0)" {
1639 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1641 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16421633
1643 const nan_times_zero = comptime std.math.nan(f64) * 0;1634 const nan_times_zero = comptime std.math.nan(f64) * 0;
1644 try std.testing.expect(std.math.isNan(nan_times_zero));1635 try std.testing.expect(std.math.isNan(nan_times_zero));
...@@ -1648,7 +1639,6 @@ test "comptime isNan(nan * 0)" {...@@ -1648,7 +1639,6 @@ test "comptime isNan(nan * 0)" {
1648test "runtime isNan(nan * 0)" {1639test "runtime isNan(nan * 0)" {
1649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1640 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1650 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1641 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16521642
1653 const nan_times_zero = std.math.nan(f64) * 0;1643 const nan_times_zero = std.math.nan(f64) * 0;
1654 try std.testing.expect(std.math.isNan(nan_times_zero));1644 try std.testing.expect(std.math.isNan(nan_times_zero));
...@@ -1658,7 +1648,6 @@ test "runtime isNan(nan * 0)" {...@@ -1658,7 +1648,6 @@ test "runtime isNan(nan * 0)" {
1658test "comptime isNan(inf * 0)" {1648test "comptime isNan(inf * 0)" {
1659 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1660 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1650 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1661 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16621651
1663 const inf_times_zero = comptime std.math.inf(f64) * 0;1652 const inf_times_zero = comptime std.math.inf(f64) * 0;
1664 try std.testing.expect(std.math.isNan(inf_times_zero));1653 try std.testing.expect(std.math.isNan(inf_times_zero));
...@@ -1668,7 +1657,6 @@ test "comptime isNan(inf * 0)" {...@@ -1668,7 +1657,6 @@ test "comptime isNan(inf * 0)" {
1668test "runtime isNan(inf * 0)" {1657test "runtime isNan(inf * 0)" {
1669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1658 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1670 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1671 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16721660
1673 const inf_times_zero = std.math.inf(f64) * 0;1661 const inf_times_zero = std.math.inf(f64) * 0;
1674 try std.testing.expect(std.math.isNan(inf_times_zero));1662 try std.testing.expect(std.math.isNan(inf_times_zero));
test/behavior/math.zig-1
...@@ -236,7 +236,6 @@ test "float equality" {...@@ -236,7 +236,6 @@ test "float equality" {
236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
240239
241 const x: f64 = 0.012;240 const x: f64 = 0.012;
242 const y: f64 = x + 1.0;241 const y: f64 = x + 1.0;