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 {...@@ -40,15 +40,25 @@ pub const Inst = struct {
40 /// is the same as both operands.40 /// is the same as both operands.
41 /// Uses the `bin_op` field.41 /// Uses the `bin_op` field.
42 add,42 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.
44 add_optimized,56 add_optimized,
45 /// Integer addition. Wrapping is defined to be twos complement wrapping.57 /// Twos complement wrapping integer addition.
46 /// Both operands are guaranteed to be the same type, and the result type58 /// Both operands are guaranteed to be the same type, and the result type
47 /// is the same as both operands.59 /// is the same as both operands.
48 /// Uses the `bin_op` field.60 /// Uses the `bin_op` field.
49 addwrap,61 add_wrap,
50 /// Same as `addwrap` with optimized float mode.
51 addwrap_optimized,
52 /// Saturating integer addition.62 /// Saturating integer addition.
53 /// Both operands are guaranteed to be the same type, and the result type63 /// Both operands are guaranteed to be the same type, and the result type
54 /// is the same as both operands.64 /// is the same as both operands.
...@@ -59,15 +69,25 @@ pub const Inst = struct {...@@ -59,15 +69,25 @@ pub const Inst = struct {
59 /// is the same as both operands.69 /// is the same as both operands.
60 /// Uses the `bin_op` field.70 /// Uses the `bin_op` field.
61 sub,71 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.
63 sub_optimized,85 sub_optimized,
64 /// Integer subtraction. Wrapping is defined to be twos complement wrapping.86 /// Twos complement wrapping integer subtraction.
65 /// Both operands are guaranteed to be the same type, and the result type87 /// Both operands are guaranteed to be the same type, and the result type
66 /// is the same as both operands.88 /// is the same as both operands.
67 /// Uses the `bin_op` field.89 /// Uses the `bin_op` field.
68 subwrap,90 sub_wrap,
69 /// Same as `sub` with optimized float mode.
70 subwrap_optimized,
71 /// Saturating integer subtraction.91 /// Saturating integer subtraction.
72 /// Both operands are guaranteed to be the same type, and the result type92 /// Both operands are guaranteed to be the same type, and the result type
73 /// is the same as both operands.93 /// is the same as both operands.
...@@ -78,15 +98,25 @@ pub const Inst = struct {...@@ -78,15 +98,25 @@ pub const Inst = struct {
78 /// is the same as both operands.98 /// is the same as both operands.
79 /// Uses the `bin_op` field.99 /// Uses the `bin_op` field.
80 mul,100 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.
82 mul_optimized,114 mul_optimized,
83 /// Integer multiplication. Wrapping is defined to be twos complement wrapping.115 /// Twos complement wrapping integer multiplication.
84 /// Both operands are guaranteed to be the same type, and the result type116 /// Both operands are guaranteed to be the same type, and the result type
85 /// is the same as both operands.117 /// is the same as both operands.
86 /// Uses the `bin_op` field.118 /// Uses the `bin_op` field.
87 mulwrap,119 mul_wrap,
88 /// Same as `mulwrap` with optimized float mode.
89 mulwrap_optimized,
90 /// Saturating integer multiplication.120 /// Saturating integer multiplication.
91 /// Both operands are guaranteed to be the same type, and the result type121 /// Both operands are guaranteed to be the same type, and the result type
92 /// is the same as both operands.122 /// is the same as both operands.
...@@ -1197,13 +1227,16 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1197,13 +1227,16 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1197 const datas = air.instructions.items(.data);1227 const datas = air.instructions.items(.data);
1198 switch (air.instructions.items(.tag)[inst]) {1228 switch (air.instructions.items(.tag)[inst]) {
1199 .add,1229 .add,
1200 .addwrap,1230 .add_safe,
1231 .add_wrap,
1201 .add_sat,1232 .add_sat,
1202 .sub,1233 .sub,
1203 .subwrap,1234 .sub_safe,
1235 .sub_wrap,
1204 .sub_sat,1236 .sub_sat,
1205 .mul,1237 .mul,
1206 .mulwrap,1238 .mul_safe,
1239 .mul_wrap,
1207 .mul_sat,1240 .mul_sat,
1208 .div_float,1241 .div_float,
1209 .div_trunc,1242 .div_trunc,
...@@ -1224,11 +1257,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1224,11 +1257,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1224 .bool_and,1257 .bool_and,
1225 .bool_or,1258 .bool_or,
1226 .add_optimized,1259 .add_optimized,
1227 .addwrap_optimized,
1228 .sub_optimized,1260 .sub_optimized,
1229 .subwrap_optimized,
1230 .mul_optimized,1261 .mul_optimized,
1231 .mulwrap_optimized,
1232 .div_float_optimized,1262 .div_float_optimized,
1233 .div_trunc_optimized,1263 .div_trunc_optimized,
1234 .div_floor_optimized,1264 .div_floor_optimized,
...@@ -1594,19 +1624,19 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1594,19 +1624,19 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1594 => true,1624 => true,
15951625
1596 .add,1626 .add,
1627 .add_safe,
1597 .add_optimized,1628 .add_optimized,
1598 .addwrap,1629 .add_wrap,
1599 .addwrap_optimized,
1600 .add_sat,1630 .add_sat,
1601 .sub,1631 .sub,
1632 .sub_safe,
1602 .sub_optimized,1633 .sub_optimized,
1603 .subwrap,1634 .sub_wrap,
1604 .subwrap_optimized,
1605 .sub_sat,1635 .sub_sat,
1606 .mul,1636 .mul,
1637 .mul_safe,
1607 .mul_optimized,1638 .mul_optimized,
1608 .mulwrap,1639 .mul_wrap,
1609 .mulwrap_optimized,
1610 .mul_sat,1640 .mul_sat,
1611 .div_float,1641 .div_float,
1612 .div_float_optimized,1642 .div_float_optimized,
src/Liveness.zig+15-15
...@@ -232,14 +232,20 @@ pub fn categorizeOperand(...@@ -232,14 +232,20 @@ pub fn categorizeOperand(
232 const operand_ref = Air.indexToRef(operand);232 const operand_ref = Air.indexToRef(operand);
233 switch (air_tags[inst]) {233 switch (air_tags[inst]) {
234 .add,234 .add,
235 .addwrap,235 .add_safe,
236 .add_wrap,
236 .add_sat,237 .add_sat,
238 .add_optimized,
237 .sub,239 .sub,
238 .subwrap,240 .sub_safe,
241 .sub_wrap,
239 .sub_sat,242 .sub_sat,
243 .sub_optimized,
240 .mul,244 .mul,
241 .mulwrap,245 .mul_safe,
246 .mul_wrap,
242 .mul_sat,247 .mul_sat,
248 .mul_optimized,
243 .div_float,249 .div_float,
244 .div_trunc,250 .div_trunc,
245 .div_floor,251 .div_floor,
...@@ -267,12 +273,6 @@ pub fn categorizeOperand(...@@ -267,12 +273,6 @@ pub fn categorizeOperand(
267 .shr_exact,273 .shr_exact,
268 .min,274 .min,
269 .max,275 .max,
270 .add_optimized,
271 .addwrap_optimized,
272 .sub_optimized,
273 .subwrap_optimized,
274 .mul_optimized,
275 .mulwrap_optimized,
276 .div_float_optimized,276 .div_float_optimized,
277 .div_trunc_optimized,277 .div_trunc_optimized,
278 .div_floor_optimized,278 .div_floor_optimized,
...@@ -886,19 +886,19 @@ fn analyzeInst(...@@ -886,19 +886,19 @@ fn analyzeInst(
886886
887 switch (inst_tags[inst]) {887 switch (inst_tags[inst]) {
888 .add,888 .add,
889 .add_safe,
889 .add_optimized,890 .add_optimized,
890 .addwrap,891 .add_wrap,
891 .addwrap_optimized,
892 .add_sat,892 .add_sat,
893 .sub,893 .sub,
894 .sub_safe,
894 .sub_optimized,895 .sub_optimized,
895 .subwrap,896 .sub_wrap,
896 .subwrap_optimized,
897 .sub_sat,897 .sub_sat,
898 .mul,898 .mul,
899 .mul_safe,
899 .mul_optimized,900 .mul_optimized,
900 .mulwrap,901 .mul_wrap,
901 .mulwrap_optimized,
902 .mul_sat,902 .mul_sat,
903 .div_float,903 .div_float,
904 .div_float_optimized,904 .div_float_optimized,
src/Liveness/Verify.zig+6-6
...@@ -198,19 +198,19 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -198,19 +198,19 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
198198
199 // binary199 // binary
200 .add,200 .add,
201 .add_safe,
201 .add_optimized,202 .add_optimized,
202 .addwrap,203 .add_wrap,
203 .addwrap_optimized,
204 .add_sat,204 .add_sat,
205 .sub,205 .sub,
206 .sub_safe,
206 .sub_optimized,207 .sub_optimized,
207 .subwrap,208 .sub_wrap,
208 .subwrap_optimized,
209 .sub_sat,209 .sub_sat,
210 .mul,210 .mul,
211 .mul_safe,
211 .mul_optimized,212 .mul_optimized,
212 .mulwrap,213 .mul_wrap,
213 .mulwrap_optimized,
214 .mul_sat,214 .mul_sat,
215 .div_float,215 .div_float,
216 .div_float_optimized,216 .div_float_optimized,
src/Module.zig+43
...@@ -187,6 +187,40 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {...@@ -187,6 +187,40 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
187 src: LazySrcLoc,187 src: LazySrcLoc,
188}) = .{},188}) = .{},
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
190pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);224pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
191225
192pub const CImportError = struct {226pub const CImportError = struct {
...@@ -6651,6 +6685,14 @@ pub const Feature = enum {...@@ -6651,6 +6685,14 @@ pub const Feature = enum {
6651 is_named_enum_value,6685 is_named_enum_value,
6652 error_set_has_value,6686 error_set_has_value,
6653 field_reordering,6687 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,
6654};6696};
66556697
6656pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {6698pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
...@@ -6665,6 +6707,7 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {...@@ -6665,6 +6707,7 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
6665 .is_named_enum_value => mod.comp.bin_file.options.use_llvm,6707 .is_named_enum_value => mod.comp.bin_file.options.use_llvm,
6666 .error_set_has_value => mod.comp.bin_file.options.use_llvm or mod.comp.bin_file.options.target.isWasm(),6708 .error_set_has_value => mod.comp.bin_file.options.use_llvm or mod.comp.bin_file.options.target.isWasm(),
6667 .field_reordering => mod.comp.bin_file.options.use_llvm,6709 .field_reordering => mod.comp.bin_file.options.use_llvm,
6710 .safety_checked_instructions => mod.comp.bin_file.options.use_llvm,
6668 };6711 };
6669}6712}
66706713
src/Sema.zig+117-94
...@@ -9674,7 +9674,7 @@ fn intCast(...@@ -9674,7 +9674,7 @@ fn intCast(
9674 const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty);9674 const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty);
9675 const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);9675 const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);
9676 const dest_max = try sema.addConstant(dest_max_val);9676 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
9679 if (actual_info.signedness == .signed) {9679 if (actual_info.signedness == .signed) {
9680 // Reinterpret the sign-bit as part of the value. This will make9680 // Reinterpret the sign-bit as part of the value. This will make
...@@ -15113,7 +15113,11 @@ fn analyzeArithmetic(...@@ -15113,7 +15113,11 @@ fn analyzeArithmetic(
1511315113
15114 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);15114 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
15115 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);15115 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: {
15117 switch (zir_tag) {15121 switch (zir_tag) {
15118 .add, .add_unsafe => {15122 .add, .add_unsafe => {
15119 // For integers:intAddSat15123 // For integers:intAddSat
...@@ -15162,8 +15166,8 @@ fn analyzeArithmetic(...@@ -15162,8 +15166,8 @@ fn analyzeArithmetic(
15162 try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod),15166 try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod),
15163 );15167 );
15164 }15168 }
15165 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15169 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
15166 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15170 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
15167 },15171 },
15168 .addwrap => {15172 .addwrap => {
15169 // Integers only; floats are checked above.15173 // Integers only; floats are checked above.
...@@ -15174,7 +15178,6 @@ fn analyzeArithmetic(...@@ -15174,7 +15178,6 @@ fn analyzeArithmetic(
15174 return casted_rhs;15178 return casted_rhs;
15175 }15179 }
15176 }15180 }
15177 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
15178 if (maybe_rhs_val) |rhs_val| {15181 if (maybe_rhs_val) |rhs_val| {
15179 if (rhs_val.isUndef(mod)) {15182 if (rhs_val.isUndef(mod)) {
15180 return sema.addConstUndef(resolved_type);15183 return sema.addConstUndef(resolved_type);
...@@ -15186,8 +15189,8 @@ fn analyzeArithmetic(...@@ -15186,8 +15189,8 @@ fn analyzeArithmetic(
15186 return sema.addConstant(15189 return sema.addConstant(
15187 try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type),15190 try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type),
15188 );15191 );
15189 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15192 } else break :rs .{ .src = lhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
15190 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15193 } else break :rs .{ .src = rhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
15191 },15194 },
15192 .add_sat => {15195 .add_sat => {
15193 // Integers only; floats are checked above.15196 // Integers only; floats are checked above.
...@@ -15212,8 +15215,16 @@ fn analyzeArithmetic(...@@ -15212,8 +15215,16 @@ fn analyzeArithmetic(
15212 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod);15215 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod);
1521315216
15214 return sema.addConstant(val);15217 return sema.addConstant(val);
15215 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };15218 } else break :rs .{
15216 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };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 };
15217 },15228 },
15218 .sub => {15229 .sub => {
15219 // For integers:15230 // For integers:
...@@ -15257,8 +15268,8 @@ fn analyzeArithmetic(...@@ -15257,8 +15268,8 @@ fn analyzeArithmetic(
15257 try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod),15268 try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod),
15258 );15269 );
15259 }15270 }
15260 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15271 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
15261 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15272 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
15262 },15273 },
15263 .subwrap => {15274 .subwrap => {
15264 // Integers only; floats are checked above.15275 // Integers only; floats are checked above.
...@@ -15272,7 +15283,6 @@ fn analyzeArithmetic(...@@ -15272,7 +15283,6 @@ fn analyzeArithmetic(
15272 return casted_lhs;15283 return casted_lhs;
15273 }15284 }
15274 }15285 }
15275 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
15276 if (maybe_lhs_val) |lhs_val| {15286 if (maybe_lhs_val) |lhs_val| {
15277 if (lhs_val.isUndef(mod)) {15287 if (lhs_val.isUndef(mod)) {
15278 return sema.addConstUndef(resolved_type);15288 return sema.addConstUndef(resolved_type);
...@@ -15281,8 +15291,8 @@ fn analyzeArithmetic(...@@ -15281,8 +15291,8 @@ fn analyzeArithmetic(
15281 return sema.addConstant(15291 return sema.addConstant(
15282 try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type),15292 try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type),
15283 );15293 );
15284 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15294 } else break :rs .{ .src = rhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
15285 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15295 } else break :rs .{ .src = lhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
15286 },15296 },
15287 .sub_sat => {15297 .sub_sat => {
15288 // Integers only; floats are checked above.15298 // Integers only; floats are checked above.
...@@ -15307,8 +15317,8 @@ fn analyzeArithmetic(...@@ -15307,8 +15317,8 @@ fn analyzeArithmetic(
15307 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);15317 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);
1530815318
15309 return sema.addConstant(val);15319 return sema.addConstant(val);
15310 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };15320 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
15311 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };15321 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
15312 },15322 },
15313 .mul => {15323 .mul => {
15314 // For integers:15324 // For integers:
...@@ -15406,8 +15416,8 @@ fn analyzeArithmetic(...@@ -15406,8 +15416,8 @@ fn analyzeArithmetic(
15406 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod),15416 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod),
15407 );15417 );
15408 }15418 }
15409 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15419 } else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
15410 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15420 } else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
15411 },15421 },
15412 .mulwrap => {15422 .mulwrap => {
15413 // Integers only; floats are handled above.15423 // Integers only; floats are handled above.
...@@ -15435,7 +15445,6 @@ fn analyzeArithmetic(...@@ -15435,7 +15445,6 @@ fn analyzeArithmetic(
15435 }15445 }
15436 }15446 }
15437 }15447 }
15438 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
15439 if (maybe_rhs_val) |rhs_val| {15448 if (maybe_rhs_val) |rhs_val| {
15440 if (rhs_val.isUndef(mod)) {15449 if (rhs_val.isUndef(mod)) {
15441 return sema.addConstUndef(resolved_type);15450 return sema.addConstUndef(resolved_type);
...@@ -15454,8 +15463,8 @@ fn analyzeArithmetic(...@@ -15454,8 +15463,8 @@ fn analyzeArithmetic(
15454 return sema.addConstant(15463 return sema.addConstant(
15455 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod),15464 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod),
15456 );15465 );
15457 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };15466 } else break :rs .{ .src = lhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
15458 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };15467 } else break :rs .{ .src = rhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
15459 },15468 },
15460 .mul_sat => {15469 .mul_sat => {
15461 // Integers only; floats are checked above.15470 // Integers only; floats are checked above.
...@@ -15505,16 +15514,19 @@ fn analyzeArithmetic(...@@ -15505,16 +15514,19 @@ fn analyzeArithmetic(
15505 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod);15514 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod);
1550615515
15507 return sema.addConstant(val);15516 return sema.addConstant(val);
15508 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };15517 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
15509 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };15518 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
15510 },15519 },
15511 else => unreachable,15520 else => unreachable,
15512 }15521 }
15513 };15522 };
1551415523
15515 try sema.requireRuntimeBlock(block, src, rs.src);15524 try sema.requireRuntimeBlock(block, src, rs.src);
15516 if (block.wantSafety() and want_safety) {15525 if (block.wantSafety() and want_safety and scalar_tag == .Int) {
15517 if (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 {
15518 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {15530 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
15519 .add => .add_with_overflow,15531 .add => .add_with_overflow,
15520 .sub => .sub_with_overflow,15532 .sub => .sub_with_overflow,
...@@ -24743,39 +24755,67 @@ fn explainWhyTypeIsNotPacked(...@@ -24743,39 +24755,67 @@ fn explainWhyTypeIsNotPacked(
24743 }24755 }
24744}24756}
2474524757
24746pub const PanicId = enum {24758fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
24747 unreach,24759 const mod = sema.mod;
24748 unwrap_null,24760
24749 cast_to_null,24761 if (mod.panic_func_index == .none) {
24750 incorrect_alignment,24762 const decl_index = (try sema.getBuiltinDecl(block, "panic"));
24751 invalid_error_code,24763 // decl_index may be an alias; we must find the decl that actually
24752 cast_truncated_data,24764 // owns the function.
24753 negative_to_unsigned,24765 try sema.ensureDeclAnalyzed(decl_index);
24754 integer_overflow,24766 const tv = try mod.declPtr(decl_index).typedValue();
24755 shl_overflow,24767 assert(tv.ty.zigTypeTag(mod) == .Fn);
24756 shr_overflow,24768 assert(try sema.fnHasRuntimeBits(tv.ty));
24757 divide_by_zero,24769 const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap().?;
24758 exact_division_remainder,24770 try mod.ensureFuncBodyAnalysisQueued(func_index);
24759 inactive_union_field,24771 mod.panic_func_index = func_index.toOptional();
24760 integer_part_out_of_bounds,24772 }
24761 corrupt_switch,24773
24762 shift_rhs_too_big,24774 if (mod.null_stack_trace == .none) {
24763 invalid_enum_value,24775 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
24764 sentinel_mismatch,24776 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
24765 unwrap_error,24777 const target = mod.getTarget();
24766 index_out_of_bounds,24778 const ptr_stack_trace_ty = try mod.ptrType(.{
24767 start_index_greater_than_end,24779 .child = stack_trace_ty.toIntern(),
24768 for_len_mismatch,24780 .flags = .{
24769 memcpy_len_mismatch,24781 .address_space = target_util.defaultAddressSpace(target, .global_constant),
24770 memcpy_alias,24782 },
24771 noreturn_returned,24783 });
24772};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
24774fn addSafetyCheck(24814fn addSafetyCheck(
24775 sema: *Sema,24815 sema: *Sema,
24776 parent_block: *Block,24816 parent_block: *Block,
24777 ok: Air.Inst.Ref,24817 ok: Air.Inst.Ref,
24778 panic_id: PanicId,24818 panic_id: Module.PanicId,
24779) !void {24819) !void {
24780 const gpa = sema.gpa;24820 const gpa = sema.gpa;
24781 assert(!parent_block.is_comptime);24821 assert(!parent_block.is_comptime);
...@@ -24852,32 +24892,19 @@ fn addSafetyCheckExtra(...@@ -24852,32 +24892,19 @@ fn addSafetyCheckExtra(
24852 parent_block.instructions.appendAssumeCapacity(block_inst);24892 parent_block.instructions.appendAssumeCapacity(block_inst);
24853}24893}
2485424894
24855fn panicWithMsg(24895fn panicWithMsg(sema: *Sema, block: *Block, msg_inst: Air.Inst.Ref) !void {
24856 sema: *Sema,
24857 block: *Block,
24858 msg_inst: Air.Inst.Ref,
24859) !void {
24860 const mod = sema.mod;24896 const mod = sema.mod;
2486124897
24862 if (!mod.backendSupportsFeature(.panic_fn)) {24898 if (!mod.backendSupportsFeature(.panic_fn)) {
24863 _ = try block.addNoOp(.trap);24899 _ = try block.addNoOp(.trap);
24864 return;24900 return;
24865 }24901 }
24866 const panic_fn = try sema.getBuiltin("panic");24902
24867 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");24903 try sema.prepareSimplePanic(block);
24868 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);24904
24869 const target = mod.getTarget();24905 const panic_func = mod.funcPtrUnwrap(mod.panic_func_index).?;
24870 const ptr_stack_trace_ty = try mod.ptrType(.{24906 const panic_fn = try sema.analyzeDeclVal(block, .unneeded, panic_func.owner_decl);
24871 .child = stack_trace_ty.toIntern(),24907 const null_stack_trace = try sema.addConstant(mod.null_stack_trace.toValue());
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());
2488124908
24882 const opt_usize_ty = try mod.optionalType(.usize_type);24909 const opt_usize_ty = try mod.optionalType(.usize_type);
24883 const null_ret_addr = try sema.addConstant((try mod.intern(.{ .opt = .{24910 const null_ret_addr = try sema.addConstant((try mod.intern(.{ .opt = .{
...@@ -25036,21 +25063,8 @@ fn safetyCheckFormatted(...@@ -25036,21 +25063,8 @@ fn safetyCheckFormatted(
25036 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);25063 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
25037}25064}
2503825065
25039fn safetyPanic(25066fn safetyPanic(sema: *Sema, block: *Block, panic_id: Module.PanicId) CompileError!void {
25040 sema: *Sema,25067 const msg_decl_index = try sema.preparePanicId(block, panic_id);
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
25054 const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);25068 const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
25055 try sema.panicWithMsg(block, msg_inst);25069 try sema.panicWithMsg(block, msg_inst);
25056}25070}
...@@ -35022,6 +35036,7 @@ fn generateUnionTagTypeSimple(...@@ -35022,6 +35036,7 @@ fn generateUnionTagTypeSimple(
3502235036
35023fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {35037fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
35024 const gpa = sema.gpa;35038 const gpa = sema.gpa;
35039 const src = LazySrcLoc.nodeOffset(0);
3502535040
35026 var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);35041 var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);
35027 defer wip_captures.deinit();35042 defer wip_captures.deinit();
...@@ -35040,6 +35055,14 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {...@@ -35040,6 +35055,14 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
35040 block.instructions.deinit(gpa);35055 block.instructions.deinit(gpa);
35041 block.params.deinit(gpa);35056 block.params.deinit(gpa);
35042 }35057 }
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
35043 const src = LazySrcLoc.nodeOffset(0);35066 const src = LazySrcLoc.nodeOffset(0);
3504435067
35045 const mod = sema.mod;35068 const mod = sema.mod;
...@@ -35047,23 +35070,23 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {...@@ -35047,23 +35070,23 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
35047 const std_pkg = mod.main_pkg.table.get("std").?;35070 const std_pkg = mod.main_pkg.table.get("std").?;
35048 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;35071 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
35049 const opt_builtin_inst = (try sema.namespaceLookupRef(35072 const opt_builtin_inst = (try sema.namespaceLookupRef(
35050 &block,35073 block,
35051 src,35074 src,
35052 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,35075 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,
35053 try ip.getOrPutString(gpa, "builtin"),35076 try ip.getOrPutString(gpa, "builtin"),
35054 )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");35077 )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
35055 const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src);35078 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) {35079 const builtin_ty = sema.analyzeAsType(block, src, builtin_inst) catch |err| switch (err) {
35057 error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}),35080 error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}),
35058 else => |e| return e,35081 else => |e| return e,
35059 };35082 };
35060 const opt_ty_decl = (try sema.namespaceLookup(35083 const decl_index = (try sema.namespaceLookup(
35061 &block,35084 block,
35062 src,35085 src,
35063 builtin_ty.getNamespaceIndex(mod).unwrap().?,35086 builtin_ty.getNamespaceIndex(mod).unwrap().?,
35064 try ip.getOrPutString(gpa, name),35087 try ip.getOrPutString(gpa, name),
35065 )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});35088 )) 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;
35067}35090}
3506835091
35069fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {35092fn 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 {...@@ -669,11 +669,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669 switch (air_tags[inst]) {669 switch (air_tags[inst]) {
670 // zig fmt: off670 // zig fmt: off
671 .add => try self.airBinOp(inst, .add),671 .add => try self.airBinOp(inst, .add),
672 .addwrap => try self.airBinOp(inst, .addwrap),672 .add_wrap => try self.airBinOp(inst, .add_wrap),
673 .sub => try self.airBinOp(inst, .sub),673 .sub => try self.airBinOp(inst, .sub),
674 .subwrap => try self.airBinOp(inst, .subwrap),674 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
675 .mul => try self.airBinOp(inst, .mul),675 .mul => try self.airBinOp(inst, .mul),
676 .mulwrap => try self.airBinOp(inst, .mulwrap),676 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
677 .shl => try self.airBinOp(inst, .shl),677 .shl => try self.airBinOp(inst, .shl),
678 .shl_exact => try self.airBinOp(inst, .shl_exact),678 .shl_exact => try self.airBinOp(inst, .shl_exact),
679 .bool_and => try self.airBinOp(inst, .bool_and),679 .bool_and => try self.airBinOp(inst, .bool_and),
...@@ -865,11 +865,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -865,11 +865,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
865 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),865 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
866866
867 .add_optimized,867 .add_optimized,
868 .addwrap_optimized,
869 .sub_optimized,868 .sub_optimized,
870 .subwrap_optimized,
871 .mul_optimized,869 .mul_optimized,
872 .mulwrap_optimized,
873 .div_float_optimized,870 .div_float_optimized,
874 .div_trunc_optimized,871 .div_trunc_optimized,
875 .div_floor_optimized,872 .div_floor_optimized,
...@@ -888,6 +885,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -888,6 +885,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
888 .int_from_float_optimized,885 .int_from_float_optimized,
889 => return self.fail("TODO implement optimized float mode", .{}),886 => 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
891 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),893 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
892 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),894 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
893 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),895 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
...@@ -2216,9 +2218,9 @@ fn wrappingArithmetic(...@@ -2216,9 +2218,9 @@ fn wrappingArithmetic(
2216 if (int_info.bits <= 64) {2218 if (int_info.bits <= 64) {
2217 // Generate an add/sub/mul2219 // Generate an add/sub/mul
2218 const result: MCValue = switch (tag) {2220 const result: MCValue = switch (tag) {
2219 .addwrap => try self.addSub(.add, 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),
2220 .subwrap => try self.addSub(.sub, 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),
2221 .mulwrap => try self.mul(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),
2222 else => unreachable,2224 else => unreachable,
2223 };2225 };
22242226
...@@ -2458,9 +2460,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -2458,9 +2460,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
24582460
2459 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),2461 .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),2463 .add_wrap => 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),2464 .sub_wrap => 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),2465 .mul_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
24642466
2465 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),2467 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2466 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),2468 .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 {...@@ -653,11 +653,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
653 switch (air_tags[inst]) {653 switch (air_tags[inst]) {
654 // zig fmt: off654 // zig fmt: off
655 .add, => try self.airBinOp(inst, .add),655 .add, => try self.airBinOp(inst, .add),
656 .addwrap => try self.airBinOp(inst, .addwrap),656 .add_wrap => try self.airBinOp(inst, .add_wrap),
657 .sub, => try self.airBinOp(inst, .sub),657 .sub, => try self.airBinOp(inst, .sub),
658 .subwrap => try self.airBinOp(inst, .subwrap),658 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
659 .mul => try self.airBinOp(inst, .mul),659 .mul => try self.airBinOp(inst, .mul),
660 .mulwrap => try self.airBinOp(inst, .mulwrap),660 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
661 .shl => try self.airBinOp(inst, .shl),661 .shl => try self.airBinOp(inst, .shl),
662 .shl_exact => try self.airBinOp(inst, .shl_exact),662 .shl_exact => try self.airBinOp(inst, .shl_exact),
663 .bool_and => try self.airBinOp(inst, .bool_and),663 .bool_and => try self.airBinOp(inst, .bool_and),
...@@ -849,11 +849,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -849,11 +849,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
849 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),849 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
850850
851 .add_optimized,851 .add_optimized,
852 .addwrap_optimized,
853 .sub_optimized,852 .sub_optimized,
854 .subwrap_optimized,
855 .mul_optimized,853 .mul_optimized,
856 .mulwrap_optimized,
857 .div_float_optimized,854 .div_float_optimized,
858 .div_trunc_optimized,855 .div_trunc_optimized,
859 .div_floor_optimized,856 .div_floor_optimized,
...@@ -872,6 +869,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -872,6 +869,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
872 .int_from_float_optimized,869 .int_from_float_optimized,
873 => return self.fail("TODO implement optimized float mode", .{}),870 => 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
875 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),877 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
876 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),878 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
877 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),879 .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 {...@@ -1523,9 +1525,9 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
15231525
1524 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),1526 .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),1528 .add_wrap => 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),1529 .sub_wrap => 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),1530 .mul_wrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
15291531
1530 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),1532 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1531 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),1533 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
...@@ -3694,9 +3696,9 @@ fn wrappingArithmetic(...@@ -3694,9 +3696,9 @@ fn wrappingArithmetic(
3694 if (int_info.bits <= 32) {3696 if (int_info.bits <= 32) {
3695 // Generate an add/sub/mul3697 // Generate an add/sub/mul
3696 const result: MCValue = switch (tag) {3698 const result: MCValue = switch (tag) {
3697 .addwrap => try self.addSub(.add, 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),
3698 .subwrap => try self.addSub(.sub, 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),
3699 .mulwrap => try self.mul(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),
3700 else => unreachable,3702 else => unreachable,
3701 };3703 };
37023704
src/arch/riscv64/CodeGen.zig+8-6
...@@ -492,12 +492,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -492,12 +492,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
492 .add => try self.airBinOp(inst, .add),492 .add => try self.airBinOp(inst, .add),
493 .sub => try self.airBinOp(inst, .sub),493 .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),
496 .add_sat => try self.airAddSat(inst),501 .add_sat => try self.airAddSat(inst),
497 .subwrap => try self.airSubWrap(inst),502 .sub_wrap => try self.airSubWrap(inst),
498 .sub_sat => try self.airSubSat(inst),503 .sub_sat => try self.airSubSat(inst),
499 .mul => try self.airMul(inst),504 .mul => try self.airMul(inst),
500 .mulwrap => try self.airMulWrap(inst),505 .mul_wrap => try self.airMulWrap(inst),
501 .mul_sat => try self.airMulSat(inst),506 .mul_sat => try self.airMulSat(inst),
502 .rem => try self.airRem(inst),507 .rem => try self.airRem(inst),
503 .mod => try self.airMod(inst),508 .mod => try self.airMod(inst),
...@@ -679,11 +684,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -679,11 +684,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
679 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),684 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
680685
681 .add_optimized,686 .add_optimized,
682 .addwrap_optimized,
683 .sub_optimized,687 .sub_optimized,
684 .subwrap_optimized,
685 .mul_optimized,688 .mul_optimized,
686 .mulwrap_optimized,
687 .div_float_optimized,689 .div_float_optimized,
688 .div_trunc_optimized,690 .div_trunc_optimized,
689 .div_floor_optimized,691 .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 {...@@ -508,11 +508,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
508 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),508 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
509509
510 .add => try self.airBinOp(inst, .add),510 .add => try self.airBinOp(inst, .add),
511 .addwrap => try self.airBinOp(inst, .addwrap),511 .add_wrap => try self.airBinOp(inst, .add_wrap),
512 .sub => try self.airBinOp(inst, .sub),512 .sub => try self.airBinOp(inst, .sub),
513 .subwrap => try self.airBinOp(inst, .subwrap),513 .sub_wrap => try self.airBinOp(inst, .sub_wrap),
514 .mul => try self.airBinOp(inst, .mul),514 .mul => try self.airBinOp(inst, .mul),
515 .mulwrap => try self.airBinOp(inst, .mulwrap),515 .mul_wrap => try self.airBinOp(inst, .mul_wrap),
516 .shl => try self.airBinOp(inst, .shl),516 .shl => try self.airBinOp(inst, .shl),
517 .shl_exact => try self.airBinOp(inst, .shl_exact),517 .shl_exact => try self.airBinOp(inst, .shl_exact),
518 .shr => try self.airBinOp(inst, .shr),518 .shr => try self.airBinOp(inst, .shr),
...@@ -697,11 +697,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -697,11 +697,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
697 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),697 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
698698
699 .add_optimized,699 .add_optimized,
700 .addwrap_optimized,
701 .sub_optimized,700 .sub_optimized,
702 .subwrap_optimized,
703 .mul_optimized,701 .mul_optimized,
704 .mulwrap_optimized,
705 .div_float_optimized,702 .div_float_optimized,
706 .div_trunc_optimized,703 .div_trunc_optimized,
707 .div_floor_optimized,704 .div_floor_optimized,
...@@ -720,6 +717,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -720,6 +717,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
720 .int_from_float_optimized,717 .int_from_float_optimized,
721 => @panic("TODO implement optimized float mode"),718 => @panic("TODO implement optimized float mode"),
722719
720 .add_safe,
721 .sub_safe,
722 .mul_safe,
723 => @panic("TODO implement safety_checked_instructions"),
724
723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),725 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724 .error_set_has_value => @panic("TODO implement error_set_has_value"),726 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725 .vector_store_elem => @panic("TODO implement vector_store_elem"),727 .vector_store_elem => @panic("TODO implement vector_store_elem"),
...@@ -2931,14 +2933,14 @@ fn binOp(...@@ -2931,14 +2933,14 @@ fn binOp(
2931 }2933 }
2932 },2934 },
29332935
2934 .addwrap,2936 .add_wrap,
2935 .subwrap,2937 .sub_wrap,
2936 .mulwrap,2938 .mul_wrap,
2937 => {2939 => {
2938 const base_tag: Air.Inst.Tag = switch (tag) {2940 const base_tag: Air.Inst.Tag = switch (tag) {
2939 .addwrap => .add,2941 .add_wrap => .add,
2940 .subwrap => .sub,2942 .sub_wrap => .sub,
2941 .mulwrap => .mul,2943 .mul_wrap => .mul,
2942 else => unreachable,2944 else => unreachable,
2943 };2945 };
29442946
src/arch/wasm/CodeGen.zig+8-6
...@@ -1836,12 +1836,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1836,12 +1836,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18361836
1837 .add => func.airBinOp(inst, .add),1837 .add => func.airBinOp(inst, .add),
1838 .add_sat => func.airSatBinOp(inst, .add),1838 .add_sat => func.airSatBinOp(inst, .add),
1839 .addwrap => func.airWrapBinOp(inst, .add),1839 .add_wrap => func.airWrapBinOp(inst, .add),
1840 .sub => func.airBinOp(inst, .sub),1840 .sub => func.airBinOp(inst, .sub),
1841 .sub_sat => func.airSatBinOp(inst, .sub),1841 .sub_sat => func.airSatBinOp(inst, .sub),
1842 .subwrap => func.airWrapBinOp(inst, .sub),1842 .sub_wrap => func.airWrapBinOp(inst, .sub),
1843 .mul => func.airBinOp(inst, .mul),1843 .mul => func.airBinOp(inst, .mul),
1844 .mulwrap => func.airWrapBinOp(inst, .mul),1844 .mul_wrap => func.airWrapBinOp(inst, .mul),
1845 .div_float, .div_exact => func.airDiv(inst),1845 .div_float, .div_exact => func.airDiv(inst),
1846 .div_trunc => func.airDivTrunc(inst),1846 .div_trunc => func.airDivTrunc(inst),
1847 .div_floor => func.airDivFloor(inst),1847 .div_floor => func.airDivFloor(inst),
...@@ -2041,11 +2041,8 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2041,11 +2041,8 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2041 .fence => func.airFence(inst),2041 .fence => func.airFence(inst),
20422042
2043 .add_optimized,2043 .add_optimized,
2044 .addwrap_optimized,
2045 .sub_optimized,2044 .sub_optimized,
2046 .subwrap_optimized,
2047 .mul_optimized,2045 .mul_optimized,
2048 .mulwrap_optimized,
2049 .div_float_optimized,2046 .div_float_optimized,
2050 .div_trunc_optimized,2047 .div_trunc_optimized,
2051 .div_floor_optimized,2048 .div_floor_optimized,
...@@ -2064,6 +2061,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2064,6 +2061,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2064 .int_from_float_optimized,2061 .int_from_float_optimized,
2065 => return func.fail("TODO implement optimized float mode", .{}),2062 => 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
2067 .work_item_id,2069 .work_item_id,
2068 .work_group_size,2070 .work_group_size,
2069 .work_group_id,2071 .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 {...@@ -1755,9 +1755,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1755 => |tag| try self.airUnOp(inst, tag),1755 => |tag| try self.airUnOp(inst, tag),
17561756
1757 .add,1757 .add,
1758 .addwrap,1758 .add_wrap,
1759 .sub,1759 .sub,
1760 .subwrap,1760 .sub_wrap,
1761 .bool_and,1761 .bool_and,
1762 .bool_or,1762 .bool_or,
1763 .bit_and,1763 .bit_and,
...@@ -1773,7 +1773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1773,7 +1773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1773 .shl, .shl_exact => try self.airShlShrBinOp(inst),1773 .shl, .shl_exact => try self.airShlShrBinOp(inst),
17741774
1775 .mul => try self.airMulDivBinOp(inst),1775 .mul => try self.airMulDivBinOp(inst),
1776 .mulwrap => try self.airMulDivBinOp(inst),1776 .mul_wrap => try self.airMulDivBinOp(inst),
1777 .rem => try self.airMulDivBinOp(inst),1777 .rem => try self.airMulDivBinOp(inst),
1778 .mod => try self.airMulDivBinOp(inst),1778 .mod => try self.airMulDivBinOp(inst),
17791779
...@@ -1947,11 +1947,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1947,11 +1947,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1947 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),1947 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
19481948
1949 .add_optimized,1949 .add_optimized,
1950 .addwrap_optimized,
1951 .sub_optimized,1950 .sub_optimized,
1952 .subwrap_optimized,
1953 .mul_optimized,1951 .mul_optimized,
1954 .mulwrap_optimized,
1955 .div_float_optimized,1952 .div_float_optimized,
1956 .div_trunc_optimized,1953 .div_trunc_optimized,
1957 .div_floor_optimized,1954 .div_floor_optimized,
...@@ -1970,6 +1967,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1970,6 +1967,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1970 .int_from_float_optimized,1967 .int_from_float_optimized,
1971 => return self.fail("TODO implement optimized float mode", .{}),1968 => 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
1973 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),1975 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
1974 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),1976 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
1975 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),1977 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
...@@ -2912,7 +2914,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2912,7 +2914,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
2912 const dst_info = dst_ty.intInfo(mod);2914 const dst_info = dst_ty.intInfo(mod);
2913 const src_ty = try mod.intType(dst_info.signedness, switch (tag) {2915 const src_ty = try mod.intType(dst_info.signedness, switch (tag) {
2914 else => unreachable,2916 else => unreachable,
2915 .mul, .mulwrap => @max(2917 .mul, .mul_wrap => @max(
2916 self.activeIntBits(bin_op.lhs),2918 self.activeIntBits(bin_op.lhs),
2917 self.activeIntBits(bin_op.rhs),2919 self.activeIntBits(bin_op.rhs),
2918 dst_info.bits / 2,2920 dst_info.bits / 2,
...@@ -6155,7 +6157,7 @@ fn genMulDivBinOp(...@@ -6155,7 +6157,7 @@ fn genMulDivBinOp(
6155 const src_abi_size = @as(u32, @intCast(src_ty.abiSize(mod)));6157 const src_abi_size = @as(u32, @intCast(src_ty.abiSize(mod)));
6156 if (switch (tag) {6158 if (switch (tag) {
6157 else => unreachable,6159 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,
6159 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,6161 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
6160 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{6162 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{
6161 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),6163 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
...@@ -6172,13 +6174,13 @@ fn genMulDivBinOp(...@@ -6172,13 +6174,13 @@ fn genMulDivBinOp(
6172 const signedness = ty.intInfo(mod).signedness;6174 const signedness = ty.intInfo(mod).signedness;
6173 switch (tag) {6175 switch (tag) {
6174 .mul,6176 .mul,
6175 .mulwrap,6177 .mul_wrap,
6176 .rem,6178 .rem,
6177 .div_trunc,6179 .div_trunc,
6178 .div_exact,6180 .div_exact,
6179 => {6181 => {
6180 const track_inst_rax = switch (tag) {6182 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,
6182 .div_exact, .div_trunc => maybe_inst,6184 .div_exact, .div_trunc => maybe_inst,
6183 else => null,6185 else => null,
6184 };6186 };
...@@ -6191,19 +6193,19 @@ fn genMulDivBinOp(...@@ -6191,19 +6193,19 @@ fn genMulDivBinOp(
61916193
6192 try self.genIntMulDivOpMir(switch (signedness) {6194 try self.genIntMulDivOpMir(switch (signedness) {
6193 .signed => switch (tag) {6195 .signed => switch (tag) {
6194 .mul, .mulwrap => .{ .i_, .mul },6196 .mul, .mul_wrap => .{ .i_, .mul },
6195 .div_trunc, .div_exact, .rem => .{ .i_, .div },6197 .div_trunc, .div_exact, .rem => .{ .i_, .div },
6196 else => unreachable,6198 else => unreachable,
6197 },6199 },
6198 .unsigned => switch (tag) {6200 .unsigned => switch (tag) {
6199 .mul, .mulwrap => .{ ._, .mul },6201 .mul, .mul_wrap => .{ ._, .mul },
6200 .div_trunc, .div_exact, .rem => .{ ._, .div },6202 .div_trunc, .div_exact, .rem => .{ ._, .div },
6201 else => unreachable,6203 else => unreachable,
6202 },6204 },
6203 }, ty, lhs, rhs);6205 }, ty, lhs, rhs);
62046206
6205 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {6207 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,
6207 .rem => .rdx,6209 .rem => .rdx,
6208 else => unreachable,6210 else => unreachable,
6209 }, dst_abi_size) };6211 }, dst_abi_size) };
...@@ -6347,7 +6349,7 @@ fn genBinOp(...@@ -6347,7 +6349,7 @@ fn genBinOp(
6347 switch (lhs_mcv) {6349 switch (lhs_mcv) {
6348 .immediate => |imm| switch (imm) {6350 .immediate => |imm| switch (imm) {
6349 0 => switch (air_tag) {6351 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),
6351 else => {},6353 else => {},
6352 },6354 },
6353 else => {},6355 else => {},
...@@ -6357,7 +6359,7 @@ fn genBinOp(...@@ -6357,7 +6359,7 @@ fn genBinOp(
63576359
6358 const is_commutative = switch (air_tag) {6360 const is_commutative = switch (air_tag) {
6359 .add,6361 .add,
6360 .addwrap,6362 .add_wrap,
6361 .mul,6363 .mul,
6362 .bool_or,6364 .bool_or,
6363 .bit_or,6365 .bit_or,
...@@ -6427,11 +6429,11 @@ fn genBinOp(...@@ -6427,11 +6429,11 @@ fn genBinOp(
6427 if (!vec_op) {6429 if (!vec_op) {
6428 switch (air_tag) {6430 switch (air_tag) {
6429 .add,6431 .add,
6430 .addwrap,6432 .add_wrap,
6431 => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),6433 => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),
64326434
6433 .sub,6435 .sub,
6434 .subwrap,6436 .sub_wrap,
6435 => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),6437 => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),
64366438
6437 .ptr_add,6439 .ptr_add,
...@@ -6649,10 +6651,10 @@ fn genBinOp(...@@ -6649,10 +6651,10 @@ fn genBinOp(
6649 8 => switch (lhs_ty.vectorLen(mod)) {6651 8 => switch (lhs_ty.vectorLen(mod)) {
6650 1...16 => switch (air_tag) {6652 1...16 => switch (air_tag) {
6651 .add,6653 .add,
6652 .addwrap,6654 .add_wrap,
6653 => if (self.hasFeature(.avx)) .{ .vp_b, .add } else .{ .p_b, .add },6655 => if (self.hasFeature(.avx)) .{ .vp_b, .add } else .{ .p_b, .add },
6654 .sub,6656 .sub,
6655 .subwrap,6657 .sub_wrap,
6656 => if (self.hasFeature(.avx)) .{ .vp_b, .sub } else .{ .p_b, .sub },6658 => if (self.hasFeature(.avx)) .{ .vp_b, .sub } else .{ .p_b, .sub },
6657 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },6659 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
6658 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },6660 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
...@@ -6689,10 +6691,10 @@ fn genBinOp(...@@ -6689,10 +6691,10 @@ fn genBinOp(
6689 },6691 },
6690 17...32 => switch (air_tag) {6692 17...32 => switch (air_tag) {
6691 .add,6693 .add,
6692 .addwrap,6694 .add_wrap,
6693 => if (self.hasFeature(.avx2)) .{ .vp_b, .add } else null,6695 => if (self.hasFeature(.avx2)) .{ .vp_b, .add } else null,
6694 .sub,6696 .sub,
6695 .subwrap,6697 .sub_wrap,
6696 => if (self.hasFeature(.avx2)) .{ .vp_b, .sub } else null,6698 => if (self.hasFeature(.avx2)) .{ .vp_b, .sub } else null,
6697 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,6699 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
6698 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,6700 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
...@@ -6712,13 +6714,13 @@ fn genBinOp(...@@ -6712,13 +6714,13 @@ fn genBinOp(
6712 16 => switch (lhs_ty.vectorLen(mod)) {6714 16 => switch (lhs_ty.vectorLen(mod)) {
6713 1...8 => switch (air_tag) {6715 1...8 => switch (air_tag) {
6714 .add,6716 .add,
6715 .addwrap,6717 .add_wrap,
6716 => if (self.hasFeature(.avx)) .{ .vp_w, .add } else .{ .p_w, .add },6718 => if (self.hasFeature(.avx)) .{ .vp_w, .add } else .{ .p_w, .add },
6717 .sub,6719 .sub,
6718 .subwrap,6720 .sub_wrap,
6719 => if (self.hasFeature(.avx)) .{ .vp_w, .sub } else .{ .p_w, .sub },6721 => if (self.hasFeature(.avx)) .{ .vp_w, .sub } else .{ .p_w, .sub },
6720 .mul,6722 .mul,
6721 .mulwrap,6723 .mul_wrap,
6722 => if (self.hasFeature(.avx)) .{ .vp_w, .mull } else .{ .p_d, .mull },6724 => if (self.hasFeature(.avx)) .{ .vp_w, .mull } else .{ .p_d, .mull },
6723 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },6725 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
6724 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },6726 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
...@@ -6747,13 +6749,13 @@ fn genBinOp(...@@ -6747,13 +6749,13 @@ fn genBinOp(
6747 },6749 },
6748 9...16 => switch (air_tag) {6750 9...16 => switch (air_tag) {
6749 .add,6751 .add,
6750 .addwrap,6752 .add_wrap,
6751 => if (self.hasFeature(.avx2)) .{ .vp_w, .add } else null,6753 => if (self.hasFeature(.avx2)) .{ .vp_w, .add } else null,
6752 .sub,6754 .sub,
6753 .subwrap,6755 .sub_wrap,
6754 => if (self.hasFeature(.avx2)) .{ .vp_w, .sub } else null,6756 => if (self.hasFeature(.avx2)) .{ .vp_w, .sub } else null,
6755 .mul,6757 .mul,
6756 .mulwrap,6758 .mul_wrap,
6757 => if (self.hasFeature(.avx2)) .{ .vp_w, .mull } else null,6759 => if (self.hasFeature(.avx2)) .{ .vp_w, .mull } else null,
6758 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,6760 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
6759 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,6761 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
...@@ -6773,13 +6775,13 @@ fn genBinOp(...@@ -6773,13 +6775,13 @@ fn genBinOp(
6773 32 => switch (lhs_ty.vectorLen(mod)) {6775 32 => switch (lhs_ty.vectorLen(mod)) {
6774 1...4 => switch (air_tag) {6776 1...4 => switch (air_tag) {
6775 .add,6777 .add,
6776 .addwrap,6778 .add_wrap,
6777 => if (self.hasFeature(.avx)) .{ .vp_d, .add } else .{ .p_d, .add },6779 => if (self.hasFeature(.avx)) .{ .vp_d, .add } else .{ .p_d, .add },
6778 .sub,6780 .sub,
6779 .subwrap,6781 .sub_wrap,
6780 => if (self.hasFeature(.avx)) .{ .vp_d, .sub } else .{ .p_d, .sub },6782 => if (self.hasFeature(.avx)) .{ .vp_d, .sub } else .{ .p_d, .sub },
6781 .mul,6783 .mul,
6782 .mulwrap,6784 .mul_wrap,
6783 => if (self.hasFeature(.avx))6785 => if (self.hasFeature(.avx))
6784 .{ .vp_d, .mull }6786 .{ .vp_d, .mull }
6785 else if (self.hasFeature(.sse4_1))6787 else if (self.hasFeature(.sse4_1))
...@@ -6821,13 +6823,13 @@ fn genBinOp(...@@ -6821,13 +6823,13 @@ fn genBinOp(
6821 },6823 },
6822 5...8 => switch (air_tag) {6824 5...8 => switch (air_tag) {
6823 .add,6825 .add,
6824 .addwrap,6826 .add_wrap,
6825 => if (self.hasFeature(.avx2)) .{ .vp_d, .add } else null,6827 => if (self.hasFeature(.avx2)) .{ .vp_d, .add } else null,
6826 .sub,6828 .sub,
6827 .subwrap,6829 .sub_wrap,
6828 => if (self.hasFeature(.avx2)) .{ .vp_d, .sub } else null,6830 => if (self.hasFeature(.avx2)) .{ .vp_d, .sub } else null,
6829 .mul,6831 .mul,
6830 .mulwrap,6832 .mul_wrap,
6831 => if (self.hasFeature(.avx2)) .{ .vp_d, .mull } else null,6833 => if (self.hasFeature(.avx2)) .{ .vp_d, .mull } else null,
6832 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,6834 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
6833 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,6835 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
...@@ -6847,10 +6849,10 @@ fn genBinOp(...@@ -6847,10 +6849,10 @@ fn genBinOp(
6847 64 => switch (lhs_ty.vectorLen(mod)) {6849 64 => switch (lhs_ty.vectorLen(mod)) {
6848 1...2 => switch (air_tag) {6850 1...2 => switch (air_tag) {
6849 .add,6851 .add,
6850 .addwrap,6852 .add_wrap,
6851 => if (self.hasFeature(.avx)) .{ .vp_q, .add } else .{ .p_q, .add },6853 => if (self.hasFeature(.avx)) .{ .vp_q, .add } else .{ .p_q, .add },
6852 .sub,6854 .sub,
6853 .subwrap,6855 .sub_wrap,
6854 => if (self.hasFeature(.avx)) .{ .vp_q, .sub } else .{ .p_q, .sub },6856 => if (self.hasFeature(.avx)) .{ .vp_q, .sub } else .{ .p_q, .sub },
6855 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },6857 .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" },
6856 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },6858 .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
...@@ -6859,10 +6861,10 @@ fn genBinOp(...@@ -6859,10 +6861,10 @@ fn genBinOp(
6859 },6861 },
6860 3...4 => switch (air_tag) {6862 3...4 => switch (air_tag) {
6861 .add,6863 .add,
6862 .addwrap,6864 .add_wrap,
6863 => if (self.hasFeature(.avx2)) .{ .vp_q, .add } else null,6865 => if (self.hasFeature(.avx2)) .{ .vp_q, .add } else null,
6864 .sub,6866 .sub,
6865 .subwrap,6867 .sub_wrap,
6866 => if (self.hasFeature(.avx2)) .{ .vp_q, .sub } else null,6868 => if (self.hasFeature(.avx2)) .{ .vp_q, .sub } else null,
6867 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,6869 .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
6868 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,6870 .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
...@@ -7174,7 +7176,7 @@ fn genBinOp(...@@ -7174,7 +7176,7 @@ fn genBinOp(
7174 }7176 }
71757177
7176 switch (air_tag) {7178 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 => {},
7178 .div_trunc, .div_floor => if (self.hasFeature(.sse4_1)) try self.genRound(7180 .div_trunc, .div_floor => if (self.hasFeature(.sse4_1)) try self.genRound(
7179 lhs_ty,7181 lhs_ty,
7180 dst_reg,7182 dst_reg,
src/codegen/c.zig+8-6
...@@ -2860,9 +2860,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2860,9 +2860,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2860 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),2860 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),
2861 .mod => try airBinBuiltinCall(f, inst, "mod", .none),2861 .mod => try airBinBuiltinCall(f, inst, "mod", .none),
28622862
2863 .addwrap => try airBinBuiltinCall(f, inst, "addw", .bits),2863 .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits),
2864 .subwrap => try airBinBuiltinCall(f, inst, "subw", .bits),2864 .sub_wrap => try airBinBuiltinCall(f, inst, "subw", .bits),
2865 .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .bits),2865 .mul_wrap => try airBinBuiltinCall(f, inst, "mulw", .bits),
28662866
2867 .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits),2867 .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits),
2868 .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits),2868 .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits),
...@@ -3048,11 +3048,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3048,11 +3048,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3048 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),3048 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
30493049
3050 .add_optimized,3050 .add_optimized,
3051 .addwrap_optimized,
3052 .sub_optimized,3051 .sub_optimized,
3053 .subwrap_optimized,
3054 .mul_optimized,3052 .mul_optimized,
3055 .mulwrap_optimized,
3056 .div_float_optimized,3053 .div_float_optimized,
3057 .div_trunc_optimized,3054 .div_trunc_optimized,
3058 .div_floor_optimized,3055 .div_floor_optimized,
...@@ -3071,6 +3068,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3071,6 +3068,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3071 .int_from_float_optimized,3068 .int_from_float_optimized,
3072 => return f.fail("TODO implement optimized float mode", .{}),3069 => 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
3074 .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}),3076 .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}),
3075 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),3077 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
3076 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),3078 .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 {...@@ -377,6 +377,9 @@ pub const Object = struct {
377 /// name collision.377 /// name collision.
378 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),378 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
379379
380 /// Memoizes a null `?usize` value.
381 null_opt_addr: ?*llvm.Value,
382
380 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type);383 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type);
381384
382 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we385 /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
...@@ -532,6 +535,7 @@ pub const Object = struct {...@@ -532,6 +535,7 @@ pub const Object = struct {
532 .di_type_map = .{},535 .di_type_map = .{},
533 .error_name_table = null,536 .error_name_table = null,
534 .extern_collisions = .{},537 .extern_collisions = .{},
538 .null_opt_addr = null,
535 };539 };
536 }540 }
537541
...@@ -2416,6 +2420,35 @@ pub const Object = struct {...@@ -2416,6 +2420,35 @@ pub const Object = struct {
2416 return buffer.toOwnedSliceSentinel(0);2420 return buffer.toOwnedSliceSentinel(0);
2417 }2421 }
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
2419 /// If the llvm function does not exist, create it.2452 /// If the llvm function does not exist, create it.
2420 /// Note that this can be called before the function's semantic analysis has2453 /// Note that this can be called before the function's semantic analysis has
2421 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.2454 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
...@@ -3141,8 +3174,8 @@ pub const Object = struct {...@@ -3141,8 +3174,8 @@ pub const Object = struct {
3141 .func => |func| mod.funcPtr(func.index).owner_decl,3174 .func => |func| mod.funcPtr(func.index).owner_decl,
3142 else => unreachable,3175 else => unreachable,
3143 };3176 };
3144 const fn_decl = o.module.declPtr(fn_decl_index);3177 const fn_decl = mod.declPtr(fn_decl_index);
3145 try o.module.markDeclAlive(fn_decl);3178 try mod.markDeclAlive(fn_decl);
3146 return o.resolveLlvmFunction(fn_decl_index);3179 return o.resolveLlvmFunction(fn_decl_index);
3147 },3180 },
3148 .int => {3181 .int => {
...@@ -3682,11 +3715,12 @@ pub const Object = struct {...@@ -3682,11 +3715,12 @@ pub const Object = struct {
3682 }3715 }
36833716
3684 fn lowerIntAsPtr(o: *Object, val: Value) Error!*llvm.Value {3717 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())) {
3686 .undef => return o.context.pointerType(0).getUndef(),3720 .undef => return o.context.pointerType(0).getUndef(),
3687 .int => {3721 .int => {
3688 var bigint_space: Value.BigIntSpace = undefined;3722 var bigint_space: Value.BigIntSpace = undefined;
3689 const bigint = val.toBigInt(&bigint_space, o.module);3723 const bigint = val.toBigInt(&bigint_space, mod);
3690 const llvm_int = lowerBigInt(o, Type.usize, bigint);3724 const llvm_int = lowerBigInt(o, Type.usize, bigint);
3691 return llvm_int.constIntToPtr(o.context.pointerType(0));3725 return llvm_int.constIntToPtr(o.context.pointerType(0));
3692 },3726 },
...@@ -4306,15 +4340,25 @@ pub const FuncGen = struct {...@@ -4306,15 +4340,25 @@ pub const FuncGen = struct {
43064340
4307 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {4341 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
4308 // zig fmt: off4342 // zig fmt: off
4309 .add => try self.airAdd(inst, false),4343 .add => try self.airAdd(inst, false),
4310 .addwrap => try self.airAddWrap(inst, false),4344 .add_optimized => try self.airAdd(inst, true),
4311 .add_sat => try self.airAddSat(inst),4345 .add_wrap => try self.airAddWrap(inst),
4312 .sub => try self.airSub(inst, false),4346 .add_sat => try self.airAddSat(inst),
4313 .subwrap => try self.airSubWrap(inst, false),4347
4314 .sub_sat => try self.airSubSat(inst),4348 .sub => try self.airSub(inst, false),
4315 .mul => try self.airMul(inst, false),4349 .sub_optimized => try self.airSub(inst, true),
4316 .mulwrap => try self.airMulWrap(inst, false),4350 .sub_wrap => try self.airSubWrap(inst),
4317 .mul_sat => try self.airMulSat(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
4318 .div_float => try self.airDivFloat(inst, false),4362 .div_float => try self.airDivFloat(inst, false),
4319 .div_trunc => try self.airDivTrunc(inst, false),4363 .div_trunc => try self.airDivTrunc(inst, false),
4320 .div_floor => try self.airDivFloor(inst, false),4364 .div_floor => try self.airDivFloor(inst, false),
...@@ -4331,12 +4375,6 @@ pub const FuncGen = struct {...@@ -4331,12 +4375,6 @@ pub const FuncGen = struct {
4331 .slice => try self.airSlice(inst),4375 .slice => try self.airSlice(inst),
4332 .mul_add => try self.airMulAdd(inst),4376 .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),
4340 .div_float_optimized => try self.airDivFloat(inst, true),4378 .div_float_optimized => try self.airDivFloat(inst, true),
4341 .div_trunc_optimized => try self.airDivTrunc(inst, true),4379 .div_trunc_optimized => try self.airDivTrunc(inst, true),
4342 .div_floor_optimized => try self.airDivFloor(inst, true),4380 .div_floor_optimized => try self.airDivFloor(inst, true),
...@@ -4859,6 +4897,48 @@ pub const FuncGen = struct {...@@ -4859,6 +4897,48 @@ pub const FuncGen = struct {
4859 }4897 }
4860 }4898 }
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
4862 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {4942 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
4863 const o = self.dg.object;4943 const o = self.dg.object;
4864 const mod = o.module;4944 const mod = o.module;
...@@ -6945,9 +7025,55 @@ pub const FuncGen = struct {...@@ -6945,9 +7025,55 @@ pub const FuncGen = struct {
6945 return self.builder.buildNUWAdd(lhs, rhs, "");7025 return self.builder.buildNUWAdd(lhs, rhs, "");
6946 }7026 }
69477027
6948 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {7028 fn airSafeArithmetic(
6949 self.builder.setFastMath(want_fast_math);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 {
6951 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7077 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6952 const lhs = try self.resolveInst(bin_op.lhs);7078 const lhs = try self.resolveInst(bin_op.lhs);
6953 const rhs = try self.resolveInst(bin_op.rhs);7079 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -6986,9 +7112,7 @@ pub const FuncGen = struct {...@@ -6986,9 +7112,7 @@ pub const FuncGen = struct {
6986 return self.builder.buildNUWSub(lhs, rhs, "");7112 return self.builder.buildNUWSub(lhs, rhs, "");
6987 }7113 }
69887114
6989 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {7115 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6990 self.builder.setFastMath(want_fast_math);
6991
6992 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7116 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6993 const lhs = try self.resolveInst(bin_op.lhs);7117 const lhs = try self.resolveInst(bin_op.lhs);
6994 const rhs = try self.resolveInst(bin_op.rhs);7118 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -7026,9 +7150,7 @@ pub const FuncGen = struct {...@@ -7026,9 +7150,7 @@ pub const FuncGen = struct {
7026 return self.builder.buildNUWMul(lhs, rhs, "");7150 return self.builder.buildNUWMul(lhs, rhs, "");
7027 }7151 }
70287152
7029 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {7153 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7030 self.builder.setFastMath(want_fast_math);
7031
7032 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7154 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7033 const lhs = try self.resolveInst(bin_op.lhs);7155 const lhs = try self.resolveInst(bin_op.lhs);
7034 const rhs = try self.resolveInst(bin_op.rhs);7156 const rhs = try self.resolveInst(bin_op.rhs);
src/codegen/spirv.zig+3-3
...@@ -1703,9 +1703,9 @@ pub const DeclGen = struct {...@@ -1703,9 +1703,9 @@ pub const DeclGen = struct {
1703 const air_tags = self.air.instructions.items(.tag);1703 const air_tags = self.air.instructions.items(.tag);
1704 const maybe_result_id: ?IdRef = switch (air_tags[inst]) {1704 const maybe_result_id: ?IdRef = switch (air_tags[inst]) {
1705 // zig fmt: off1705 // zig fmt: off
1706 .add, .addwrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true),1706 .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true),
1707 .sub, .subwrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true),1707 .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true),
1708 .mul, .mulwrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true),1708 .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true),
17091709
1710 .div_float,1710 .div_float,
1711 .div_float_optimized,1711 .div_float_optimized,
src/print_air.zig+9-9
...@@ -114,13 +114,19 @@ const Writer = struct {...@@ -114,13 +114,19 @@ const Writer = struct {
114 });114 });
115 switch (tag) {115 switch (tag) {
116 .add,116 .add,
117 .addwrap,117 .add_optimized,
118 .add_safe,
119 .add_wrap,
118 .add_sat,120 .add_sat,
119 .sub,121 .sub,
120 .subwrap,122 .sub_optimized,
123 .sub_safe,
124 .sub_wrap,
121 .sub_sat,125 .sub_sat,
122 .mul,126 .mul,
123 .mulwrap,127 .mul_optimized,
128 .mul_safe,
129 .mul_wrap,
124 .mul_sat,130 .mul_sat,
125 .div_float,131 .div_float,
126 .div_trunc,132 .div_trunc,
...@@ -152,12 +158,6 @@ const Writer = struct {...@@ -152,12 +158,6 @@ const Writer = struct {
152 .set_union_tag,158 .set_union_tag,
153 .min,159 .min,
154 .max,160 .max,
155 .add_optimized,
156 .addwrap_optimized,
157 .sub_optimized,
158 .subwrap_optimized,
159 .mul_optimized,
160 .mulwrap_optimized,
161 .div_float_optimized,161 .div_float_optimized,
162 .div_trunc_optimized,162 .div_trunc_optimized,
163 .div_floor_optimized,163 .div_floor_optimized,