| ... | @@ -119,6 +119,12 @@ pub const MCValue = union(enum) { | ... | @@ -119,6 +119,12 @@ pub const MCValue = union(enum) { |
| 119 | immediate: u64, | 119 | immediate: u64, |
| 120 | /// The value is in a target-specific register. | 120 | /// The value is in a target-specific register. |
| 121 | register: Register, | 121 | register: Register, |
| | 122 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the register, |
| | 123 | /// and the operation is an unsigned operation. |
| | 124 | register_overflow_unsigned: Register, |
| | 125 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the register, |
| | 126 | /// and the operation is a signed operation. |
| | 127 | register_overflow_signed: Register, |
| 122 | /// The value is in memory at a hard-coded address. | 128 | /// The value is in memory at a hard-coded address. |
| 123 | /// If the type is a pointer, it means the pointer address is at this memory location. | 129 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 124 | memory: u64, | 130 | memory: u64, |
| ... | @@ -144,7 +150,10 @@ pub const MCValue = union(enum) { | ... | @@ -144,7 +150,10 @@ pub const MCValue = union(enum) { |
| 144 | | 150 | |
| 145 | fn isMemory(mcv: MCValue) bool { | 151 | fn isMemory(mcv: MCValue) bool { |
| 146 | return switch (mcv) { | 152 | return switch (mcv) { |
| 147 | .memory, .stack_offset => true, | 153 | .memory, |
| | 154 | .stack_offset, |
| | 155 | .ptr_stack_offset, |
| | 156 | => true, |
| 148 | else => false, | 157 | else => false, |
| 149 | }; | 158 | }; |
| 150 | } | 159 | } |
| ... | @@ -168,6 +177,8 @@ pub const MCValue = union(enum) { | ... | @@ -168,6 +177,8 @@ pub const MCValue = union(enum) { |
| 168 | .compare_flags_signed, | 177 | .compare_flags_signed, |
| 169 | .ptr_stack_offset, | 178 | .ptr_stack_offset, |
| 170 | .undef, | 179 | .undef, |
| | 180 | .register_overflow_unsigned, |
| | 181 | .register_overflow_signed, |
| 171 | => false, | 182 | => false, |
| 172 | | 183 | |
| 173 | .register, | 184 | .register, |
| ... | @@ -176,16 +187,33 @@ pub const MCValue = union(enum) { | ... | @@ -176,16 +187,33 @@ pub const MCValue = union(enum) { |
| 176 | }; | 187 | }; |
| 177 | } | 188 | } |
| 178 | | 189 | |
| | 190 | fn usesCompareFlags(mcv: MCValue) bool { |
| | 191 | return switch (mcv) { |
| | 192 | .compare_flags_unsigned, |
| | 193 | .compare_flags_signed, |
| | 194 | .register_overflow_unsigned, |
| | 195 | .register_overflow_signed, |
| | 196 | => true, |
| | 197 | else => false, |
| | 198 | }; |
| | 199 | } |
| | 200 | |
| 179 | fn isRegister(mcv: MCValue) bool { | 201 | fn isRegister(mcv: MCValue) bool { |
| 180 | return switch (mcv) { | 202 | return switch (mcv) { |
| 181 | .register => true, | 203 | .register, |
| | 204 | .register_overflow_unsigned, |
| | 205 | .register_overflow_signed, |
| | 206 | => true, |
| 182 | else => false, | 207 | else => false, |
| 183 | }; | 208 | }; |
| 184 | } | 209 | } |
| 185 | | 210 | |
| 186 | fn freezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { | 211 | fn freezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| 187 | switch (mcv) { | 212 | switch (mcv) { |
| 188 | .register => |reg| { | 213 | .register, |
| | 214 | .register_overflow_signed, |
| | 215 | .register_overflow_unsigned, |
| | 216 | => |reg| { |
| 189 | mgr.freezeRegs(&.{reg}); | 217 | mgr.freezeRegs(&.{reg}); |
| 190 | }, | 218 | }, |
| 191 | else => {}, | 219 | else => {}, |
| ... | @@ -194,12 +222,25 @@ pub const MCValue = union(enum) { | ... | @@ -194,12 +222,25 @@ pub const MCValue = union(enum) { |
| 194 | | 222 | |
| 195 | fn unfreezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { | 223 | fn unfreezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| 196 | switch (mcv) { | 224 | switch (mcv) { |
| 197 | .register => |reg| { | 225 | .register, |
| | 226 | .register_overflow_signed, |
| | 227 | .register_overflow_unsigned, |
| | 228 | => |reg| { |
| 198 | mgr.unfreezeRegs(&.{reg}); | 229 | mgr.unfreezeRegs(&.{reg}); |
| 199 | }, | 230 | }, |
| 200 | else => {}, | 231 | else => {}, |
| 201 | } | 232 | } |
| 202 | } | 233 | } |
| | 234 | |
| | 235 | fn asRegister(mcv: MCValue) ?Register { |
| | 236 | return switch (mcv) { |
| | 237 | .register, |
| | 238 | .register_overflow_signed, |
| | 239 | .register_overflow_unsigned, |
| | 240 | => |reg| reg, |
| | 241 | else => null, |
| | 242 | }; |
| | 243 | } |
| 203 | }; | 244 | }; |
| 204 | | 245 | |
| 205 | const Branch = struct { | 246 | const Branch = struct { |
| ... | @@ -807,8 +848,11 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -807,8 +848,11 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 807 | branch.inst_table.putAssumeCapacity(inst, .dead); | 848 | branch.inst_table.putAssumeCapacity(inst, .dead); |
| 808 | switch (prev_value) { | 849 | switch (prev_value) { |
| 809 | .register => |reg| { | 850 | .register => |reg| { |
| 810 | const canon_reg = reg.to64(); | 851 | self.register_manager.freeReg(reg.to64()); |
| 811 | self.register_manager.freeReg(canon_reg); | 852 | }, |
| | 853 | .register_overflow_signed, .register_overflow_unsigned => |reg| { |
| | 854 | self.register_manager.freeReg(reg.to64()); |
| | 855 | self.compare_flags_inst = null; |
| 812 | }, | 856 | }, |
| 813 | .compare_flags_signed, .compare_flags_unsigned => { | 857 | .compare_flags_signed, .compare_flags_unsigned => { |
| 814 | self.compare_flags_inst = null; | 858 | self.compare_flags_inst = null; |
| ... | @@ -841,18 +885,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -841,18 +885,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 841 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 885 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 842 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); | 886 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); |
| 843 | | 887 | |
| 844 | switch (result) { | 888 | if (result.asRegister()) |reg| { |
| 845 | .register => |reg| { | 889 | // In some cases (such as bitcast), an operand |
| 846 | // In some cases (such as bitcast), an operand | 890 | // may be the same MCValue as the result. If |
| 847 | // may be the same MCValue as the result. If | 891 | // that operand died and was a register, it |
| 848 | // that operand died and was a register, it | 892 | // was freed by processDeath. We have to |
| 849 | // was freed by processDeath. We have to | 893 | // "re-allocate" the register. |
| 850 | // "re-allocate" the register. | 894 | if (self.register_manager.isRegFree(reg)) { |
| 851 | if (self.register_manager.isRegFree(reg)) { | 895 | self.register_manager.getRegAssumeFree(reg, inst); |
| 852 | self.register_manager.getRegAssumeFree(reg, inst); | 896 | } |
| 853 | } | | |
| 854 | }, | | |
| 855 | else => {}, | | |
| 856 | } | 897 | } |
| 857 | } | 898 | } |
| 858 | self.finishAirBookkeeping(); | 899 | self.finishAirBookkeeping(); |
| ... | @@ -924,7 +965,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -924,7 +965,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 924 | const stack_mcv = try self.allocRegOrMem(inst, false); | 965 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 925 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); | 966 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 926 | const reg_mcv = self.getResolvedInstValue(inst); | 967 | const reg_mcv = self.getResolvedInstValue(inst); |
| 927 | assert(reg.to64() == reg_mcv.register.to64()); | 968 | assert(reg.to64() == reg_mcv.asRegister().?.to64()); |
| 928 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 969 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 929 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 970 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 930 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); | 971 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); |
| ... | @@ -933,7 +974,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -933,7 +974,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 933 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { | 974 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 934 | if (self.compare_flags_inst) |inst_to_save| { | 975 | if (self.compare_flags_inst) |inst_to_save| { |
| 935 | const mcv = self.getResolvedInstValue(inst_to_save); | 976 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 936 | assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned); | 977 | assert(mcv.usesCompareFlags()); |
| 937 | | 978 | |
| 938 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); | 979 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); |
| 939 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 980 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| ... | @@ -1291,17 +1332,21 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1291,17 +1332,21 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1291 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1332 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1292 | } | 1333 | } |
| 1293 | | 1334 | |
| | 1335 | /// Result is always a register. |
| 1294 | fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { | 1336 | fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1295 | const dst_ty = self.air.typeOfIndex(inst); | 1337 | const dst_ty = self.air.typeOf(op_lhs); |
| | 1338 | |
| 1296 | const lhs = try self.resolveInst(op_lhs); | 1339 | const lhs = try self.resolveInst(op_lhs); |
| 1297 | const rhs = try self.resolveInst(op_rhs); | 1340 | lhs.freezeIfRegister(&self.register_manager); |
| | 1341 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1298 | | 1342 | |
| | 1343 | const rhs = try self.resolveInst(op_rhs); |
| 1299 | rhs.freezeIfRegister(&self.register_manager); | 1344 | rhs.freezeIfRegister(&self.register_manager); |
| 1300 | defer rhs.unfreezeIfRegister(&self.register_manager); | 1345 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1301 | | 1346 | |
| 1302 | const dst_mcv = blk: { | 1347 | const dst_mcv = blk: { |
| 1303 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { | 1348 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 1304 | if (lhs.isMemory() or lhs.isRegister()) break :blk lhs; | 1349 | break :blk lhs; |
| 1305 | } | 1350 | } |
| 1306 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); | 1351 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 1307 | }; | 1352 | }; |
| ... | @@ -1310,7 +1355,7 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air | ... | @@ -1310,7 +1355,7 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air |
| 1310 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); | 1355 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 1311 | | 1356 | |
| 1312 | const rhs_mcv = blk: { | 1357 | const rhs_mcv = blk: { |
| 1313 | if (rhs.isRegister()) break :blk rhs; | 1358 | if (rhs.isMemory() or rhs.isRegister()) break :blk rhs; |
| 1314 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; | 1359 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 1315 | }; | 1360 | }; |
| 1316 | | 1361 | |
| ... | @@ -1377,18 +1422,78 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1377,18 +1422,78 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1377 | } | 1422 | } |
| 1378 | | 1423 | |
| 1379 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1424 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1380 | _ = inst; | 1425 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1381 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | 1426 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1427 | |
| | 1428 | if (self.liveness.isUnused(inst)) { |
| | 1429 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1430 | } |
| | 1431 | |
| | 1432 | const ty = self.air.typeOf(bin_op.lhs); |
| | 1433 | const signedness: std.builtin.Signedness = blk: { |
| | 1434 | if (ty.zigTypeTag() != .Int) { |
| | 1435 | return self.fail("TODO implement airAddWithOverflow for type {}", .{ty.fmtDebug()}); |
| | 1436 | } |
| | 1437 | break :blk ty.intInfo(self.target.*).signedness; |
| | 1438 | }; |
| | 1439 | |
| | 1440 | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| | 1441 | const result: MCValue = switch (signedness) { |
| | 1442 | .signed => .{ .register_overflow_signed = partial.register }, |
| | 1443 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| | 1444 | }; |
| | 1445 | |
| | 1446 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1382 | } | 1447 | } |
| 1383 | | 1448 | |
| 1384 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1449 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1385 | _ = inst; | 1450 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1386 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | 1451 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1452 | |
| | 1453 | if (self.liveness.isUnused(inst)) { |
| | 1454 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1455 | } |
| | 1456 | |
| | 1457 | const ty = self.air.typeOf(bin_op.lhs); |
| | 1458 | const signedness: std.builtin.Signedness = blk: { |
| | 1459 | if (ty.zigTypeTag() != .Int) { |
| | 1460 | return self.fail("TODO implement airSubWithOverflow for type {}", .{ty.fmtDebug()}); |
| | 1461 | } |
| | 1462 | break :blk ty.intInfo(self.target.*).signedness; |
| | 1463 | }; |
| | 1464 | |
| | 1465 | const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); |
| | 1466 | const result: MCValue = switch (signedness) { |
| | 1467 | .signed => .{ .register_overflow_signed = partial.register }, |
| | 1468 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| | 1469 | }; |
| | 1470 | |
| | 1471 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1387 | } | 1472 | } |
| 1388 | | 1473 | |
| 1389 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1474 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1390 | _ = inst; | 1475 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1391 | return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); | 1476 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1477 | |
| | 1478 | if (self.liveness.isUnused(inst)) { |
| | 1479 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1480 | } |
| | 1481 | |
| | 1482 | const ty = self.air.typeOf(bin_op.lhs); |
| | 1483 | const signedness: std.builtin.Signedness = blk: { |
| | 1484 | if (ty.zigTypeTag() != .Int) { |
| | 1485 | return self.fail("TODO implement airMulWithOverflow for type {}", .{ty.fmtDebug()}); |
| | 1486 | } |
| | 1487 | break :blk ty.intInfo(self.target.*).signedness; |
| | 1488 | }; |
| | 1489 | |
| | 1490 | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| | 1491 | const result: MCValue = switch (signedness) { |
| | 1492 | .signed => .{ .register_overflow_signed = partial.register }, |
| | 1493 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| | 1494 | }; |
| | 1495 | |
| | 1496 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1392 | } | 1497 | } |
| 1393 | | 1498 | |
| 1394 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1499 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2422,6 +2527,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2422,6 +2527,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2422 | .dead => unreachable, | 2527 | .dead => unreachable, |
| 2423 | .compare_flags_unsigned => unreachable, | 2528 | .compare_flags_unsigned => unreachable, |
| 2424 | .compare_flags_signed => unreachable, | 2529 | .compare_flags_signed => unreachable, |
| | 2530 | .register_overflow_unsigned => unreachable, |
| | 2531 | .register_overflow_signed => unreachable, |
| 2425 | .immediate => |imm| { | 2532 | .immediate => |imm| { |
| 2426 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); | 2533 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); |
| 2427 | }, | 2534 | }, |
| ... | @@ -2545,6 +2652,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2545,6 +2652,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2545 | .dead => unreachable, | 2652 | .dead => unreachable, |
| 2546 | .compare_flags_unsigned => unreachable, | 2653 | .compare_flags_unsigned => unreachable, |
| 2547 | .compare_flags_signed => unreachable, | 2654 | .compare_flags_signed => unreachable, |
| | 2655 | .register_overflow_unsigned => unreachable, |
| | 2656 | .register_overflow_signed => unreachable, |
| 2548 | .immediate => |imm| { | 2657 | .immediate => |imm| { |
| 2549 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | 2658 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 2550 | }, | 2659 | }, |
| ... | @@ -2899,6 +3008,38 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2899,6 +3008,38 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2899 | | 3008 | |
| 2900 | break :result dst_mcv; | 3009 | break :result dst_mcv; |
| 2901 | }, | 3010 | }, |
| | 3011 | .register_overflow_unsigned, |
| | 3012 | .register_overflow_signed, |
| | 3013 | => |reg| { |
| | 3014 | switch (index) { |
| | 3015 | 0 => { |
| | 3016 | // Get wrapped value for overflow operation. |
| | 3017 | break :result MCValue{ .register = reg }; |
| | 3018 | }, |
| | 3019 | 1 => { |
| | 3020 | // Get overflow bit. |
| | 3021 | mcv.freezeIfRegister(&self.register_manager); |
| | 3022 | defer mcv.unfreezeIfRegister(&self.register_manager); |
| | 3023 | |
| | 3024 | const dst_reg = try self.register_manager.allocReg(inst); |
| | 3025 | const flags: u2 = switch (mcv) { |
| | 3026 | .register_overflow_unsigned => 0b10, |
| | 3027 | .register_overflow_signed => 0b00, |
| | 3028 | else => unreachable, |
| | 3029 | }; |
| | 3030 | _ = try self.addInst(.{ |
| | 3031 | .tag = .cond_set_byte_overflow, |
| | 3032 | .ops = (Mir.Ops{ |
| | 3033 | .reg1 = dst_reg.to8(), |
| | 3034 | .flags = flags, |
| | 3035 | }).encode(), |
| | 3036 | .data = undefined, |
| | 3037 | }); |
| | 3038 | break :result MCValue{ .register = dst_reg.to8() }; |
| | 3039 | }, |
| | 3040 | else => unreachable, |
| | 3041 | } |
| | 3042 | }, |
| 2902 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), | 3043 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| 2903 | } | 3044 | } |
| 2904 | }; | 3045 | }; |
| ... | @@ -2915,84 +3056,47 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2915,84 +3056,47 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2915 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3056 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2916 | } | 3057 | } |
| 2917 | | 3058 | |
| 2918 | /// Perform "binary" operators, excluding comparisons. | 3059 | /// Result is always a register. |
| 2919 | /// Currently, the following ops are supported: | | |
| 2920 | /// ADD, SUB, XOR, OR, AND | | |
| 2921 | fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { | 3060 | fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 2922 | // TODO: make this algorithm less bad | 3061 | const dst_ty = self.air.typeOf(op_lhs); |
| | 3062 | |
| 2923 | const lhs = try self.resolveInst(op_lhs); | 3063 | const lhs = try self.resolveInst(op_lhs); |
| | 3064 | lhs.freezeIfRegister(&self.register_manager); |
| | 3065 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| | 3066 | |
| 2924 | const rhs = try self.resolveInst(op_rhs); | 3067 | const rhs = try self.resolveInst(op_rhs); |
| | 3068 | rhs.freezeIfRegister(&self.register_manager); |
| | 3069 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 2925 | | 3070 | |
| 2926 | // There are 2 operands, destination and source. | 3071 | var flipped: bool = false; |
| 2927 | // Either one, but not both, can be a memory operand. | 3072 | const dst_mcv = blk: { |
| 2928 | // Source operand can be an immediate, 8 bits or 32 bits. | 3073 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 2929 | // So, if either one of the operands dies with this instruction, we can use it | 3074 | break :blk lhs; |
| 2930 | // as the result MCValue. | | |
| 2931 | const dst_ty = self.air.typeOfIndex(inst); | | |
| 2932 | var dst_mcv: MCValue = undefined; | | |
| 2933 | var src_mcv: MCValue = undefined; | | |
| 2934 | | | |
| 2935 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { | | |
| 2936 | // LHS dies; use it as the destination. | | |
| 2937 | // Both operands cannot be memory. | | |
| 2938 | if (lhs.isMemory() and rhs.isMemory()) { | | |
| 2939 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); | | |
| 2940 | src_mcv = rhs; | | |
| 2941 | } else { | | |
| 2942 | dst_mcv = lhs; | | |
| 2943 | src_mcv = rhs; | | |
| 2944 | } | | |
| 2945 | } else if (self.reuseOperand(inst, op_rhs, 1, rhs)) { | | |
| 2946 | // RHS dies; use it as the destination. | | |
| 2947 | // Both operands cannot be memory. | | |
| 2948 | if (lhs.isMemory() and rhs.isMemory()) { | | |
| 2949 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs); | | |
| 2950 | src_mcv = lhs; | | |
| 2951 | } else { | | |
| 2952 | dst_mcv = rhs; | | |
| 2953 | src_mcv = lhs; | | |
| 2954 | } | 3075 | } |
| 2955 | } else { | 3076 | if (self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) { |
| 2956 | if (lhs.isMemory()) { | 3077 | flipped = true; |
| 2957 | rhs.freezeIfRegister(&self.register_manager); | 3078 | break :blk rhs; |
| 2958 | defer rhs.unfreezeIfRegister(&self.register_manager); | | |
| 2959 | | | |
| 2960 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); | | |
| 2961 | src_mcv = rhs; | | |
| 2962 | } else { | | |
| 2963 | lhs.freezeIfRegister(&self.register_manager); | | |
| 2964 | defer lhs.unfreezeIfRegister(&self.register_manager); | | |
| 2965 | | | |
| 2966 | dst_mcv = try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs); | | |
| 2967 | src_mcv = lhs; | | |
| 2968 | } | 3079 | } |
| 2969 | } | 3080 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 2970 | // This instruction supports only signed 32-bit immediates at most. If the immediate | 3081 | }; |
| 2971 | // value is larger than this, we put it in a register. | 3082 | dst_mcv.freezeIfRegister(&self.register_manager); |
| 2972 | // A potential opportunity for future optimization here would be keeping track | 3083 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 2973 | // of the fact that the instruction is available both as an immediate | | |
| 2974 | // and as a register. | | |
| 2975 | // TODO consolidate with limitImmediateType() function | | |
| 2976 | switch (src_mcv) { | | |
| 2977 | .immediate => |imm| { | | |
| 2978 | if (imm > math.maxInt(u31)) { | | |
| 2979 | dst_mcv.freezeIfRegister(&self.register_manager); | | |
| 2980 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); | | |
| 2981 | | 3084 | |
| 2982 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(Type.usize, src_mcv) }; | 3085 | const src_mcv = blk: { |
| 2983 | } | 3086 | const mcv = if (flipped) lhs else rhs; |
| 2984 | }, | 3087 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; |
| 2985 | else => {}, | 3088 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) }; |
| 2986 | } | 3089 | }; |
| | 3090 | src_mcv.freezeIfRegister(&self.register_manager); |
| | 3091 | defer src_mcv.unfreezeIfRegister(&self.register_manager); |
| 2987 | | 3092 | |
| 2988 | const tag = self.air.instructions.items(.tag)[inst]; | 3093 | const tag = self.air.instructions.items(.tag)[inst]; |
| 2989 | switch (tag) { | 3094 | switch (tag) { |
| 2990 | .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), | 3095 | .add, .addwrap, .add_with_overflow => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), |
| 2991 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), | 3096 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 2992 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), | 3097 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 2993 | .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv), | | |
| 2994 | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), | 3098 | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), |
| 2995 | .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv), | 3099 | .mul, .mulwrap, .mul_with_overflow => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv), |
| 2996 | else => unreachable, | 3100 | else => unreachable, |
| 2997 | } | 3101 | } |
| 2998 | return dst_mcv; | 3102 | return dst_mcv; |
| ... | @@ -3007,11 +3111,15 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3007,11 +3111,15 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3007 | .compare_flags_unsigned => unreachable, | 3111 | .compare_flags_unsigned => unreachable, |
| 3008 | .compare_flags_signed => unreachable, | 3112 | .compare_flags_signed => unreachable, |
| 3009 | .ptr_stack_offset => unreachable, | 3113 | .ptr_stack_offset => unreachable, |
| | 3114 | .register_overflow_unsigned => unreachable, |
| | 3115 | .register_overflow_signed => unreachable, |
| 3010 | .register => |dst_reg| { | 3116 | .register => |dst_reg| { |
| 3011 | switch (src_mcv) { | 3117 | switch (src_mcv) { |
| 3012 | .none => unreachable, | 3118 | .none => unreachable, |
| 3013 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), | 3119 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), |
| 3014 | .dead, .unreach => unreachable, | 3120 | .dead, .unreach => unreachable, |
| | 3121 | .register_overflow_unsigned => unreachable, |
| | 3122 | .register_overflow_signed => unreachable, |
| 3015 | .ptr_stack_offset => { | 3123 | .ptr_stack_offset => { |
| 3016 | self.register_manager.freezeRegs(&.{dst_reg}); | 3124 | self.register_manager.freezeRegs(&.{dst_reg}); |
| 3017 | defer self.register_manager.unfreezeRegs(&.{dst_reg}); | 3125 | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| ... | @@ -3078,6 +3186,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3078,6 +3186,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3078 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), | 3186 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), |
| 3079 | .dead, .unreach => unreachable, | 3187 | .dead, .unreach => unreachable, |
| 3080 | .ptr_stack_offset => unreachable, | 3188 | .ptr_stack_offset => unreachable, |
| | 3189 | .register_overflow_unsigned => unreachable, |
| | 3190 | .register_overflow_signed => unreachable, |
| 3081 | .register => |src_reg| { | 3191 | .register => |src_reg| { |
| 3082 | _ = try self.addInst(.{ | 3192 | _ = try self.addInst(.{ |
| 3083 | .tag = mir_tag, | 3193 | .tag = mir_tag, |
| ... | @@ -3144,6 +3254,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3144,6 +3254,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3144 | | 3254 | |
| 3145 | // Performs integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. | 3255 | // Performs integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3146 | fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | 3256 | fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| | 3257 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3147 | switch (dst_mcv) { | 3258 | switch (dst_mcv) { |
| 3148 | .none => unreachable, | 3259 | .none => unreachable, |
| 3149 | .undef => unreachable, | 3260 | .undef => unreachable, |
| ... | @@ -3151,19 +3262,23 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -3151,19 +3262,23 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3151 | .compare_flags_unsigned => unreachable, | 3262 | .compare_flags_unsigned => unreachable, |
| 3152 | .compare_flags_signed => unreachable, | 3263 | .compare_flags_signed => unreachable, |
| 3153 | .ptr_stack_offset => unreachable, | 3264 | .ptr_stack_offset => unreachable, |
| | 3265 | .register_overflow_unsigned => unreachable, |
| | 3266 | .register_overflow_signed => unreachable, |
| 3154 | .register => |dst_reg| { | 3267 | .register => |dst_reg| { |
| 3155 | switch (src_mcv) { | 3268 | switch (src_mcv) { |
| 3156 | .none => unreachable, | 3269 | .none => unreachable, |
| 3157 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), | 3270 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), |
| 3158 | .dead, .unreach => unreachable, | 3271 | .dead, .unreach => unreachable, |
| 3159 | .ptr_stack_offset => unreachable, | 3272 | .ptr_stack_offset => unreachable, |
| | 3273 | .register_overflow_unsigned => unreachable, |
| | 3274 | .register_overflow_signed => unreachable, |
| 3160 | .register => |src_reg| { | 3275 | .register => |src_reg| { |
| 3161 | // register, register | 3276 | // register, register |
| 3162 | _ = try self.addInst(.{ | 3277 | _ = try self.addInst(.{ |
| 3163 | .tag = .imul_complex, | 3278 | .tag = .imul_complex, |
| 3164 | .ops = (Mir.Ops{ | 3279 | .ops = (Mir.Ops{ |
| 3165 | .reg1 = registerAlias(dst_reg, @divExact(src_reg.size(), 8)), | 3280 | .reg1 = registerAlias(dst_reg, abi_size), |
| 3166 | .reg2 = src_reg, | 3281 | .reg2 = registerAlias(src_reg, abi_size), |
| 3167 | }).encode(), | 3282 | }).encode(), |
| 3168 | .data = undefined, | 3283 | .data = undefined, |
| 3169 | }); | 3284 | }); |
| ... | @@ -3191,7 +3306,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -3191,7 +3306,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3191 | _ = try self.addInst(.{ | 3306 | _ = try self.addInst(.{ |
| 3192 | .tag = .imul_complex, | 3307 | .tag = .imul_complex, |
| 3193 | .ops = (Mir.Ops{ | 3308 | .ops = (Mir.Ops{ |
| 3194 | .reg1 = dst_reg, | 3309 | .reg1 = registerAlias(dst_reg, abi_size), |
| 3195 | .reg2 = .rbp, | 3310 | .reg2 = .rbp, |
| 3196 | .flags = 0b01, | 3311 | .flags = 0b01, |
| 3197 | }).encode(), | 3312 | }).encode(), |
| ... | @@ -3218,6 +3333,8 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -3218,6 +3333,8 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3218 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), | 3333 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), |
| 3219 | .dead, .unreach => unreachable, | 3334 | .dead, .unreach => unreachable, |
| 3220 | .ptr_stack_offset => unreachable, | 3335 | .ptr_stack_offset => unreachable, |
| | 3336 | .register_overflow_unsigned => unreachable, |
| | 3337 | .register_overflow_signed => unreachable, |
| 3221 | .register => |src_reg| { | 3338 | .register => |src_reg| { |
| 3222 | // copy dst to a register | 3339 | // copy dst to a register |
| 3223 | const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); | 3340 | const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| ... | @@ -3226,8 +3343,8 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -3226,8 +3343,8 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 3226 | _ = try self.addInst(.{ | 3343 | _ = try self.addInst(.{ |
| 3227 | .tag = .imul_complex, | 3344 | .tag = .imul_complex, |
| 3228 | .ops = (Mir.Ops{ | 3345 | .ops = (Mir.Ops{ |
| 3229 | .reg1 = registerAlias(dst_reg, @divExact(src_reg.size(), 8)), | 3346 | .reg1 = registerAlias(dst_reg, abi_size), |
| 3230 | .reg2 = src_reg, | 3347 | .reg2 = registerAlias(src_reg, abi_size), |
| 3231 | }).encode(), | 3348 | }).encode(), |
| 3232 | .data = undefined, | 3349 | .data = undefined, |
| 3233 | }); | 3350 | }); |
| ... | @@ -3366,6 +3483,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3366,6 +3483,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3366 | try self.genSetReg(arg_ty, reg, arg_mcv); | 3483 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 3367 | }, | 3484 | }, |
| 3368 | .stack_offset => |off| { | 3485 | .stack_offset => |off| { |
| | 3486 | // TODO rewrite using `genSetStack` |
| 3369 | try self.genSetStackArg(arg_ty, off, arg_mcv); | 3487 | try self.genSetStackArg(arg_ty, off, arg_mcv); |
| 3370 | }, | 3488 | }, |
| 3371 | .ptr_stack_offset => { | 3489 | .ptr_stack_offset => { |
| ... | @@ -3380,6 +3498,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3380,6 +3498,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3380 | .direct_load => unreachable, | 3498 | .direct_load => unreachable, |
| 3381 | .compare_flags_signed => unreachable, | 3499 | .compare_flags_signed => unreachable, |
| 3382 | .compare_flags_unsigned => unreachable, | 3500 | .compare_flags_unsigned => unreachable, |
| | 3501 | .register_overflow_signed => unreachable, |
| | 3502 | .register_overflow_unsigned => unreachable, |
| 3383 | } | 3503 | } |
| 3384 | } | 3504 | } |
| 3385 | | 3505 | |
| ... | @@ -4610,6 +4730,9 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -4610,6 +4730,9 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4610 | .{ .dest_stack_base = .rsp }, | 4730 | .{ .dest_stack_base = .rsp }, |
| 4611 | ); | 4731 | ); |
| 4612 | }, | 4732 | }, |
| | 4733 | .register_overflow_unsigned, |
| | 4734 | .register_overflow_signed, |
| | 4735 | => return self.fail("TODO genSetStackArg for register with overflow bit", .{}), |
| 4613 | .compare_flags_unsigned, | 4736 | .compare_flags_unsigned, |
| 4614 | .compare_flags_signed, | 4737 | .compare_flags_signed, |
| 4615 | => { | 4738 | => { |
| ... | @@ -4712,6 +4835,39 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -4712,6 +4835,39 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 4712 | ), | 4835 | ), |
| 4713 | } | 4836 | } |
| 4714 | }, | 4837 | }, |
| | 4838 | .register_overflow_unsigned, |
| | 4839 | .register_overflow_signed, |
| | 4840 | => |reg| { |
| | 4841 | self.register_manager.freezeRegs(&.{reg}); |
| | 4842 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| | 4843 | |
| | 4844 | const wrapped_ty = ty.structFieldType(0); |
| | 4845 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{}); |
| | 4846 | |
| | 4847 | const overflow_bit_ty = ty.structFieldType(1); |
| | 4848 | const overflow_bit_offset = ty.structFieldOffset(1, self.target.*); |
| | 4849 | const tmp_reg = try self.register_manager.allocReg(null); |
| | 4850 | const flags: u2 = switch (mcv) { |
| | 4851 | .register_overflow_unsigned => 0b10, |
| | 4852 | .register_overflow_signed => 0b00, |
| | 4853 | else => unreachable, |
| | 4854 | }; |
| | 4855 | _ = try self.addInst(.{ |
| | 4856 | .tag = .cond_set_byte_overflow, |
| | 4857 | .ops = (Mir.Ops{ |
| | 4858 | .reg1 = tmp_reg.to8(), |
| | 4859 | .flags = flags, |
| | 4860 | }).encode(), |
| | 4861 | .data = undefined, |
| | 4862 | }); |
| | 4863 | |
| | 4864 | return self.genSetStack( |
| | 4865 | overflow_bit_ty, |
| | 4866 | stack_offset - @intCast(i32, overflow_bit_offset), |
| | 4867 | .{ .register = tmp_reg.to8() }, |
| | 4868 | .{}, |
| | 4869 | ); |
| | 4870 | }, |
| 4715 | .compare_flags_unsigned, | 4871 | .compare_flags_unsigned, |
| 4716 | .compare_flags_signed, | 4872 | .compare_flags_signed, |
| 4717 | => { | 4873 | => { |
| ... | @@ -5170,6 +5326,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5170,6 +5326,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5170 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5326 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 5171 | switch (mcv) { | 5327 | switch (mcv) { |
| 5172 | .dead => unreachable, | 5328 | .dead => unreachable, |
| | 5329 | .register_overflow_unsigned, |
| | 5330 | .register_overflow_signed, |
| | 5331 | => unreachable, |
| 5173 | .ptr_stack_offset => |off| { | 5332 | .ptr_stack_offset => |off| { |
| 5174 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { | 5333 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { |
| 5175 | return self.fail("stack offset too large", .{}); | 5334 | return self.fail("stack offset too large", .{}); |