| author | |
| committer | |
| log | c10d1c6a75f818eda092ef7912fd3c2b996632f0 |
| tree | bfaf9037294f5d140ee03facfa39ec935dfe1c08 |
| parent | 083b7b483e1ad83d62ed7029822a82fff14953c5 |
| signature |
7 files changed, 366 insertions(+), 128 deletions(-)
src/arch/riscv64/CodeGen.zig+108-26| ... | ... | @@ -2075,6 +2075,7 @@ fn binOp( |
| 2075 | 2075 | .add, |
| 2076 | 2076 | .sub, |
| 2077 | 2077 | .mul, |
| 2078 | .div_float, | |
| 2078 | 2079 | .cmp_eq, |
| 2079 | 2080 | .cmp_neq, |
| 2080 | 2081 | .cmp_gt, |
| ... | ... | @@ -2086,10 +2087,11 @@ fn binOp( |
| 2086 | 2087 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2087 | 2088 | .Float => { |
| 2088 | 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 | 2092 | return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty); |
| 2091 | 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 | 2097 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | ... | @@ -2255,6 +2257,7 @@ fn binOpRegister( |
| 2255 | 2257 | .cmp_lte => .lte, |
| 2256 | 2258 | else => unreachable, |
| 2257 | 2259 | }, |
| 2260 | .size = self.memSize(lhs_ty), | |
| 2258 | 2261 | }, |
| 2259 | 2262 | }, |
| 2260 | 2263 | }); |
| ... | ... | @@ -2285,28 +2288,90 @@ fn binOpFloat( |
| 2285 | 2288 | |
| 2286 | 2289 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2287 | 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 | 2303 | else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}), |
| 2290 | 2304 | }; |
| 2291 | 2305 | |
| 2292 | 2306 | 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, | |
| 2295 | 2320 | else => unreachable, |
| 2296 | 2321 | }; |
| 2297 | 2322 | |
| 2298 | 2323 | const dest_reg, const dest_lock = try self.allocReg(return_class); |
| 2299 | 2324 | defer self.register_manager.unlockReg(dest_lock); |
| 2300 | 2325 | |
| 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 | } | |
| 2310 | 2375 | |
| 2311 | 2376 | return MCValue{ .register = dest_reg }; |
| 2312 | 2377 | } |
| ... | ... | @@ -2360,7 +2425,27 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2360 | 2425 | |
| 2361 | 2426 | fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 2362 | 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 | ||
| 2439 | fn 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 | 2449 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2365 | 2450 | } |
| 2366 | 2451 | |
| ... | ... | @@ -2672,12 +2757,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2672 | 2757 | return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch}); |
| 2673 | 2758 | } |
| 2674 | 2759 | |
| 2675 | fn 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 | ||
| 2681 | 2760 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 2682 | 2761 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2683 | 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 | 3821 | const arg_ty = self.typeOfIndex(inst); |
| 3743 | 3822 | |
| 3744 | 3823 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 3824 | ||
| 3825 | log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv }); | |
| 3826 | ||
| 3745 | 3827 | try self.genCopy(arg_ty, dst_mcv, src_mcv); |
| 3746 | 3828 | |
| 3747 | 3829 | try self.genArgDbgInfo(inst, src_mcv); |
| ... | ... | @@ -4135,10 +4217,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void { |
| 4135 | 4217 | }, |
| 4136 | 4218 | .Float => { |
| 4137 | 4219 | 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", .{}); | |
| 4140 | 4223 | } |
| 4141 | ||
| 4142 | 4224 | break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty); |
| 4143 | 4225 | }, |
| 4144 | 4226 | else => unreachable, |
| ... | ... | @@ -6141,6 +6223,8 @@ fn resolveCallingConventionValues( |
| 6141 | 6223 | }; |
| 6142 | 6224 | } |
| 6143 | 6225 | |
| 6226 | var param_float_reg_i: usize = 0; | |
| 6227 | ||
| 6144 | 6228 | for (param_types, result.args) |ty, *arg| { |
| 6145 | 6229 | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 6146 | 6230 | assert(cc == .Unspecified); |
| ... | ... | @@ -6151,8 +6235,6 @@ fn resolveCallingConventionValues( |
| 6151 | 6235 | var arg_mcv: [2]MCValue = undefined; |
| 6152 | 6236 | var arg_mcv_i: usize = 0; |
| 6153 | 6237 | |
| 6154 | var param_float_reg_i: usize = 0; | |
| 6155 | ||
| 6156 | 6238 | const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none); |
| 6157 | 6239 | |
| 6158 | 6240 | for (classes) |class| switch (class) { |
src/arch/riscv64/Encoding.zig+97-18| ... | ... | @@ -111,21 +111,46 @@ pub const Mnemonic = enum { |
| 111 | 111 | ebreak, |
| 112 | 112 | unimp, |
| 113 | 113 | |
| 114 | // float mnemonics | |
| 114 | // F extension (32-bit float) | |
| 115 | 115 | fadds, |
| 116 | faddd, | |
| 116 | fsubs, | |
| 117 | fmuls, | |
| 118 | fdivs, | |
| 117 | 119 | |
| 118 | feqs, | |
| 119 | feqd, | |
| 120 | fmins, | |
| 121 | fmaxs, | |
| 120 | 122 | |
| 121 | fld, | |
| 122 | flw, | |
| 123 | fsqrts, | |
| 123 | 124 | |
| 124 | fsd, | |
| 125 | flw, | |
| 125 | 126 | fsw, |
| 126 | 127 | |
| 128 | feqs, | |
| 129 | flts, | |
| 130 | fles, | |
| 131 | ||
| 127 | 132 | fsgnjns, |
| 128 | 133 | |
| 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 | 154 | pub fn encoding(mnem: Mnemonic) Enc { |
| 130 | 155 | return switch (mnem) { |
| 131 | 156 | // zig fmt: off |
| ... | ... | @@ -163,39 +188,66 @@ pub const Mnemonic = enum { |
| 163 | 188 | .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } }, |
| 164 | 189 | .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } }, |
| 165 | 190 | |
| 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 | 215 | .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } }, |
| 167 | 216 | .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } }, |
| 168 | 217 | |
| 169 | 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 | ||
| 170 | 221 | |
| 171 | 222 | // LOAD |
| 172 | 223 | |
| 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 | 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 | 228 | .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } }, |
| 229 | .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } }, | |
| 230 | .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } }, | |
| 180 | 231 | |
| 181 | 232 | |
| 182 | 233 | // 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 | ||
| 187 | 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 } } }, | |
| 188 | 239 | |
| 189 | 240 | |
| 190 | 241 | // LOAD_FP |
| 191 | 242 | |
| 192 | .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } }, | |
| 193 | 243 | .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } }, |
| 244 | .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } }, | |
| 245 | ||
| 194 | 246 | |
| 195 | 247 | // STORE_FP |
| 196 | 248 | |
| 197 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } }, | |
| 198 | 249 | .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } }, |
| 250 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } }, | |
| 199 | 251 | |
| 200 | 252 | |
| 201 | 253 | // JALR |
| ... | ... | @@ -310,9 +362,36 @@ pub const InstEnc = enum { |
| 310 | 362 | |
| 311 | 363 | .fadds, |
| 312 | 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 | 390 | .feqs, |
| 314 | 391 | .feqd, |
| 392 | ||
| 315 | 393 | .fsgnjns, |
| 394 | .fsgnjnd, | |
| 316 | 395 | => .R, |
| 317 | 396 | |
| 318 | 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 | 139 | |
| 140 | 140 | switch (dst_class) { |
| 141 | 141 | .float => { |
| 142 | try lower.emit(.fsgnjns, &.{ | |
| 142 | try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{ | |
| 143 | 143 | .{ .reg = rr.rd }, |
| 144 | 144 | .{ .reg = rr.rs }, |
| 145 | 145 | .{ .reg = rr.rs }, |
| ... | ... | @@ -176,9 +176,11 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 176 | 176 | .pseudo_load_symbol => { |
| 177 | 177 | const payload = inst.data.payload; |
| 178 | 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); | |
| 179 | 181 | |
| 180 | 182 | try lower.emit(.lui, &.{ |
| 181 | .{ .reg = @enumFromInt(data.register) }, | |
| 183 | .{ .reg = dst_reg }, | |
| 182 | 184 | .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{ |
| 183 | 185 | .atom_index = data.atom_index, |
| 184 | 186 | .sym_index = data.sym_index, |
| ... | ... | @@ -187,14 +189,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 187 | 189 | |
| 188 | 190 | // the above reloc implies this one |
| 189 | 191 | try lower.emit(.addi, &.{ |
| 190 | .{ .reg = @enumFromInt(data.register) }, | |
| 191 | .{ .reg = @enumFromInt(data.register) }, | |
| 192 | .{ .reg = dst_reg }, | |
| 193 | .{ .reg = dst_reg }, | |
| 192 | 194 | .{ .imm = Immediate.s(0) }, |
| 193 | 195 | }); |
| 194 | 196 | }, |
| 195 | 197 | |
| 196 | 198 | .pseudo_lea_rm => { |
| 197 | 199 | const rm = inst.data.rm; |
| 200 | assert(rm.r.class() == .int); | |
| 201 | ||
| 198 | 202 | const frame = rm.m.toFrameLoc(lower.mir); |
| 199 | 203 | |
| 200 | 204 | try lower.emit(.addi, &.{ |
| ... | ... | @@ -212,78 +216,135 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 212 | 216 | const rs1 = compare.rs1; |
| 213 | 217 | const rs2 = compare.rs2; |
| 214 | 218 | |
| 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 | }, | |
| 228 | 290 | }, |
| 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 | }, | |
| 281 | 341 | }, |
| 282 | 342 | } |
| 283 | 343 | }, |
| 284 | 344 | |
| 285 | 345 | .pseudo_not => { |
| 286 | 346 | const rr = inst.data.rr; |
| 347 | assert(rr.rs.class() == .int and rr.rd.class() == .int); | |
| 287 | 348 | |
| 288 | 349 | try lower.emit(.xori, &.{ |
| 289 | 350 | .{ .reg = rr.rd }, |
| ... | ... | @@ -408,6 +469,12 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error { |
| 408 | 469 | return error.LowerFail; |
| 409 | 470 | } |
| 410 | 471 | |
| 472 | fn 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 | ||
| 411 | 478 | const Lower = @This(); |
| 412 | 479 | |
| 413 | 480 | const abi = @import("abi.zig"); |
src/arch/riscv64/Mir.zig+25| ... | ... | @@ -72,15 +72,39 @@ pub const Inst = struct { |
| 72 | 72 | |
| 73 | 73 | // F extension (32-bit float) |
| 74 | 74 | fadds, |
| 75 | fsubs, | |
| 76 | fmuls, | |
| 77 | fdivs, | |
| 78 | ||
| 79 | fmins, | |
| 80 | fmaxs, | |
| 81 | ||
| 82 | fsqrts, | |
| 83 | ||
| 75 | 84 | flw, |
| 76 | 85 | fsw, |
| 86 | ||
| 77 | 87 | feqs, |
| 88 | flts, | |
| 89 | fles, | |
| 78 | 90 | |
| 79 | 91 | // D extension (64-bit float) |
| 80 | 92 | faddd, |
| 93 | fsubd, | |
| 94 | fmuld, | |
| 95 | fdivd, | |
| 96 | ||
| 97 | fmind, | |
| 98 | fmaxd, | |
| 99 | ||
| 100 | fsqrtd, | |
| 101 | ||
| 81 | 102 | fld, |
| 82 | 103 | fsd, |
| 104 | ||
| 83 | 105 | feqd, |
| 106 | fltd, | |
| 107 | fled, | |
| 84 | 108 | |
| 85 | 109 | /// A pseudo-instruction. Used for anything that isn't 1:1 with an |
| 86 | 110 | /// assembly instruction. |
| ... | ... | @@ -182,6 +206,7 @@ pub const Inst = struct { |
| 182 | 206 | lt, |
| 183 | 207 | lte, |
| 184 | 208 | }, |
| 209 | size: Memory.Size, | |
| 185 | 210 | }, |
| 186 | 211 | |
| 187 | 212 | reloc: struct { |
test/behavior/cast.zig-2| ... | ... | @@ -1717,7 +1717,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" { |
| 1717 | 1717 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1718 | 1718 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1719 | 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; | |
| 1721 | 1720 | |
| 1722 | 1721 | const i: u8 = 100; |
| 1723 | 1722 | var f: f32 = 1.234; |
| ... | ... | @@ -2586,7 +2585,6 @@ test "@intFromBool on vector" { |
| 2586 | 2585 | |
| 2587 | 2586 | test "numeric coercions with undefined" { |
| 2588 | 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; | |
| 2590 | 2588 | |
| 2591 | 2589 | const from: i32 = undefined; |
| 2592 | 2590 | var to: f32 = from; |
test/behavior/floatop.zig-12| ... | ... | @@ -22,8 +22,6 @@ test "add f16" { |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | 24 | test "add f32/f64" { |
| 25 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 26 | ||
| 27 | 25 | try testAdd(f32); |
| 28 | 26 | try comptime testAdd(f32); |
| 29 | 27 | try testAdd(f64); |
| ... | ... | @@ -60,8 +58,6 @@ test "sub f16" { |
| 60 | 58 | } |
| 61 | 59 | |
| 62 | 60 | test "sub f32/f64" { |
| 63 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 64 | ||
| 65 | 61 | try testSub(f32); |
| 66 | 62 | try comptime testSub(f32); |
| 67 | 63 | try testSub(f64); |
| ... | ... | @@ -98,8 +94,6 @@ test "mul f16" { |
| 98 | 94 | } |
| 99 | 95 | |
| 100 | 96 | test "mul f32/f64" { |
| 101 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 102 | ||
| 103 | 97 | try testMul(f32); |
| 104 | 98 | try comptime testMul(f32); |
| 105 | 99 | try testMul(f64); |
| ... | ... | @@ -1622,7 +1616,6 @@ test "comptime inf >= runtime 1" { |
| 1622 | 1616 | test "comptime isNan(nan * 1)" { |
| 1623 | 1617 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1624 | 1618 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1625 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1626 | 1619 | |
| 1627 | 1620 | const nan_times_one = comptime std.math.nan(f64) * 1; |
| 1628 | 1621 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| ... | ... | @@ -1630,7 +1623,6 @@ test "comptime isNan(nan * 1)" { |
| 1630 | 1623 | test "runtime isNan(nan * 1)" { |
| 1631 | 1624 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1632 | 1625 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1633 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1634 | 1626 | |
| 1635 | 1627 | const nan_times_one = std.math.nan(f64) * 1; |
| 1636 | 1628 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| ... | ... | @@ -1638,7 +1630,6 @@ test "runtime isNan(nan * 1)" { |
| 1638 | 1630 | test "comptime isNan(nan * 0)" { |
| 1639 | 1631 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1640 | 1632 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1641 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1642 | 1633 | |
| 1643 | 1634 | const nan_times_zero = comptime std.math.nan(f64) * 0; |
| 1644 | 1635 | try std.testing.expect(std.math.isNan(nan_times_zero)); |
| ... | ... | @@ -1648,7 +1639,6 @@ test "comptime isNan(nan * 0)" { |
| 1648 | 1639 | test "runtime isNan(nan * 0)" { |
| 1649 | 1640 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1650 | 1641 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1651 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1652 | 1642 | |
| 1653 | 1643 | const nan_times_zero = std.math.nan(f64) * 0; |
| 1654 | 1644 | try std.testing.expect(std.math.isNan(nan_times_zero)); |
| ... | ... | @@ -1658,7 +1648,6 @@ test "runtime isNan(nan * 0)" { |
| 1658 | 1648 | test "comptime isNan(inf * 0)" { |
| 1659 | 1649 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1660 | 1650 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1661 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1662 | 1651 | |
| 1663 | 1652 | const inf_times_zero = comptime std.math.inf(f64) * 0; |
| 1664 | 1653 | try std.testing.expect(std.math.isNan(inf_times_zero)); |
| ... | ... | @@ -1668,7 +1657,6 @@ test "comptime isNan(inf * 0)" { |
| 1668 | 1657 | test "runtime isNan(inf * 0)" { |
| 1669 | 1658 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1670 | 1659 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1671 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1672 | 1660 | |
| 1673 | 1661 | const inf_times_zero = std.math.inf(f64) * 0; |
| 1674 | 1662 | try std.testing.expect(std.math.isNan(inf_times_zero)); |
test/behavior/math.zig-1| ... | ... | @@ -236,7 +236,6 @@ test "float equality" { |
| 236 | 236 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 237 | 237 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 238 | 238 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 239 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 240 | 239 | |
| 241 | 240 | const x: f64 = 0.012; |
| 242 | 241 | const y: f64 = x + 1.0; |