authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-24 15:03:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-25 01:41:08-07:00
log9684947faae674e093dda4c81d94f51b9568369e
tree2ea16a1a8187e467877fac1dc7d87ede9e1e0898
parent82ad66b2f2bd822e6d195768da9e5247ed4d78cc

compiler: start moving safety-checks into backends

This actually used to be how it worked in stage1, and there was this issue to change it: #2649 So this commit is a reversal to that idea. One motivation for that issue was avoiding emitting the panic handler in compilations that do not have any calls to panic. This commit only resolves the panic handler in the event of a safety check function being emitted, so it does not have that flaw. The other reason given in that issue was for optimizations that elide safety checks. It's yet to be determined whether that was a good idea or not; this can get re-explored when we start adding optimization passes to AIR. This commit adds these AIR instructions, which are only emitted if `backendSupportsFeature(.safety_checked_arithmetic)` is true: * add_safe * sub_safe * mul_safe It removes these nonsensical AIR instructions: * addwrap_optimized * subwrap_optimized * mulwrap_optimized The safety-checked arithmetic functions push the burden of invoking the panic handler into the backend. This makes for a messier compiler implementation, but it reduces the amount of AIR instructions emitted by Sema, which reduces time spent in the secondary bottleneck of the compiler. It also generates more compact LLVM IR, reducing time spent in the primary bottleneck of the compiler. Finally, it eliminates 1 stack allocation per safety-check which was being used to store the resulting tuple. These allocations were going to be annoying when combined with suspension points.

15 files changed, 505 insertions(+), 273 deletions(-)

src/Air.zig+57-27
......@@ -40,15 +40,25 @@ pub const Inst = struct {
4040 /// is the same as both operands.
4141 /// Uses the `bin_op` field.
4242 add,
43 /// Same as `add` with optimized float mode.
43 /// Integer addition. Wrapping is a safety panic.
44 /// Both operands are guaranteed to be the same type, and the result type
45 /// is the same as both operands.
46 /// The panic handler function must be populated before lowering AIR
47 /// that contains this instruction.
48 /// This instruction will only be emitted if the backend has the
49 /// feature `safety_checked_instructions`.
50 /// Uses the `bin_op` field.
51 add_safe,
52 /// Float addition. The instruction is allowed to have equal or more
53 /// mathematical accuracy than strict IEEE-757 float addition.
54 /// If either operand is NaN, the result value is undefined.
55 /// Uses the `bin_op` field.
4456 add_optimized,
45 /// Integer addition. Wrapping is defined to be twos complement wrapping.
57 /// Twos complement wrapping integer addition.
4658 /// Both operands are guaranteed to be the same type, and the result type
4759 /// is the same as both operands.
4860 /// Uses the `bin_op` field.
49 addwrap,
50 /// Same as `addwrap` with optimized float mode.
51 addwrap_optimized,
61 add_wrap,
5262 /// Saturating integer addition.
5363 /// Both operands are guaranteed to be the same type, and the result type
5464 /// is the same as both operands.
......@@ -59,15 +69,25 @@ pub const Inst = struct {
5969 /// is the same as both operands.
6070 /// Uses the `bin_op` field.
6171 sub,
62 /// Same as `sub` with optimized float mode.
72 /// Integer subtraction. Wrapping is a safety panic.
73 /// Both operands are guaranteed to be the same type, and the result type
74 /// is the same as both operands.
75 /// The panic handler function must be populated before lowering AIR
76 /// that contains this instruction.
77 /// This instruction will only be emitted if the backend has the
78 /// feature `safety_checked_instructions`.
79 /// Uses the `bin_op` field.
80 sub_safe,
81 /// Float subtraction. The instruction is allowed to have equal or more
82 /// mathematical accuracy than strict IEEE-757 float subtraction.
83 /// If either operand is NaN, the result value is undefined.
84 /// Uses the `bin_op` field.
6385 sub_optimized,
64 /// Integer subtraction. Wrapping is defined to be twos complement wrapping.
86 /// Twos complement wrapping integer subtraction.
6587 /// Both operands are guaranteed to be the same type, and the result type
6688 /// is the same as both operands.
6789 /// Uses the `bin_op` field.
68 subwrap,
69 /// Same as `sub` with optimized float mode.
70 subwrap_optimized,
90 sub_wrap,
7191 /// Saturating integer subtraction.
7292 /// Both operands are guaranteed to be the same type, and the result type
7393 /// is the same as both operands.
......@@ -78,15 +98,25 @@ pub const Inst = struct {
7898 /// is the same as both operands.
7999 /// Uses the `bin_op` field.
80100 mul,
81 /// Same as `mul` with optimized float mode.
101 /// Integer multiplication. Wrapping is a safety panic.
102 /// Both operands are guaranteed to be the same type, and the result type
103 /// is the same as both operands.
104 /// The panic handler function must be populated before lowering AIR
105 /// that contains this instruction.
106 /// This instruction will only be emitted if the backend has the
107 /// feature `safety_checked_instructions`.
108 /// Uses the `bin_op` field.
109 mul_safe,
110 /// Float multiplication. The instruction is allowed to have equal or more
111 /// mathematical accuracy than strict IEEE-757 float multiplication.
112 /// If either operand is NaN, the result value is undefined.
113 /// Uses the `bin_op` field.
82114 mul_optimized,
83 /// Integer multiplication. Wrapping is defined to be twos complement wrapping.
115 /// Twos complement wrapping integer multiplication.
84116 /// Both operands are guaranteed to be the same type, and the result type
85117 /// is the same as both operands.
86118 /// Uses the `bin_op` field.
87 mulwrap,
88 /// Same as `mulwrap` with optimized float mode.
89 mulwrap_optimized,
119 mul_wrap,
90120 /// Saturating integer multiplication.
91121 /// Both operands are guaranteed to be the same type, and the result type
92122 /// is the same as both operands.
......@@ -1197,13 +1227,16 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
11971227 const datas = air.instructions.items(.data);
11981228 switch (air.instructions.items(.tag)[inst]) {
11991229 .add,
1200 .addwrap,
1230 .add_safe,
1231 .add_wrap,
12011232 .add_sat,
12021233 .sub,
1203 .subwrap,
1234 .sub_safe,
1235 .sub_wrap,
12041236 .sub_sat,
12051237 .mul,
1206 .mulwrap,
1238 .mul_safe,
1239 .mul_wrap,
12071240 .mul_sat,
12081241 .div_float,
12091242 .div_trunc,
......@@ -1224,11 +1257,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
12241257 .bool_and,
12251258 .bool_or,
12261259 .add_optimized,
1227 .addwrap_optimized,
12281260 .sub_optimized,
1229 .subwrap_optimized,
12301261 .mul_optimized,
1231 .mulwrap_optimized,
12321262 .div_float_optimized,
12331263 .div_trunc_optimized,
12341264 .div_floor_optimized,
......@@ -1594,19 +1624,19 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
15941624 => true,
15951625
15961626 .add,
1627 .add_safe,
15971628 .add_optimized,
1598 .addwrap,
1599 .addwrap_optimized,
1629 .add_wrap,
16001630 .add_sat,
16011631 .sub,
1632 .sub_safe,
16021633 .sub_optimized,
1603 .subwrap,
1604 .subwrap_optimized,
1634 .sub_wrap,
16051635 .sub_sat,
16061636 .mul,
1637 .mul_safe,
16071638 .mul_optimized,
1608 .mulwrap,
1609 .mulwrap_optimized,
1639 .mul_wrap,
16101640 .mul_sat,
16111641 .div_float,
16121642 .div_float_optimized,
src/Liveness.zig+15-15
......@@ -232,14 +232,20 @@ pub fn categorizeOperand(
232232 const operand_ref = Air.indexToRef(operand);
233233 switch (air_tags[inst]) {
234234 .add,
235 .addwrap,
235 .add_safe,
236 .add_wrap,
236237 .add_sat,
238 .add_optimized,
237239 .sub,
238 .subwrap,
240 .sub_safe,
241 .sub_wrap,
239242 .sub_sat,
243 .sub_optimized,
240244 .mul,
241 .mulwrap,
245 .mul_safe,
246 .mul_wrap,
242247 .mul_sat,
248 .mul_optimized,
243249 .div_float,
244250 .div_trunc,
245251 .div_floor,
......@@ -267,12 +273,6 @@ pub fn categorizeOperand(
267273 .shr_exact,
268274 .min,
269275 .max,
270 .add_optimized,
271 .addwrap_optimized,
272 .sub_optimized,
273 .subwrap_optimized,
274 .mul_optimized,
275 .mulwrap_optimized,
276276 .div_float_optimized,
277277 .div_trunc_optimized,
278278 .div_floor_optimized,
......@@ -886,19 +886,19 @@ fn analyzeInst(
886886
887887 switch (inst_tags[inst]) {
888888 .add,
889 .add_safe,
889890 .add_optimized,
890 .addwrap,
891 .addwrap_optimized,
891 .add_wrap,
892892 .add_sat,
893893 .sub,
894 .sub_safe,
894895 .sub_optimized,
895 .subwrap,
896 .subwrap_optimized,
896 .sub_wrap,
897897 .sub_sat,
898898 .mul,
899 .mul_safe,
899900 .mul_optimized,
900 .mulwrap,
901 .mulwrap_optimized,
901 .mul_wrap,
902902 .mul_sat,
903903 .div_float,
904904 .div_float_optimized,
src/Liveness/Verify.zig+6-6
......@@ -198,19 +198,19 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
198198
199199 // binary
200200 .add,
201 .add_safe,
201202 .add_optimized,
202 .addwrap,
203 .addwrap_optimized,
203 .add_wrap,
204204 .add_sat,
205205 .sub,
206 .sub_safe,
206207 .sub_optimized,
207 .subwrap,
208 .subwrap_optimized,
208 .sub_wrap,
209209 .sub_sat,
210210 .mul,
211 .mul_safe,
211212 .mul_optimized,
212 .mulwrap,
213 .mulwrap_optimized,
213 .mul_wrap,
214214 .mul_sat,
215215 .div_float,
216216 .div_float_optimized,
src/Module.zig+43
......@@ -187,6 +187,40 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
187187 src: LazySrcLoc,
188188}) = .{},
189189
190panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len,
191panic_func_index: Fn.OptionalIndex = .none,
192null_stack_trace: InternPool.Index = .none,
193
194pub const PanicId = enum {
195 unreach,
196 unwrap_null,
197 cast_to_null,
198 incorrect_alignment,
199 invalid_error_code,
200 cast_truncated_data,
201 negative_to_unsigned,
202 integer_overflow,
203 shl_overflow,
204 shr_overflow,
205 divide_by_zero,
206 exact_division_remainder,
207 inactive_union_field,
208 integer_part_out_of_bounds,
209 corrupt_switch,
210 shift_rhs_too_big,
211 invalid_enum_value,
212 sentinel_mismatch,
213 unwrap_error,
214 index_out_of_bounds,
215 start_index_greater_than_end,
216 for_len_mismatch,
217 memcpy_len_mismatch,
218 memcpy_alias,
219 noreturn_returned,
220
221 pub const len = @typeInfo(PanicId).Enum.fields.len;
222};
223
190224pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
191225
192226pub const CImportError = struct {
......@@ -6651,6 +6685,14 @@ pub const Feature = enum {
66516685 is_named_enum_value,
66526686 error_set_has_value,
66536687 field_reordering,
6688 /// When this feature is supported, the backend supports the following AIR instructions:
6689 /// * `Air.Inst.Tag.add_safe`
6690 /// * `Air.Inst.Tag.sub_safe`
6691 /// * `Air.Inst.Tag.mul_safe`
6692 /// The motivation for this feature is that it makes AIR smaller, and makes it easier
6693 /// to generate better machine code in the backends. All backends should migrate to
6694 /// enabling this feature.
6695 safety_checked_instructions,
66546696};
66556697
66566698pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
......@@ -6665,6 +6707,7 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
66656707 .is_named_enum_value => mod.comp.bin_file.options.use_llvm,
66666708 .error_set_has_value => mod.comp.bin_file.options.use_llvm or mod.comp.bin_file.options.target.isWasm(),
66676709 .field_reordering => mod.comp.bin_file.options.use_llvm,
6710 .safety_checked_instructions => mod.comp.bin_file.options.use_llvm,
66686711 };
66696712}
66706713
src/Sema.zig+117-94
......@@ -9674,7 +9674,7 @@ fn intCast(
96749674 const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty);
96759675 const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);
96769676 const dest_max = try sema.addConstant(dest_max_val);
9677 const diff = try block.addBinOp(.subwrap, dest_max, operand);
9677 const diff = try block.addBinOp(.sub_wrap, dest_max, operand);
96789678
96799679 if (actual_info.signedness == .signed) {
96809680 // Reinterpret the sign-bit as part of the value. This will make
......@@ -15113,7 +15113,11 @@ fn analyzeArithmetic(
1511315113
1511415114 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
1511515115 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
15116 const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: {
15116 const rs: struct {
15117 src: LazySrcLoc,
15118 air_tag: Air.Inst.Tag,
15119 air_tag_safe: Air.Inst.Tag,
15120 } = rs: {
1511715121 switch (zir_tag) {
1511815122 .add, .add_unsafe => {
1511915123 // For integers:intAddSat
......@@ -15162,8 +15166,8 @@ fn analyzeArithmetic(
1516215166 try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod),
1516315167 );
1516415168 }
15165 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15166 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15169 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
15170 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
1516715171 },
1516815172 .addwrap => {
1516915173 // Integers only; floats are checked above.
......@@ -15174,7 +15178,6 @@ fn analyzeArithmetic(
1517415178 return casted_rhs;
1517515179 }
1517615180 }
15177 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
1517815181 if (maybe_rhs_val) |rhs_val| {
1517915182 if (rhs_val.isUndef(mod)) {
1518015183 return sema.addConstUndef(resolved_type);
......@@ -15186,8 +15189,8 @@ fn analyzeArithmetic(
1518615189 return sema.addConstant(
1518715190 try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type),
1518815191 );
15189 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15190 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15192 } else break :rs .{ .src = lhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
15193 } else break :rs .{ .src = rhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
1519115194 },
1519215195 .add_sat => {
1519315196 // Integers only; floats are checked above.
......@@ -15212,8 +15215,16 @@ fn analyzeArithmetic(
1521215215 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod);
1521315216
1521415217 return sema.addConstant(val);
15215 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
15216 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
15218 } else break :rs .{
15219 .src = lhs_src,
15220 .air_tag = .add_sat,
15221 .air_tag_safe = .add_sat,
15222 };
15223 } else break :rs .{
15224 .src = rhs_src,
15225 .air_tag = .add_sat,
15226 .air_tag_safe = .add_sat,
15227 };
1521715228 },
1521815229 .sub => {
1521915230 // For integers:
......@@ -15257,8 +15268,8 @@ fn analyzeArithmetic(
1525715268 try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod),
1525815269 );
1525915270 }
15260 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15261 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15271 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
15272 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
1526215273 },
1526315274 .subwrap => {
1526415275 // Integers only; floats are checked above.
......@@ -15272,7 +15283,6 @@ fn analyzeArithmetic(
1527215283 return casted_lhs;
1527315284 }
1527415285 }
15275 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
1527615286 if (maybe_lhs_val) |lhs_val| {
1527715287 if (lhs_val.isUndef(mod)) {
1527815288 return sema.addConstUndef(resolved_type);
......@@ -15281,8 +15291,8 @@ fn analyzeArithmetic(
1528115291 return sema.addConstant(
1528215292 try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type),
1528315293 );
15284 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15285 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15294 } else break :rs .{ .src = rhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
15295 } else break :rs .{ .src = lhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
1528615296 },
1528715297 .sub_sat => {
1528815298 // Integers only; floats are checked above.
......@@ -15307,8 +15317,8 @@ fn analyzeArithmetic(
1530715317 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);
1530815318
1530915319 return sema.addConstant(val);
15310 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
15311 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
15320 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
15321 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
1531215322 },
1531315323 .mul => {
1531415324 // For integers:
......@@ -15406,8 +15416,8 @@ fn analyzeArithmetic(
1540615416 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod),
1540715417 );
1540815418 }
15409 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15410 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15419 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
15420 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
1541115421 },
1541215422 .mulwrap => {
1541315423 // Integers only; floats are handled above.
......@@ -15435,7 +15445,6 @@ fn analyzeArithmetic(
1543515445 }
1543615446 }
1543715447 }
15438 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
1543915448 if (maybe_rhs_val) |rhs_val| {
1544015449 if (rhs_val.isUndef(mod)) {
1544115450 return sema.addConstUndef(resolved_type);
......@@ -15454,8 +15463,8 @@ fn analyzeArithmetic(
1545415463 return sema.addConstant(
1545515464 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod),
1545615465 );
15457 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
15458 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
15466 } else break :rs .{ .src = lhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
15467 } else break :rs .{ .src = rhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
1545915468 },
1546015469 .mul_sat => {
1546115470 // Integers only; floats are checked above.
......@@ -15505,16 +15514,19 @@ fn analyzeArithmetic(
1550515514 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod);
1550615515
1550715516 return sema.addConstant(val);
15508 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
15509 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
15517 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
15518 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
1551015519 },
1551115520 else => unreachable,
1551215521 }
1551315522 };
1551415523
1551515524 try sema.requireRuntimeBlock(block, src, rs.src);
15516 if (block.wantSafety() and want_safety) {
15517 if (scalar_tag == .Int) {
15525 if (block.wantSafety() and want_safety and scalar_tag == .Int) {
15526 if (mod.backendSupportsFeature(.safety_checked_instructions)) {
15527 _ = try sema.preparePanicId(block, .integer_overflow);
15528 return block.addBinOp(rs.air_tag_safe, casted_lhs, casted_rhs);
15529 } else {
1551815530 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
1551915531 .add => .add_with_overflow,
1552015532 .sub => .sub_with_overflow,
......@@ -24743,39 +24755,67 @@ fn explainWhyTypeIsNotPacked(
2474324755 }
2474424756}
2474524757
24746pub const PanicId = enum {
24747 unreach,
24748 unwrap_null,
24749 cast_to_null,
24750 incorrect_alignment,
24751 invalid_error_code,
24752 cast_truncated_data,
24753 negative_to_unsigned,
24754 integer_overflow,
24755 shl_overflow,
24756 shr_overflow,
24757 divide_by_zero,
24758 exact_division_remainder,
24759 inactive_union_field,
24760 integer_part_out_of_bounds,
24761 corrupt_switch,
24762 shift_rhs_too_big,
24763 invalid_enum_value,
24764 sentinel_mismatch,
24765 unwrap_error,
24766 index_out_of_bounds,
24767 start_index_greater_than_end,
24768 for_len_mismatch,
24769 memcpy_len_mismatch,
24770 memcpy_alias,
24771 noreturn_returned,
24772};
24758fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
24759 const mod = sema.mod;
24760
24761 if (mod.panic_func_index == .none) {
24762 const decl_index = (try sema.getBuiltinDecl(block, "panic"));
24763 // decl_index may be an alias; we must find the decl that actually
24764 // owns the function.
24765 try sema.ensureDeclAnalyzed(decl_index);
24766 const tv = try mod.declPtr(decl_index).typedValue();
24767 assert(tv.ty.zigTypeTag(mod) == .Fn);
24768 assert(try sema.fnHasRuntimeBits(tv.ty));
24769 const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap().?;
24770 try mod.ensureFuncBodyAnalysisQueued(func_index);
24771 mod.panic_func_index = func_index.toOptional();
24772 }
24773
24774 if (mod.null_stack_trace == .none) {
24775 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
24776 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
24777 const target = mod.getTarget();
24778 const ptr_stack_trace_ty = try mod.ptrType(.{
24779 .child = stack_trace_ty.toIntern(),
24780 .flags = .{
24781 .address_space = target_util.defaultAddressSpace(target, .global_constant),
24782 },
24783 });
24784 const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
24785 mod.null_stack_trace = try mod.intern(.{ .opt = .{
24786 .ty = opt_ptr_stack_trace_ty.toIntern(),
24787 .val = .none,
24788 } });
24789 }
24790}
24791
24792/// Backends depend on panic decls being available when lowering safety-checked
24793/// instructions. This function ensures the panic function will be available to
24794/// be called during that time.
24795fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !Module.Decl.Index {
24796 const mod = sema.mod;
24797 const gpa = sema.gpa;
24798 if (mod.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x;
24799
24800 try sema.prepareSimplePanic(block);
24801
24802 const panic_messages_ty = try sema.getBuiltinType("panic_messages");
24803 const msg_decl_index = (try sema.namespaceLookup(
24804 block,
24805 sema.src,
24806 panic_messages_ty.getNamespaceIndex(mod).unwrap().?,
24807 try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)),
24808 )).?;
24809 try sema.ensureDeclAnalyzed(msg_decl_index);
24810 mod.panic_messages[@intFromEnum(panic_id)] = msg_decl_index.toOptional();
24811 return msg_decl_index;
24812}
2477324813
2477424814fn addSafetyCheck(
2477524815 sema: *Sema,
2477624816 parent_block: *Block,
2477724817 ok: Air.Inst.Ref,
24778 panic_id: PanicId,
24818 panic_id: Module.PanicId,
2477924819) !void {
2478024820 const gpa = sema.gpa;
2478124821 assert(!parent_block.is_comptime);
......@@ -24852,32 +24892,19 @@ fn addSafetyCheckExtra(
2485224892 parent_block.instructions.appendAssumeCapacity(block_inst);
2485324893}
2485424894
24855fn panicWithMsg(
24856 sema: *Sema,
24857 block: *Block,
24858 msg_inst: Air.Inst.Ref,
24859) !void {
24895fn panicWithMsg(sema: *Sema, block: *Block, msg_inst: Air.Inst.Ref) !void {
2486024896 const mod = sema.mod;
2486124897
2486224898 if (!mod.backendSupportsFeature(.panic_fn)) {
2486324899 _ = try block.addNoOp(.trap);
2486424900 return;
2486524901 }
24866 const panic_fn = try sema.getBuiltin("panic");
24867 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
24868 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
24869 const target = mod.getTarget();
24870 const ptr_stack_trace_ty = try mod.ptrType(.{
24871 .child = stack_trace_ty.toIntern(),
24872 .flags = .{
24873 .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
24874 },
24875 });
24876 const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
24877 const null_stack_trace = try sema.addConstant((try mod.intern(.{ .opt = .{
24878 .ty = opt_ptr_stack_trace_ty.toIntern(),
24879 .val = .none,
24880 } })).toValue());
24902
24903 try sema.prepareSimplePanic(block);
24904
24905 const panic_func = mod.funcPtrUnwrap(mod.panic_func_index).?;
24906 const panic_fn = try sema.analyzeDeclVal(block, .unneeded, panic_func.owner_decl);
24907 const null_stack_trace = try sema.addConstant(mod.null_stack_trace.toValue());
2488124908
2488224909 const opt_usize_ty = try mod.optionalType(.usize_type);
2488324910 const null_ret_addr = try sema.addConstant((try mod.intern(.{ .opt = .{
......@@ -25036,21 +25063,8 @@ fn safetyCheckFormatted(
2503625063 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
2503725064}
2503825065
25039fn safetyPanic(
25040 sema: *Sema,
25041 block: *Block,
25042 panic_id: PanicId,
25043) CompileError!void {
25044 const mod = sema.mod;
25045 const gpa = sema.gpa;
25046 const panic_messages_ty = try sema.getBuiltinType("panic_messages");
25047 const msg_decl_index = (try sema.namespaceLookup(
25048 block,
25049 sema.src,
25050 panic_messages_ty.getNamespaceIndex(mod).unwrap().?,
25051 try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)),
25052 )).?;
25053
25066fn safetyPanic(sema: *Sema, block: *Block, panic_id: Module.PanicId) CompileError!void {
25067 const msg_decl_index = try sema.preparePanicId(block, panic_id);
2505425068 const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
2505525069 try sema.panicWithMsg(block, msg_inst);
2505625070}
......@@ -35022,6 +35036,7 @@ fn generateUnionTagTypeSimple(
3502235036
3502335037fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
3502435038 const gpa = sema.gpa;
35039 const src = LazySrcLoc.nodeOffset(0);
3502535040
3502635041 var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);
3502735042 defer wip_captures.deinit();
......@@ -35040,6 +35055,14 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
3504035055 block.instructions.deinit(gpa);
3504135056 block.params.deinit(gpa);
3504235057 }
35058
35059 const decl_index = try getBuiltinDecl(sema, &block, name);
35060 return sema.analyzeDeclVal(&block, src, decl_index);
35061}
35062
35063fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Module.Decl.Index {
35064 const gpa = sema.gpa;
35065
3504335066 const src = LazySrcLoc.nodeOffset(0);
3504435067
3504535068 const mod = sema.mod;
......@@ -35047,23 +35070,23 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
3504735070 const std_pkg = mod.main_pkg.table.get("std").?;
3504835071 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
3504935072 const opt_builtin_inst = (try sema.namespaceLookupRef(
35050 &block,
35073 block,
3505135074 src,
3505235075 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,
3505335076 try ip.getOrPutString(gpa, "builtin"),
3505435077 )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
35055 const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src);
35056 const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) {
35078 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst, src);
35079 const builtin_ty = sema.analyzeAsType(block, src, builtin_inst) catch |err| switch (err) {
3505735080 error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}),
3505835081 else => |e| return e,
3505935082 };
35060 const opt_ty_decl = (try sema.namespaceLookup(
35061 &block,
35083 const decl_index = (try sema.namespaceLookup(
35084 block,
3506235085 src,
3506335086 builtin_ty.getNamespaceIndex(mod).unwrap().?,
3506435087 try ip.getOrPutString(gpa, name),
3506535088 )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});
35066 return sema.analyzeDeclVal(&block, src, opt_ty_decl);
35089 return decl_index;
3506735090}
3506835091
3506935092fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
src/arch/aarch64/CodeGen.zig+14-12
......@@ -669,11 +669,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669669 switch (air_tags[inst]) {
670670 // zig fmt: off
671671 .add => try self.airBinOp(inst, .add),
672 .addwrap => try self.airBinOp(inst, .addwrap),
672 .add_wrap => try self.airBinOp(inst, .add_wrap),
673673 .sub => try self.airBinOp(inst, .sub),
674 .subwrap => try self.airBinOp(inst, .subwrap),
674 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
675675 .mul => try self.airBinOp(inst, .mul),
676 .mulwrap => try self.airBinOp(inst, .mulwrap),
676 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
677677 .shl => try self.airBinOp(inst, .shl),
678678 .shl_exact => try self.airBinOp(inst, .shl_exact),
679679 .bool_and => try self.airBinOp(inst, .bool_and),
......@@ -865,11 +865,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
865865 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
866866
867867 .add_optimized,
868 .addwrap_optimized,
869868 .sub_optimized,
870 .subwrap_optimized,
871869 .mul_optimized,
872 .mulwrap_optimized,
873870 .div_float_optimized,
874871 .div_trunc_optimized,
875872 .div_floor_optimized,
......@@ -888,6 +885,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
888885 .int_from_float_optimized,
889886 => return self.fail("TODO implement optimized float mode", .{}),
890887
888 .add_safe,
889 .sub_safe,
890 .mul_safe,
891 => return self.fail("TODO implement safety_checked_instructions", .{}),
892
891893 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
892894 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
893895 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
......@@ -2216,9 +2218,9 @@ fn wrappingArithmetic(
22162218 if (int_info.bits <= 64) {
22172219 // Generate an add/sub/mul
22182220 const result: MCValue = switch (tag) {
2219 .addwrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
2220 .subwrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
2221 .mulwrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
2221 .add_wrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
2222 .sub_wrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
2223 .mul_wrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
22222224 else => unreachable,
22232225 };
22242226
......@@ -2458,9 +2460,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
24582460
24592461 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
24602462
2461 .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2462 .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2463 .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2463 .add_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2464 .sub_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2465 .mul_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
24642466
24652467 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
24662468 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
src/arch/arm/CodeGen.zig+14-12
......@@ -653,11 +653,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
653653 switch (air_tags[inst]) {
654654 // zig fmt: off
655655 .add, => try self.airBinOp(inst, .add),
656 .addwrap => try self.airBinOp(inst, .addwrap),
656 .add_wrap => try self.airBinOp(inst, .add_wrap),
657657 .sub, => try self.airBinOp(inst, .sub),
658 .subwrap => try self.airBinOp(inst, .subwrap),
658 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
659659 .mul => try self.airBinOp(inst, .mul),
660 .mulwrap => try self.airBinOp(inst, .mulwrap),
660 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
661661 .shl => try self.airBinOp(inst, .shl),
662662 .shl_exact => try self.airBinOp(inst, .shl_exact),
663663 .bool_and => try self.airBinOp(inst, .bool_and),
......@@ -849,11 +849,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
849849 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
850850
851851 .add_optimized,
852 .addwrap_optimized,
853852 .sub_optimized,
854 .subwrap_optimized,
855853 .mul_optimized,
856 .mulwrap_optimized,
857854 .div_float_optimized,
858855 .div_trunc_optimized,
859856 .div_floor_optimized,
......@@ -872,6 +869,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
872869 .int_from_float_optimized,
873870 => return self.fail("TODO implement optimized float mode", .{}),
874871
872 .add_safe,
873 .sub_safe,
874 .mul_safe,
875 => return self.fail("TODO implement safety_checked_instructions", .{}),
876
875877 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
876878 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
877879 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
......@@ -1523,9 +1525,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
15231525
15241526 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
15251527
1526 .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1527 .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1528 .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1528 .add_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1529 .sub_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1530 .mul_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
15291531
15301532 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
15311533 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
......@@ -3694,9 +3696,9 @@ fn wrappingArithmetic(
36943696 if (int_info.bits <= 32) {
36953697 // Generate an add/sub/mul
36963698 const result: MCValue = switch (tag) {
3697 .addwrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
3698 .subwrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
3699 .mulwrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
3699 .add_wrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
3700 .sub_wrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
3701 .mul_wrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst),
37003702 else => unreachable,
37013703 };
37023704
src/arch/riscv64/CodeGen.zig+8-6
......@@ -492,12 +492,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
492492 .add => try self.airBinOp(inst, .add),
493493 .sub => try self.airBinOp(inst, .sub),
494494
495 .addwrap => try self.airAddWrap(inst),
495 .add_safe,
496 .sub_safe,
497 .mul_safe,
498 => return self.fail("TODO implement safety_checked_instructions", .{}),
499
500 .add_wrap => try self.airAddWrap(inst),
496501 .add_sat => try self.airAddSat(inst),
497 .subwrap => try self.airSubWrap(inst),
502 .sub_wrap => try self.airSubWrap(inst),
498503 .sub_sat => try self.airSubSat(inst),
499504 .mul => try self.airMul(inst),
500 .mulwrap => try self.airMulWrap(inst),
505 .mul_wrap => try self.airMulWrap(inst),
501506 .mul_sat => try self.airMulSat(inst),
502507 .rem => try self.airRem(inst),
503508 .mod => try self.airMod(inst),
......@@ -679,11 +684,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
679684 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
680685
681686 .add_optimized,
682 .addwrap_optimized,
683687 .sub_optimized,
684 .subwrap_optimized,
685688 .mul_optimized,
686 .mulwrap_optimized,
687689 .div_float_optimized,
688690 .div_trunc_optimized,
689691 .div_floor_optimized,
src/arch/sparc64/CodeGen.zig+14-12
......@@ -508,11 +508,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
508508 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
509509
510510 .add => try self.airBinOp(inst, .add),
511 .addwrap => try self.airBinOp(inst, .addwrap),
511 .add_wrap => try self.airBinOp(inst, .add_wrap),
512512 .sub => try self.airBinOp(inst, .sub),
513 .subwrap => try self.airBinOp(inst, .subwrap),
513 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
514514 .mul => try self.airBinOp(inst, .mul),
515 .mulwrap => try self.airBinOp(inst, .mulwrap),
515 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
516516 .shl => try self.airBinOp(inst, .shl),
517517 .shl_exact => try self.airBinOp(inst, .shl_exact),
518518 .shr => try self.airBinOp(inst, .shr),
......@@ -697,11 +697,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
697697 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
698698
699699 .add_optimized,
700 .addwrap_optimized,
701700 .sub_optimized,
702 .subwrap_optimized,
703701 .mul_optimized,
704 .mulwrap_optimized,
705702 .div_float_optimized,
706703 .div_trunc_optimized,
707704 .div_floor_optimized,
......@@ -720,6 +717,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
720717 .int_from_float_optimized,
721718 => @panic("TODO implement optimized float mode"),
722719
720 .add_safe,
721 .sub_safe,
722 .mul_safe,
723 => @panic("TODO implement safety_checked_instructions"),
724
723725 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724726 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725727 .vector_store_elem => @panic("TODO implement vector_store_elem"),
......@@ -2931,14 +2933,14 @@ fn binOp(
29312933 }
29322934 },
29332935
2934 .addwrap,
2935 .subwrap,
2936 .mulwrap,
2936 .add_wrap,
2937 .sub_wrap,
2938 .mul_wrap,
29372939 => {
29382940 const base_tag: Air.Inst.Tag = switch (tag) {
2939 .addwrap => .add,
2940 .subwrap => .sub,
2941 .mulwrap => .mul,
2941 .add_wrap => .add,
2942 .sub_wrap => .sub,
2943 .mul_wrap => .mul,
29422944 else => unreachable,
29432945 };
29442946
src/arch/wasm/CodeGen.zig+8-6
......@@ -1836,12 +1836,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18361836
18371837 .add => func.airBinOp(inst, .add),
18381838 .add_sat => func.airSatBinOp(inst, .add),
1839 .addwrap => func.airWrapBinOp(inst, .add),
1839 .add_wrap => func.airWrapBinOp(inst, .add),
18401840 .sub => func.airBinOp(inst, .sub),
18411841 .sub_sat => func.airSatBinOp(inst, .sub),
1842 .subwrap => func.airWrapBinOp(inst, .sub),
1842 .sub_wrap => func.airWrapBinOp(inst, .sub),
18431843 .mul => func.airBinOp(inst, .mul),
1844 .mulwrap => func.airWrapBinOp(inst, .mul),
1844 .mul_wrap => func.airWrapBinOp(inst, .mul),
18451845 .div_float, .div_exact => func.airDiv(inst),
18461846 .div_trunc => func.airDivTrunc(inst),
18471847 .div_floor => func.airDivFloor(inst),
......@@ -2041,11 +2041,8 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20412041 .fence => func.airFence(inst),
20422042
20432043 .add_optimized,
2044 .addwrap_optimized,
20452044 .sub_optimized,
2046 .subwrap_optimized,
20472045 .mul_optimized,
2048 .mulwrap_optimized,
20492046 .div_float_optimized,
20502047 .div_trunc_optimized,
20512048 .div_floor_optimized,
......@@ -2064,6 +2061,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20642061 .int_from_float_optimized,
20652062 => return func.fail("TODO implement optimized float mode", .{}),
20662063
2064 .add_safe,
2065 .sub_safe,
2066 .mul_safe,
2067 => return func.fail("TODO implement safety_checked_instructions", .{}),
2068
20672069 .work_item_id,
20682070 .work_group_size,
20692071 .work_group_id,
src/arch/x86_64/CodeGen.zig+40-38
......@@ -1755,9 +1755,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
17551755 => |tag| try self.airUnOp(inst, tag),
17561756
17571757 .add,
1758 .addwrap,
1758 .add_wrap,
17591759 .sub,
1760 .subwrap,
1760 .sub_wrap,
17611761 .bool_and,
17621762 .bool_or,
17631763 .bit_and,
......@@ -1773,7 +1773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
17731773 .shl, .shl_exact => try self.airShlShrBinOp(inst),
17741774
17751775 .mul => try self.airMulDivBinOp(inst),
1776 .mulwrap => try self.airMulDivBinOp(inst),
1776 .mul_wrap => try self.airMulDivBinOp(inst),
17771777 .rem => try self.airMulDivBinOp(inst),
17781778 .mod => try self.airMulDivBinOp(inst),
17791779
......@@ -1947,11 +1947,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
19471947 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
19481948
19491949 .add_optimized,
1950 .addwrap_optimized,
19511950 .sub_optimized,
1952 .subwrap_optimized,
19531951 .mul_optimized,
1954 .mulwrap_optimized,
19551952 .div_float_optimized,
19561953 .div_trunc_optimized,
19571954 .div_floor_optimized,
......@@ -1970,6 +1967,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
19701967 .int_from_float_optimized,
19711968 => return self.fail("TODO implement optimized float mode", .{}),
19721969
1970 .add_safe,
1971 .sub_safe,
1972 .mul_safe,
1973 => return self.fail("TODO implement safety_checked_instructions", .{}),
1974
19731975 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
19741976 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
19751977 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
......@@ -2912,7 +2914,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
29122914 const dst_info = dst_ty.intInfo(mod);
29132915 const src_ty = try mod.intType(dst_info.signedness, switch (tag) {
29142916 else => unreachable,
2915 .mul, .mulwrap => @max(
2917 .mul, .mul_wrap => @max(
29162918 self.activeIntBits(bin_op.lhs),
29172919 self.activeIntBits(bin_op.rhs),
29182920 dst_info.bits / 2,
......@@ -6155,7 +6157,7 @@ fn genMulDivBinOp(
61556157 const src_abi_size = @as(u32, @intCast(src_ty.abiSize(mod)));
61566158 if (switch (tag) {
61576159 else => unreachable,
6158 .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
6160 .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
61596161 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
61606162 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{
61616163 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
......@@ -6172,13 +6174,13 @@ fn genMulDivBinOp(
61726174 const signedness = ty.intInfo(mod).signedness;
61736175 switch (tag) {
61746176 .mul,
6175 .mulwrap,
6177 .mul_wrap,
61766178 .rem,
61776179 .div_trunc,
61786180 .div_exact,
61796181 => {
61806182 const track_inst_rax = switch (tag) {
6181 .mul, .mulwrap => if (dst_abi_size <= 8) maybe_inst else null,
6183 .mul, .mul_wrap => if (dst_abi_size <= 8) maybe_inst else null,
61826184 .div_exact, .div_trunc => maybe_inst,
61836185 else => null,
61846186 };
......@@ -6191,19 +6193,19 @@ fn genMulDivBinOp(
61916193
61926194 try self.genIntMulDivOpMir(switch (signedness) {
61936195 .signed => switch (tag) {
6194 .mul, .mulwrap => .{ .i_, .mul },
6196 .mul, .mul_wrap => .{ .i_, .mul },
61956197 .div_trunc, .div_exact, .rem => .{ .i_, .div },
61966198 else => unreachable,
61976199 },
61986200 .unsigned => switch (tag) {
6199 .mul, .mulwrap => .{ ._, .mul },
6201 .mul, .mul_wrap => .{ ._, .mul },
62006202 .div_trunc, .div_exact, .rem => .{ ._, .div },
62016203 else => unreachable,
62026204 },
62036205 }, ty, lhs, rhs);
62046206
62056207 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
6206 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
6208 .mul, .mul_wrap, .div_trunc, .div_exact => .rax,
62076209 .rem => .rdx,
62086210 else => unreachable,
62096211 }, dst_abi_size) };
......@@ -6347,7 +6349,7 @@ fn genBinOp(
63476349 switch (lhs_mcv) {
63486350 .immediate => |imm| switch (imm) {
63496351 0 => switch (air_tag) {
6350 .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
6352 .sub, .sub_wrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
63516353 else => {},
63526354 },
63536355 else => {},
......@@ -6357,7 +6359,7 @@ fn genBinOp(
63576359
63586360 const is_commutative = switch (air_tag) {
63596361 .add,
6360 .addwrap,
6362 .add_wrap,
63616363 .mul,
63626364 .bool_or,
63636365 .bit_or,
......@@ -6427,11 +6429,11 @@ fn genBinOp(
64276429 if (!vec_op) {
64286430 switch (air_tag) {
64296431 .add,
6430 .addwrap,
6432 .add_wrap,
64316433 => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),
64326434
64336435 .sub,
6434 .subwrap,
6436 .sub_wrap,
64356437 => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),
64366438
64376439 .ptr_add,
......@@ -6649,10 +6651,10 @@ fn genBinOp(
66496651 8 => switch (lhs_ty.vectorLen(mod)) {
66506652 1...16 => switch (air_tag) {
66516653 .add,
6652 .addwrap,
6654 .add_wrap,
66536655 => if (self.hasFeature(.avx)) .{ .vp_b, .add } else .{ .p_b, .add },
66546656 .sub,
6655 .subwrap,
6657 .sub_wrap,
66566658 => if (self.hasFeature(.avx)) .{ .vp_b, .sub } else .{ .p_b, .sub },
66576659 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
66586660 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
......@@ -6689,10 +6691,10 @@ fn genBinOp(
66896691 },
66906692 17...32 => switch (air_tag) {
66916693 .add,
6692 .addwrap,
6694 .add_wrap,
66936695 => if (self.hasFeature(.avx2)) .{ .vp_b, .add } else null,
66946696 .sub,
6695 .subwrap,
6697 .sub_wrap,
66966698 => if (self.hasFeature(.avx2)) .{ .vp_b, .sub } else null,
66976699 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
66986700 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
......@@ -6712,13 +6714,13 @@ fn genBinOp(
67126714 16 => switch (lhs_ty.vectorLen(mod)) {
67136715 1...8 => switch (air_tag) {
67146716 .add,
6715 .addwrap,
6717 .add_wrap,
67166718 => if (self.hasFeature(.avx)) .{ .vp_w, .add } else .{ .p_w, .add },
67176719 .sub,
6718 .subwrap,
6720 .sub_wrap,
67196721 => if (self.hasFeature(.avx)) .{ .vp_w, .sub } else .{ .p_w, .sub },
67206722 .mul,
6721 .mulwrap,
6723 .mul_wrap,
67226724 => if (self.hasFeature(.avx)) .{ .vp_w, .mull } else .{ .p_d, .mull },
67236725 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
67246726 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
......@@ -6747,13 +6749,13 @@ fn genBinOp(
67476749 },
67486750 9...16 => switch (air_tag) {
67496751 .add,
6750 .addwrap,
6752 .add_wrap,
67516753 => if (self.hasFeature(.avx2)) .{ .vp_w, .add } else null,
67526754 .sub,
6753 .subwrap,
6755 .sub_wrap,
67546756 => if (self.hasFeature(.avx2)) .{ .vp_w, .sub } else null,
67556757 .mul,
6756 .mulwrap,
6758 .mul_wrap,
67576759 => if (self.hasFeature(.avx2)) .{ .vp_w, .mull } else null,
67586760 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
67596761 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
......@@ -6773,13 +6775,13 @@ fn genBinOp(
67736775 32 => switch (lhs_ty.vectorLen(mod)) {
67746776 1...4 => switch (air_tag) {
67756777 .add,
6776 .addwrap,
6778 .add_wrap,
67776779 => if (self.hasFeature(.avx)) .{ .vp_d, .add } else .{ .p_d, .add },
67786780 .sub,
6779 .subwrap,
6781 .sub_wrap,
67806782 => if (self.hasFeature(.avx)) .{ .vp_d, .sub } else .{ .p_d, .sub },
67816783 .mul,
6782 .mulwrap,
6784 .mul_wrap,
67836785 => if (self.hasFeature(.avx))
67846786 .{ .vp_d, .mull }
67856787 else if (self.hasFeature(.sse4_1))
......@@ -6821,13 +6823,13 @@ fn genBinOp(
68216823 },
68226824 5...8 => switch (air_tag) {
68236825 .add,
6824 .addwrap,
6826 .add_wrap,
68256827 => if (self.hasFeature(.avx2)) .{ .vp_d, .add } else null,
68266828 .sub,
6827 .subwrap,
6829 .sub_wrap,
68286830 => if (self.hasFeature(.avx2)) .{ .vp_d, .sub } else null,
68296831 .mul,
6830 .mulwrap,
6832 .mul_wrap,
68316833 => if (self.hasFeature(.avx2)) .{ .vp_d, .mull } else null,
68326834 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
68336835 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
......@@ -6847,10 +6849,10 @@ fn genBinOp(
68476849 64 => switch (lhs_ty.vectorLen(mod)) {
68486850 1...2 => switch (air_tag) {
68496851 .add,
6850 .addwrap,
6852 .add_wrap,
68516853 => if (self.hasFeature(.avx)) .{ .vp_q, .add } else .{ .p_q, .add },
68526854 .sub,
6853 .subwrap,
6855 .sub_wrap,
68546856 => if (self.hasFeature(.avx)) .{ .vp_q, .sub } else .{ .p_q, .sub },
68556857 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
68566858 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
......@@ -6859,10 +6861,10 @@ fn genBinOp(
68596861 },
68606862 3...4 => switch (air_tag) {
68616863 .add,
6862 .addwrap,
6864 .add_wrap,
68636865 => if (self.hasFeature(.avx2)) .{ .vp_q, .add } else null,
68646866 .sub,
6865 .subwrap,
6867 .sub_wrap,
68666868 => if (self.hasFeature(.avx2)) .{ .vp_q, .sub } else null,
68676869 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
68686870 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
......@@ -7174,7 +7176,7 @@ fn genBinOp(
71747176 }
71757177
71767178 switch (air_tag) {
7177 .add, .addwrap, .sub, .subwrap, .mul, .mulwrap, .div_float, .div_exact => {},
7179 .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
71787180 .div_trunc, .div_floor => if (self.hasFeature(.sse4_1)) try self.genRound(
71797181 lhs_ty,
71807182 dst_reg,
src/codegen/c.zig+8-6
......@@ -2860,9 +2860,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
28602860 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),
28612861 .mod => try airBinBuiltinCall(f, inst, "mod", .none),
28622862
2863 .addwrap => try airBinBuiltinCall(f, inst, "addw", .bits),
2864 .subwrap => try airBinBuiltinCall(f, inst, "subw", .bits),
2865 .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .bits),
2863 .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits),
2864 .sub_wrap => try airBinBuiltinCall(f, inst, "subw", .bits),
2865 .mul_wrap => try airBinBuiltinCall(f, inst, "mulw", .bits),
28662866
28672867 .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits),
28682868 .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits),
......@@ -3048,11 +3048,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
30483048 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
30493049
30503050 .add_optimized,
3051 .addwrap_optimized,
30523051 .sub_optimized,
3053 .subwrap_optimized,
30543052 .mul_optimized,
3055 .mulwrap_optimized,
30563053 .div_float_optimized,
30573054 .div_trunc_optimized,
30583055 .div_floor_optimized,
......@@ -3071,6 +3068,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
30713068 .int_from_float_optimized,
30723069 => return f.fail("TODO implement optimized float mode", .{}),
30733070
3071 .add_safe,
3072 .sub_safe,
3073 .mul_safe,
3074 => return f.fail("TODO implement safety_checked_instructions", .{}),
3075
30743076 .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}),
30753077 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
30763078 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
src/codegen/llvm.zig+149-27
......@@ -377,6 +377,9 @@ pub const Object = struct {
377377 /// name collision.
378378 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
379379
380 /// Memoizes a null `?usize` value.
381 null_opt_addr: ?*llvm.Value,
382
380383 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type);
381384
382385 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
......@@ -532,6 +535,7 @@ pub const Object = struct {
532535 .di_type_map = .{},
533536 .error_name_table = null,
534537 .extern_collisions = .{},
538 .null_opt_addr = null,
535539 };
536540 }
537541
......@@ -2416,6 +2420,35 @@ pub const Object = struct {
24162420 return buffer.toOwnedSliceSentinel(0);
24172421 }
24182422
2423 fn getNullOptAddr(o: *Object) !*llvm.Value {
2424 if (o.null_opt_addr) |global| return global;
2425
2426 const mod = o.module;
2427 const target = mod.getTarget();
2428 const ty = try mod.intern(.{ .opt_type = .usize_type });
2429 const null_opt_usize = try mod.intern(.{ .opt = .{
2430 .ty = ty,
2431 .val = .none,
2432 } });
2433
2434 const llvm_init = try o.lowerValue(.{
2435 .ty = ty.toType(),
2436 .val = null_opt_usize.toValue(),
2437 });
2438 const global = o.llvm_module.addGlobalInAddressSpace(
2439 llvm_init.typeOf(),
2440 "",
2441 toLlvmGlobalAddressSpace(.generic, target),
2442 );
2443 global.setLinkage(.Internal);
2444 global.setUnnamedAddr(.True);
2445 global.setAlignment(ty.toType().abiAlignment(mod));
2446 global.setInitializer(llvm_init);
2447
2448 o.null_opt_addr = global;
2449 return global;
2450 }
2451
24192452 /// If the llvm function does not exist, create it.
24202453 /// Note that this can be called before the function's semantic analysis has
24212454 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
......@@ -3141,8 +3174,8 @@ pub const Object = struct {
31413174 .func => |func| mod.funcPtr(func.index).owner_decl,
31423175 else => unreachable,
31433176 };
3144 const fn_decl = o.module.declPtr(fn_decl_index);
3145 try o.module.markDeclAlive(fn_decl);
3177 const fn_decl = mod.declPtr(fn_decl_index);
3178 try mod.markDeclAlive(fn_decl);
31463179 return o.resolveLlvmFunction(fn_decl_index);
31473180 },
31483181 .int => {
......@@ -3682,11 +3715,12 @@ pub const Object = struct {
36823715 }
36833716
36843717 fn lowerIntAsPtr(o: *Object, val: Value) Error!*llvm.Value {
3685 switch (o.module.intern_pool.indexToKey(val.toIntern())) {
3718 const mod = o.module;
3719 switch (mod.intern_pool.indexToKey(val.toIntern())) {
36863720 .undef => return o.context.pointerType(0).getUndef(),
36873721 .int => {
36883722 var bigint_space: Value.BigIntSpace = undefined;
3689 const bigint = val.toBigInt(&bigint_space, o.module);
3723 const bigint = val.toBigInt(&bigint_space, mod);
36903724 const llvm_int = lowerBigInt(o, Type.usize, bigint);
36913725 return llvm_int.constIntToPtr(o.context.pointerType(0));
36923726 },
......@@ -4306,15 +4340,25 @@ pub const FuncGen = struct {
43064340
43074341 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
43084342 // zig fmt: off
4309 .add => try self.airAdd(inst, false),
4310 .addwrap => try self.airAddWrap(inst, false),
4311 .add_sat => try self.airAddSat(inst),
4312 .sub => try self.airSub(inst, false),
4313 .subwrap => try self.airSubWrap(inst, false),
4314 .sub_sat => try self.airSubSat(inst),
4315 .mul => try self.airMul(inst, false),
4316 .mulwrap => try self.airMulWrap(inst, false),
4317 .mul_sat => try self.airMulSat(inst),
4343 .add => try self.airAdd(inst, false),
4344 .add_optimized => try self.airAdd(inst, true),
4345 .add_wrap => try self.airAddWrap(inst),
4346 .add_sat => try self.airAddSat(inst),
4347
4348 .sub => try self.airSub(inst, false),
4349 .sub_optimized => try self.airSub(inst, true),
4350 .sub_wrap => try self.airSubWrap(inst),
4351 .sub_sat => try self.airSubSat(inst),
4352
4353 .mul => try self.airMul(inst, false),
4354 .mul_optimized => try self.airMul(inst, true),
4355 .mul_wrap => try self.airMulWrap(inst),
4356 .mul_sat => try self.airMulSat(inst),
4357
4358 .add_safe => try self.airSafeArithmetic(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
4359 .sub_safe => try self.airSafeArithmetic(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
4360 .mul_safe => try self.airSafeArithmetic(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
4361
43184362 .div_float => try self.airDivFloat(inst, false),
43194363 .div_trunc => try self.airDivTrunc(inst, false),
43204364 .div_floor => try self.airDivFloor(inst, false),
......@@ -4331,12 +4375,6 @@ pub const FuncGen = struct {
43314375 .slice => try self.airSlice(inst),
43324376 .mul_add => try self.airMulAdd(inst),
43334377
4334 .add_optimized => try self.airAdd(inst, true),
4335 .addwrap_optimized => try self.airAddWrap(inst, true),
4336 .sub_optimized => try self.airSub(inst, true),
4337 .subwrap_optimized => try self.airSubWrap(inst, true),
4338 .mul_optimized => try self.airMul(inst, true),
4339 .mulwrap_optimized => try self.airMulWrap(inst, true),
43404378 .div_float_optimized => try self.airDivFloat(inst, true),
43414379 .div_trunc_optimized => try self.airDivTrunc(inst, true),
43424380 .div_floor_optimized => try self.airDivFloor(inst, true),
......@@ -4859,6 +4897,48 @@ pub const FuncGen = struct {
48594897 }
48604898 }
48614899
4900 fn buildSimplePanic(fg: *FuncGen, panic_id: Module.PanicId) !void {
4901 const o = fg.dg.object;
4902 const mod = o.module;
4903 const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?;
4904 const msg_decl = mod.declPtr(msg_decl_index);
4905 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);
4906 const msg_ptr = try o.lowerValue(.{
4907 .ty = msg_decl.ty,
4908 .val = msg_decl.val,
4909 });
4910 const null_opt_addr_global = try o.getNullOptAddr();
4911 const target = mod.getTarget();
4912 const llvm_usize = fg.context.intType(target.ptrBitWidth());
4913 // example:
4914 // call fastcc void @test2.panic(
4915 // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
4916 // i64 16, ; msg.len
4917 // ptr null, ; stack trace
4918 // ptr @2, ; addr (null ?usize)
4919 // )
4920 const args = [4]*llvm.Value{
4921 msg_ptr,
4922 llvm_usize.constInt(msg_len, .False),
4923 fg.context.pointerType(0).constNull(),
4924 null_opt_addr_global,
4925 };
4926 const panic_func = mod.funcPtrUnwrap(mod.panic_func_index).?;
4927 const panic_decl = mod.declPtr(panic_func.owner_decl);
4928 const fn_info = mod.typeToFunc(panic_decl.ty).?;
4929 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
4930 _ = fg.builder.buildCall(
4931 try o.lowerType(panic_decl.ty),
4932 panic_global,
4933 &args,
4934 args.len,
4935 toLlvmCallConv(fn_info.cc, target),
4936 .Auto,
4937 "",
4938 );
4939 _ = fg.builder.buildUnreachable();
4940 }
4941
48624942 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
48634943 const o = self.dg.object;
48644944 const mod = o.module;
......@@ -6945,9 +7025,55 @@ pub const FuncGen = struct {
69457025 return self.builder.buildNUWAdd(lhs, rhs, "");
69467026 }
69477027
6948 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
6949 self.builder.setFastMath(want_fast_math);
7028 fn airSafeArithmetic(
7029 fg: *FuncGen,
7030 inst: Air.Inst.Index,
7031 signed_intrinsic: []const u8,
7032 unsigned_intrinsic: []const u8,
7033 ) !?*llvm.Value {
7034 const o = fg.dg.object;
7035 const mod = o.module;
69507036
7037 const bin_op = fg.air.instructions.items(.data)[inst].bin_op;
7038 const lhs = try fg.resolveInst(bin_op.lhs);
7039 const rhs = try fg.resolveInst(bin_op.rhs);
7040 const inst_ty = fg.typeOfIndex(inst);
7041 const scalar_ty = inst_ty.scalarType(mod);
7042 const is_scalar = scalar_ty.ip_index == inst_ty.ip_index;
7043
7044 const intrinsic_name = switch (scalar_ty.isSignedInt(mod)) {
7045 true => signed_intrinsic,
7046 false => unsigned_intrinsic,
7047 };
7048 const llvm_inst_ty = try o.lowerType(inst_ty);
7049 const llvm_fn = fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
7050 const result_struct = fg.builder.buildCall(
7051 llvm_fn.globalGetValueType(),
7052 llvm_fn,
7053 &[_]*llvm.Value{ lhs, rhs },
7054 2,
7055 .Fast,
7056 .Auto,
7057 "",
7058 );
7059 const overflow_bit = fg.builder.buildExtractValue(result_struct, 1, "");
7060 const scalar_overflow_bit = switch (is_scalar) {
7061 true => overflow_bit,
7062 false => fg.builder.buildOrReduce(overflow_bit),
7063 };
7064
7065 const fail_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowFail");
7066 const ok_block = fg.context.appendBasicBlock(fg.llvm_func, "OverflowOk");
7067 _ = fg.builder.buildCondBr(scalar_overflow_bit, fail_block, ok_block);
7068
7069 fg.builder.positionBuilderAtEnd(fail_block);
7070 try fg.buildSimplePanic(.integer_overflow);
7071
7072 fg.builder.positionBuilderAtEnd(ok_block);
7073 return fg.builder.buildExtractValue(result_struct, 0, "");
7074 }
7075
7076 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
69517077 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
69527078 const lhs = try self.resolveInst(bin_op.lhs);
69537079 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -6986,9 +7112,7 @@ pub const FuncGen = struct {
69867112 return self.builder.buildNUWSub(lhs, rhs, "");
69877113 }
69887114
6989 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
6990 self.builder.setFastMath(want_fast_math);
6991
7115 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
69927116 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
69937117 const lhs = try self.resolveInst(bin_op.lhs);
69947118 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7026,9 +7150,7 @@ pub const FuncGen = struct {
70267150 return self.builder.buildNUWMul(lhs, rhs, "");
70277151 }
70287152
7029 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7030 self.builder.setFastMath(want_fast_math);
7031
7153 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
70327154 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
70337155 const lhs = try self.resolveInst(bin_op.lhs);
70347156 const rhs = try self.resolveInst(bin_op.rhs);
src/codegen/spirv.zig+3-3
......@@ -1703,9 +1703,9 @@ pub const DeclGen = struct {
17031703 const air_tags = self.air.instructions.items(.tag);
17041704 const maybe_result_id: ?IdRef = switch (air_tags[inst]) {
17051705 // zig fmt: off
1706 .add, .addwrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true),
1707 .sub, .subwrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true),
1708 .mul, .mulwrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true),
1706 .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true),
1707 .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true),
1708 .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true),
17091709
17101710 .div_float,
17111711 .div_float_optimized,
src/print_air.zig+9-9
......@@ -114,13 +114,19 @@ const Writer = struct {
114114 });
115115 switch (tag) {
116116 .add,
117 .addwrap,
117 .add_optimized,
118 .add_safe,
119 .add_wrap,
118120 .add_sat,
119121 .sub,
120 .subwrap,
122 .sub_optimized,
123 .sub_safe,
124 .sub_wrap,
121125 .sub_sat,
122126 .mul,
123 .mulwrap,
127 .mul_optimized,
128 .mul_safe,
129 .mul_wrap,
124130 .mul_sat,
125131 .div_float,
126132 .div_trunc,
......@@ -152,12 +158,6 @@ const Writer = struct {
152158 .set_union_tag,
153159 .min,
154160 .max,
155 .add_optimized,
156 .addwrap_optimized,
157 .sub_optimized,
158 .subwrap_optimized,
159 .mul_optimized,
160 .mulwrap_optimized,
161161 .div_float_optimized,
162162 .div_trunc_optimized,
163163 .div_floor_optimized,