| author | |
| committer | |
| log | e7f128c2051b086cdb1c03da041745b560bbaa3e |
| tree | 89d06ee67639dfa0260c5beabc344fb33099df0d |
| parent | c9d990d79083f117564837f762c3e225d7fbc5cf |
| parent | 4eb3f50fcf6fcfb6b8013571be00b9eeeb909833 |
| signature |
add `@trap` builtin28 files changed, 203 insertions(+), 34 deletions(-)
doc/langref.html.in+16-1| ... | ... | @@ -7818,12 +7818,14 @@ comptime { |
| 7818 | 7818 | <p> |
| 7819 | 7819 | This function inserts a platform-specific debug trap instruction which causes |
| 7820 | 7820 | debuggers to break there. |
| 7821 | Unlike for {#syntax#}@trap(){#endsyntax#}, execution may continue after this point if the program is resumed. | |
| 7821 | 7822 | </p> |
| 7822 | 7823 | <p> |
| 7823 | 7824 | This function is only valid within function scope. |
| 7824 | 7825 | </p> |
| 7825 | ||
| 7826 | {#see_also|@trap#} | |
| 7826 | 7827 | {#header_close#} |
| 7828 | ||
| 7827 | 7829 | {#header_open|@mulAdd#} |
| 7828 | 7830 | <pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre> |
| 7829 | 7831 | <p> |
| ... | ... | @@ -9393,6 +9395,19 @@ fn List(comptime T: type) type { |
| 9393 | 9395 | </p> |
| 9394 | 9396 | {#header_close#} |
| 9395 | 9397 | |
| 9398 | {#header_open|@trap#} | |
| 9399 | <pre>{#syntax#}@trap() noreturn{#endsyntax#}</pre> | |
| 9400 | <p> | |
| 9401 | This function inserts a platform-specific trap/jam instruction which can be used to exit the program abnormally. | |
| 9402 | This may be implemented by explicitly emitting an invalid instruction which may cause an illegal instruction exception of some sort. | |
| 9403 | Unlike for {#syntax#}@breakpoint(){#endsyntax#}, execution does not continue after this point. | |
| 9404 | </p> | |
| 9405 | <p> | |
| 9406 | This function is only valid within function scope. | |
| 9407 | </p> | |
| 9408 | {#see_also|@breakpoint#} | |
| 9409 | {#header_close#} | |
| 9410 | ||
| 9396 | 9411 | {#header_open|@truncate#} |
| 9397 | 9412 | <pre>{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}</pre> |
| 9398 | 9413 | <p> |
lib/docs/main.js-4| ... | ... | @@ -1187,10 +1187,6 @@ const NAV_MODES = { |
| 1187 | 1187 | payloadHtml += "panic"; |
| 1188 | 1188 | break; |
| 1189 | 1189 | } |
| 1190 | case "set_cold": { | |
| 1191 | payloadHtml += "setCold"; | |
| 1192 | break; | |
| 1193 | } | |
| 1194 | 1190 | case "set_runtime_safety": { |
| 1195 | 1191 | payloadHtml += "setRuntimeSafety"; |
| 1196 | 1192 | break; |
lib/zig.h+8-2| ... | ... | @@ -180,10 +180,16 @@ typedef char bool; |
| 180 | 180 | #define zig_export(sig, symbol, name) __asm(name " = " symbol) |
| 181 | 181 | #endif |
| 182 | 182 | |
| 183 | #if zig_has_builtin(trap) | |
| 184 | #define zig_trap() __builtin_trap() | |
| 185 | #elif defined(__i386__) || defined(__x86_64__) | |
| 186 | #define zig_trap() __asm__ volatile("ud2"); | |
| 187 | #else | |
| 188 | #define zig_trap() raise(SIGILL) | |
| 189 | #endif | |
| 190 | ||
| 183 | 191 | #if zig_has_builtin(debugtrap) |
| 184 | 192 | #define zig_breakpoint() __builtin_debugtrap() |
| 185 | #elif zig_has_builtin(trap) || defined(zig_gnuc) | |
| 186 | #define zig_breakpoint() __builtin_trap() | |
| 187 | 193 | #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) |
| 188 | 194 | #define zig_breakpoint() __debugbreak() |
| 189 | 195 | #elif defined(__i386__) || defined(__x86_64__) |
src/Air.zig+9-1| ... | ... | @@ -232,7 +232,14 @@ pub const Inst = struct { |
| 232 | 232 | /// Result type is always noreturn; no instructions in a block follow this one. |
| 233 | 233 | /// Uses the `br` field. |
| 234 | 234 | br, |
| 235 | /// Lowers to a hardware trap instruction, or the next best thing. | |
| 235 | /// Lowers to a trap/jam instruction causing program abortion. | |
| 236 | /// This may lower to an instruction known to be invalid. | |
| 237 | /// Sometimes, for the lack of a better instruction, `trap` and `breakpoint` may compile down to the same code. | |
| 238 | /// Result type is always noreturn; no instructions in a block follow this one. | |
| 239 | trap, | |
| 240 | /// Lowers to a trap instruction causing debuggers to break here, or the next best thing. | |
| 241 | /// The debugger or something else may allow the program to resume after this point. | |
| 242 | /// Sometimes, for the lack of a better instruction, `trap` and `breakpoint` may compile down to the same code. | |
| 236 | 243 | /// Result type is always void. |
| 237 | 244 | breakpoint, |
| 238 | 245 | /// Yields the return address of the current function. |
| ... | ... | @@ -1186,6 +1193,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1186 | 1193 | .ret, |
| 1187 | 1194 | .ret_load, |
| 1188 | 1195 | .unreach, |
| 1196 | .trap, | |
| 1189 | 1197 | => return Type.initTag(.noreturn), |
| 1190 | 1198 | |
| 1191 | 1199 | .breakpoint, |
src/AstGen.zig+17-4| ... | ... | @@ -2609,8 +2609,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2609 | 2609 | .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { |
| 2610 | 2610 | .breakpoint, |
| 2611 | 2611 | .fence, |
| 2612 | .set_align_stack, | |
| 2613 | 2612 | .set_float_mode, |
| 2613 | .set_align_stack, | |
| 2614 | .set_cold, | |
| 2614 | 2615 | => break :b true, |
| 2615 | 2616 | else => break :b false, |
| 2616 | 2617 | }, |
| ... | ... | @@ -2630,6 +2631,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2630 | 2631 | .repeat_inline, |
| 2631 | 2632 | .panic, |
| 2632 | 2633 | .panic_comptime, |
| 2634 | .trap, | |
| 2633 | 2635 | .check_comptime_control_flow, |
| 2634 | 2636 | => { |
| 2635 | 2637 | noreturn_src_node = statement; |
| ... | ... | @@ -2658,7 +2660,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2658 | 2660 | .validate_struct_init_comptime, |
| 2659 | 2661 | .validate_array_init, |
| 2660 | 2662 | .validate_array_init_comptime, |
| 2661 | .set_cold, | |
| 2662 | 2663 | .set_runtime_safety, |
| 2663 | 2664 | .closure_capture, |
| 2664 | 2665 | .memcpy, |
| ... | ... | @@ -8081,6 +8082,14 @@ fn builtinCall( |
| 8081 | 8082 | }); |
| 8082 | 8083 | return rvalue(gz, ri, result, node); |
| 8083 | 8084 | }, |
| 8085 | .set_cold => { | |
| 8086 | const order = try expr(gz, scope, ri, params[0]); | |
| 8087 | const result = try gz.addExtendedPayload(.set_cold, Zir.Inst.UnNode{ | |
| 8088 | .node = gz.nodeIndexToRelative(node), | |
| 8089 | .operand = order, | |
| 8090 | }); | |
| 8091 | return rvalue(gz, ri, result, node); | |
| 8092 | }, | |
| 8084 | 8093 | |
| 8085 | 8094 | .src => { |
| 8086 | 8095 | const token_starts = tree.tokens.items(.start); |
| ... | ... | @@ -8100,7 +8109,7 @@ fn builtinCall( |
| 8100 | 8109 | .error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node), |
| 8101 | 8110 | .frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node), |
| 8102 | 8111 | .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node), |
| 8103 | .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), | |
| 8112 | .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), | |
| 8104 | 8113 | |
| 8105 | 8114 | .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info), |
| 8106 | 8115 | .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of), |
| ... | ... | @@ -8114,7 +8123,6 @@ fn builtinCall( |
| 8114 | 8123 | .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int), |
| 8115 | 8124 | .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .embed_file), |
| 8116 | 8125 | .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), |
| 8117 | .set_cold => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_cold), | |
| 8118 | 8126 | .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), |
| 8119 | 8127 | .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), |
| 8120 | 8128 | .sin => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sin), |
| ... | ... | @@ -8174,6 +8182,11 @@ fn builtinCall( |
| 8174 | 8182 | try emitDbgNode(gz, node); |
| 8175 | 8183 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic); |
| 8176 | 8184 | }, |
| 8185 | .trap => { | |
| 8186 | try emitDbgNode(gz, node); | |
| 8187 | _ = try gz.addNode(.trap, node); | |
| 8188 | return rvalue(gz, ri, .void_value, node); | |
| 8189 | }, | |
| 8177 | 8190 | .error_to_int => { |
| 8178 | 8191 | const operand = try expr(gz, scope, .{ .rl = .none }, params[0]); |
| 8179 | 8192 | const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{ |
src/Autodoc.zig-1| ... | ... | @@ -1338,7 +1338,6 @@ fn walkInstruction( |
| 1338 | 1338 | .embed_file, |
| 1339 | 1339 | .error_name, |
| 1340 | 1340 | .panic, |
| 1341 | .set_cold, // @check | |
| 1342 | 1341 | .set_runtime_safety, // @check |
| 1343 | 1342 | .sqrt, |
| 1344 | 1343 | .sin, |
src/BuiltinFn.zig+8| ... | ... | @@ -109,6 +109,7 @@ pub const Tag = enum { |
| 109 | 109 | sub_with_overflow, |
| 110 | 110 | tag_name, |
| 111 | 111 | This, |
| 112 | trap, | |
| 112 | 113 | truncate, |
| 113 | 114 | Type, |
| 114 | 115 | type_info, |
| ... | ... | @@ -915,6 +916,13 @@ pub const list = list: { |
| 915 | 916 | .param_count = 0, |
| 916 | 917 | }, |
| 917 | 918 | }, |
| 919 | .{ | |
| 920 | "@trap", | |
| 921 | .{ | |
| 922 | .tag = .trap, | |
| 923 | .param_count = 0, | |
| 924 | }, | |
| 925 | }, | |
| 918 | 926 | .{ |
| 919 | 927 | "@truncate", |
| 920 | 928 | .{ |
src/Liveness.zig+2| ... | ... | @@ -226,6 +226,7 @@ pub fn categorizeOperand( |
| 226 | 226 | .ret_ptr, |
| 227 | 227 | .constant, |
| 228 | 228 | .const_ty, |
| 229 | .trap, | |
| 229 | 230 | .breakpoint, |
| 230 | 231 | .dbg_stmt, |
| 231 | 232 | .dbg_inline_begin, |
| ... | ... | @@ -848,6 +849,7 @@ fn analyzeInst( |
| 848 | 849 | .ret_ptr, |
| 849 | 850 | .constant, |
| 850 | 851 | .const_ty, |
| 852 | .trap, | |
| 851 | 853 | .breakpoint, |
| 852 | 854 | .dbg_stmt, |
| 853 | 855 | .dbg_inline_begin, |
src/Sema.zig+18-9| ... | ... | @@ -1101,6 +1101,7 @@ fn analyzeBodyInner( |
| 1101 | 1101 | .@"unreachable" => break sema.zirUnreachable(block, inst), |
| 1102 | 1102 | .panic => break sema.zirPanic(block, inst, false), |
| 1103 | 1103 | .panic_comptime => break sema.zirPanic(block, inst, true), |
| 1104 | .trap => break sema.zirTrap(block, inst), | |
| 1104 | 1105 | // zig fmt: on |
| 1105 | 1106 | |
| 1106 | 1107 | .extended => ext: { |
| ... | ... | @@ -1167,6 +1168,11 @@ fn analyzeBodyInner( |
| 1167 | 1168 | i += 1; |
| 1168 | 1169 | continue; |
| 1169 | 1170 | }, |
| 1171 | .set_cold => { | |
| 1172 | try sema.zirSetCold(block, extended); | |
| 1173 | i += 1; | |
| 1174 | continue; | |
| 1175 | }, | |
| 1170 | 1176 | .breakpoint => { |
| 1171 | 1177 | if (!block.is_comptime) { |
| 1172 | 1178 | _ = try block.addNoOp(.breakpoint); |
| ... | ... | @@ -1304,11 +1310,6 @@ fn analyzeBodyInner( |
| 1304 | 1310 | i += 1; |
| 1305 | 1311 | continue; |
| 1306 | 1312 | }, |
| 1307 | .set_cold => { | |
| 1308 | try sema.zirSetCold(block, inst); | |
| 1309 | i += 1; | |
| 1310 | continue; | |
| 1311 | }, | |
| 1312 | 1313 | .set_runtime_safety => { |
| 1313 | 1314 | try sema.zirSetRuntimeSafety(block, inst); |
| 1314 | 1315 | i += 1; |
| ... | ... | @@ -5144,6 +5145,14 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo |
| 5144 | 5145 | return always_noreturn; |
| 5145 | 5146 | } |
| 5146 | 5147 | |
| 5148 | fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { | |
| 5149 | const src_node = sema.code.instructions.items(.data)[inst].node; | |
| 5150 | const src = LazySrcLoc.nodeOffset(src_node); | |
| 5151 | sema.src = src; | |
| 5152 | _ = try block.addNoOp(.trap); | |
| 5153 | return always_noreturn; | |
| 5154 | } | |
| 5155 | ||
| 5147 | 5156 | fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5148 | 5157 | const tracy = trace(@src()); |
| 5149 | 5158 | defer tracy.end(); |
| ... | ... | @@ -5721,10 +5730,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5721 | 5730 | gop.value_ptr.* = .{ .alignment = alignment, .src = src }; |
| 5722 | 5731 | } |
| 5723 | 5732 | |
| 5724 | fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | |
| 5725 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 5726 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | |
| 5727 | const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setCold must be comptime-known"); | |
| 5733 | fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { | |
| 5734 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | |
| 5735 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 5736 | const is_cold = try sema.resolveConstBool(block, operand_src, extra.operand, "operand to @setCold must be comptime-known"); | |
| 5728 | 5737 | const func = sema.func orelse return; // does nothing outside a function |
| 5729 | 5738 | func.is_cold = is_cold; |
| 5730 | 5739 | } |
src/Zir.zig+13-8| ... | ... | @@ -617,7 +617,7 @@ pub const Inst = struct { |
| 617 | 617 | /// Uses the `un_node` field. |
| 618 | 618 | typeof_log2_int_type, |
| 619 | 619 | /// Asserts control-flow will not reach this instruction (`unreachable`). |
| 620 | /// Uses the `unreachable` union field. | |
| 620 | /// Uses the `@"unreachable"` union field. | |
| 621 | 621 | @"unreachable", |
| 622 | 622 | /// Bitwise XOR. `^` |
| 623 | 623 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| ... | ... | @@ -808,8 +808,9 @@ pub const Inst = struct { |
| 808 | 808 | panic, |
| 809 | 809 | /// Same as `panic` but forces comptime. |
| 810 | 810 | panic_comptime, |
| 811 | /// Implement builtin `@setCold`. Uses `un_node`. | |
| 812 | set_cold, | |
| 811 | /// Implements `@trap`. | |
| 812 | /// Uses the `node` field. | |
| 813 | trap, | |
| 813 | 814 | /// Implement builtin `@setRuntimeSafety`. Uses `un_node`. |
| 814 | 815 | set_runtime_safety, |
| 815 | 816 | /// Implement builtin `@sqrt`. Uses `un_node`. |
| ... | ... | @@ -1187,7 +1188,6 @@ pub const Inst = struct { |
| 1187 | 1188 | .bool_to_int, |
| 1188 | 1189 | .embed_file, |
| 1189 | 1190 | .error_name, |
| 1190 | .set_cold, | |
| 1191 | 1191 | .set_runtime_safety, |
| 1192 | 1192 | .sqrt, |
| 1193 | 1193 | .sin, |
| ... | ... | @@ -1277,6 +1277,7 @@ pub const Inst = struct { |
| 1277 | 1277 | .repeat_inline, |
| 1278 | 1278 | .panic, |
| 1279 | 1279 | .panic_comptime, |
| 1280 | .trap, | |
| 1280 | 1281 | .check_comptime_control_flow, |
| 1281 | 1282 | => true, |
| 1282 | 1283 | }; |
| ... | ... | @@ -1323,7 +1324,6 @@ pub const Inst = struct { |
| 1323 | 1324 | .validate_deref, |
| 1324 | 1325 | .@"export", |
| 1325 | 1326 | .export_value, |
| 1326 | .set_cold, | |
| 1327 | 1327 | .set_runtime_safety, |
| 1328 | 1328 | .memcpy, |
| 1329 | 1329 | .memset, |
| ... | ... | @@ -1553,6 +1553,7 @@ pub const Inst = struct { |
| 1553 | 1553 | .repeat_inline, |
| 1554 | 1554 | .panic, |
| 1555 | 1555 | .panic_comptime, |
| 1556 | .trap, | |
| 1556 | 1557 | .for_len, |
| 1557 | 1558 | .@"try", |
| 1558 | 1559 | .try_ptr, |
| ... | ... | @@ -1561,7 +1562,7 @@ pub const Inst = struct { |
| 1561 | 1562 | => false, |
| 1562 | 1563 | |
| 1563 | 1564 | .extended => switch (data.extended.opcode) { |
| 1564 | .breakpoint, .fence => true, | |
| 1565 | .fence, .set_cold, .breakpoint => true, | |
| 1565 | 1566 | else => false, |
| 1566 | 1567 | }, |
| 1567 | 1568 | }; |
| ... | ... | @@ -1750,7 +1751,7 @@ pub const Inst = struct { |
| 1750 | 1751 | .error_name = .un_node, |
| 1751 | 1752 | .panic = .un_node, |
| 1752 | 1753 | .panic_comptime = .un_node, |
| 1753 | .set_cold = .un_node, | |
| 1754 | .trap = .node, | |
| 1754 | 1755 | .set_runtime_safety = .un_node, |
| 1755 | 1756 | .sqrt = .un_node, |
| 1756 | 1757 | .sin = .un_node, |
| ... | ... | @@ -1979,11 +1980,15 @@ pub const Inst = struct { |
| 1979 | 1980 | /// Implement builtin `@setAlignStack`. |
| 1980 | 1981 | /// `operand` is payload index to `UnNode`. |
| 1981 | 1982 | set_align_stack, |
| 1983 | /// Implements `@setCold`. | |
| 1984 | /// `operand` is payload index to `UnNode`. | |
| 1985 | set_cold, | |
| 1982 | 1986 | /// Implements the `@errSetCast` builtin. |
| 1983 | 1987 | /// `operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand. |
| 1984 | 1988 | err_set_cast, |
| 1985 | 1989 | /// `operand` is payload index to `UnNode`. |
| 1986 | 1990 | await_nosuspend, |
| 1991 | /// Implements `@breakpoint`. | |
| 1987 | 1992 | /// `operand` is `src_node: i32`. |
| 1988 | 1993 | breakpoint, |
| 1989 | 1994 | /// Implements the `@select` builtin. |
| ... | ... | @@ -1997,7 +2002,7 @@ pub const Inst = struct { |
| 1997 | 2002 | int_to_error, |
| 1998 | 2003 | /// Implement builtin `@Type`. |
| 1999 | 2004 | /// `operand` is payload index to `UnNode`. |
| 2000 | /// `small` contains `NameStrategy | |
| 2005 | /// `small` contains `NameStrategy`. | |
| 2001 | 2006 | reify, |
| 2002 | 2007 | /// Implements the `@asyncCall` builtin. |
| 2003 | 2008 | /// `operand` is payload index to `AsyncCall`. |
src/arch/aarch64/CodeGen.zig+10-1| ... | ... | @@ -733,6 +733,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 733 | 733 | .bitcast => try self.airBitCast(inst), |
| 734 | 734 | .block => try self.airBlock(inst), |
| 735 | 735 | .br => try self.airBr(inst), |
| 736 | .trap => try self.airTrap(), | |
| 736 | 737 | .breakpoint => try self.airBreakpoint(), |
| 737 | 738 | .ret_addr => try self.airRetAddr(inst), |
| 738 | 739 | .frame_addr => try self.airFrameAddress(inst), |
| ... | ... | @@ -4194,10 +4195,18 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4194 | 4195 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 4195 | 4196 | } |
| 4196 | 4197 | |
| 4198 | fn airTrap(self: *Self) !void { | |
| 4199 | _ = try self.addInst(.{ | |
| 4200 | .tag = .brk, | |
| 4201 | .data = .{ .imm16 = 0x0001 }, | |
| 4202 | }); | |
| 4203 | return self.finishAirBookkeeping(); | |
| 4204 | } | |
| 4205 | ||
| 4197 | 4206 | fn airBreakpoint(self: *Self) !void { |
| 4198 | 4207 | _ = try self.addInst(.{ |
| 4199 | 4208 | .tag = .brk, |
| 4200 | .data = .{ .imm16 = 1 }, | |
| 4209 | .data = .{ .imm16 = 0xf000 }, | |
| 4201 | 4210 | }); |
| 4202 | 4211 | return self.finishAirBookkeeping(); |
| 4203 | 4212 | } |
src/arch/arm/CodeGen.zig+9| ... | ... | @@ -717,6 +717,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 717 | 717 | .bitcast => try self.airBitCast(inst), |
| 718 | 718 | .block => try self.airBlock(inst), |
| 719 | 719 | .br => try self.airBr(inst), |
| 720 | .trap => try self.airTrap(), | |
| 720 | 721 | .breakpoint => try self.airBreakpoint(), |
| 721 | 722 | .ret_addr => try self.airRetAddr(inst), |
| 722 | 723 | .frame_addr => try self.airFrameAddress(inst), |
| ... | ... | @@ -4142,6 +4143,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4142 | 4143 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 4143 | 4144 | } |
| 4144 | 4145 | |
| 4146 | fn airTrap(self: *Self) !void { | |
| 4147 | _ = try self.addInst(.{ | |
| 4148 | .tag = .undefined_instruction, | |
| 4149 | .data = .{ .nop = {} }, | |
| 4150 | }); | |
| 4151 | return self.finishAirBookkeeping(); | |
| 4152 | } | |
| 4153 | ||
| 4145 | 4154 | fn airBreakpoint(self: *Self) !void { |
| 4146 | 4155 | _ = try self.addInst(.{ |
| 4147 | 4156 | .tag = .bkpt, |
src/arch/arm/Emit.zig+7-2| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //! This file contains the functionality for lowering AArch64 MIR into | |
| 1 | //! This file contains the functionality for lowering AArch32 MIR into | |
| 2 | 2 | //! machine code |
| 3 | 3 | |
| 4 | 4 | const Emit = @This(); |
| ... | ... | @@ -15,7 +15,7 @@ const Target = std.Target; |
| 15 | 15 | const assert = std.debug.assert; |
| 16 | 16 | const Instruction = bits.Instruction; |
| 17 | 17 | const Register = bits.Register; |
| 18 | const log = std.log.scoped(.aarch64_emit); | |
| 18 | const log = std.log.scoped(.aarch32_emit); | |
| 19 | 19 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 20 | 20 | const CodeGen = @import("CodeGen.zig"); |
| 21 | 21 | |
| ... | ... | @@ -100,6 +100,7 @@ pub fn emitMir( |
| 100 | 100 | |
| 101 | 101 | .b => try emit.mirBranch(inst), |
| 102 | 102 | |
| 103 | .undefined_instruction => try emit.mirUndefinedInstruction(), | |
| 103 | 104 | .bkpt => try emit.mirExceptionGeneration(inst), |
| 104 | 105 | |
| 105 | 106 | .blx => try emit.mirBranchExchange(inst), |
| ... | ... | @@ -494,6 +495,10 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 494 | 495 | } |
| 495 | 496 | } |
| 496 | 497 | |
| 498 | fn mirUndefinedInstruction(emit: *Emit) !void { | |
| 499 | try emit.writeInstruction(Instruction.undefinedInstruction()); | |
| 500 | } | |
| 501 | ||
| 497 | 502 | fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 498 | 503 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 499 | 504 | const imm16 = emit.mir.instructions.items(.data)[inst].imm16; |
src/arch/arm/Mir.zig+2| ... | ... | @@ -35,6 +35,8 @@ pub const Inst = struct { |
| 35 | 35 | asr, |
| 36 | 36 | /// Branch |
| 37 | 37 | b, |
| 38 | /// Undefined instruction | |
| 39 | undefined_instruction, | |
| 38 | 40 | /// Breakpoint |
| 39 | 41 | bkpt, |
| 40 | 42 | /// Branch with Link and Exchange |
src/arch/arm/bits.zig+11| ... | ... | @@ -307,6 +307,9 @@ pub const Instruction = union(enum) { |
| 307 | 307 | fixed: u4 = 0b1111, |
| 308 | 308 | cond: u4, |
| 309 | 309 | }, |
| 310 | undefined_instruction: packed struct { | |
| 311 | imm32: u32 = 0xe7ffdefe, | |
| 312 | }, | |
| 310 | 313 | breakpoint: packed struct { |
| 311 | 314 | imm4: u4, |
| 312 | 315 | fixed_1: u4 = 0b0111, |
| ... | ... | @@ -613,6 +616,7 @@ pub const Instruction = union(enum) { |
| 613 | 616 | .branch => |v| @bitCast(u32, v), |
| 614 | 617 | .branch_exchange => |v| @bitCast(u32, v), |
| 615 | 618 | .supervisor_call => |v| @bitCast(u32, v), |
| 619 | .undefined_instruction => |v| v.imm32, | |
| 616 | 620 | .breakpoint => |v| @intCast(u32, v.imm4) | (@intCast(u32, v.fixed_1) << 4) | (@intCast(u32, v.imm12) << 8) | (@intCast(u32, v.fixed_2_and_cond) << 20), |
| 617 | 621 | }; |
| 618 | 622 | } |
| ... | ... | @@ -890,6 +894,13 @@ pub const Instruction = union(enum) { |
| 890 | 894 | }; |
| 891 | 895 | } |
| 892 | 896 | |
| 897 | // This instruction has no official mnemonic equivalent so it is public as-is. | |
| 898 | pub fn undefinedInstruction() Instruction { | |
| 899 | return Instruction{ | |
| 900 | .undefined_instruction = .{}, | |
| 901 | }; | |
| 902 | } | |
| 903 | ||
| 893 | 904 | fn breakpoint(imm: u16) Instruction { |
| 894 | 905 | return Instruction{ |
| 895 | 906 | .breakpoint = .{ |
src/arch/riscv64/CodeGen.zig+9| ... | ... | @@ -547,6 +547,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 547 | 547 | .bitcast => try self.airBitCast(inst), |
| 548 | 548 | .block => try self.airBlock(inst), |
| 549 | 549 | .br => try self.airBr(inst), |
| 550 | .trap => try self.airTrap(), | |
| 550 | 551 | .breakpoint => try self.airBreakpoint(), |
| 551 | 552 | .ret_addr => try self.airRetAddr(inst), |
| 552 | 553 | .frame_addr => try self.airFrameAddress(inst), |
| ... | ... | @@ -1649,6 +1650,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1649 | 1650 | return self.finishAir(inst, mcv, .{ .none, .none, .none }); |
| 1650 | 1651 | } |
| 1651 | 1652 | |
| 1653 | fn airTrap(self: *Self) !void { | |
| 1654 | _ = try self.addInst(.{ | |
| 1655 | .tag = .unimp, | |
| 1656 | .data = .{ .nop = {} }, | |
| 1657 | }); | |
| 1658 | return self.finishAirBookkeeping(); | |
| 1659 | } | |
| 1660 | ||
| 1652 | 1661 | fn airBreakpoint(self: *Self) !void { |
| 1653 | 1662 | _ = try self.addInst(.{ |
| 1654 | 1663 | .tag = .ebreak, |
src/arch/riscv64/Emit.zig+2| ... | ... | @@ -51,6 +51,7 @@ pub fn emitMir( |
| 51 | 51 | |
| 52 | 52 | .ebreak => try emit.mirSystem(inst), |
| 53 | 53 | .ecall => try emit.mirSystem(inst), |
| 54 | .unimp => try emit.mirSystem(inst), | |
| 54 | 55 | |
| 55 | 56 | .dbg_line => try emit.mirDbgLine(inst), |
| 56 | 57 | |
| ... | ... | @@ -153,6 +154,7 @@ fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 153 | 154 | switch (tag) { |
| 154 | 155 | .ebreak => try emit.writeInstruction(Instruction.ebreak), |
| 155 | 156 | .ecall => try emit.writeInstruction(Instruction.ecall), |
| 157 | .unimp => try emit.writeInstruction(Instruction.unimp), | |
| 156 | 158 | else => unreachable, |
| 157 | 159 | } |
| 158 | 160 | } |
src/arch/riscv64/Mir.zig+1| ... | ... | @@ -32,6 +32,7 @@ pub const Inst = struct { |
| 32 | 32 | dbg_epilogue_begin, |
| 33 | 33 | /// Pseudo-instruction: Update debug line |
| 34 | 34 | dbg_line, |
| 35 | unimp, | |
| 35 | 36 | ebreak, |
| 36 | 37 | ecall, |
| 37 | 38 | jalr, |
src/arch/riscv64/bits.zig+1| ... | ... | @@ -380,6 +380,7 @@ pub const Instruction = union(enum) { |
| 380 | 380 | |
| 381 | 381 | pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000); |
| 382 | 382 | pub const ebreak = iType(0b1110011, 0b000, .zero, .zero, 0x001); |
| 383 | pub const unimp = iType(0, 0, .zero, .zero, 0); | |
| 383 | 384 | }; |
| 384 | 385 | |
| 385 | 386 | pub const Register = enum(u6) { |
src/arch/sparc64/CodeGen.zig+16| ... | ... | @@ -562,6 +562,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 562 | 562 | .bitcast => try self.airBitCast(inst), |
| 563 | 563 | .block => try self.airBlock(inst), |
| 564 | 564 | .br => try self.airBr(inst), |
| 565 | .trap => try self.airTrap(), | |
| 565 | 566 | .breakpoint => try self.airBreakpoint(), |
| 566 | 567 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), |
| 567 | 568 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), |
| ... | ... | @@ -1156,6 +1157,21 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1156 | 1157 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); |
| 1157 | 1158 | } |
| 1158 | 1159 | |
| 1160 | fn airTrap(self: *Self) !void { | |
| 1161 | // ta 0x05 | |
| 1162 | _ = try self.addInst(.{ | |
| 1163 | .tag = .tcc, | |
| 1164 | .data = .{ | |
| 1165 | .trap = .{ | |
| 1166 | .is_imm = true, | |
| 1167 | .cond = .al, | |
| 1168 | .rs2_or_imm = .{ .imm = 0x05 }, | |
| 1169 | }, | |
| 1170 | }, | |
| 1171 | }); | |
| 1172 | return self.finishAirBookkeeping(); | |
| 1173 | } | |
| 1174 | ||
| 1159 | 1175 | fn airBreakpoint(self: *Self) !void { |
| 1160 | 1176 | // ta 0x01 |
| 1161 | 1177 | _ = try self.addInst(.{ |
src/arch/wasm/CodeGen.zig+7| ... | ... | @@ -1827,6 +1827,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1827 | 1827 | .arg => func.airArg(inst), |
| 1828 | 1828 | .bitcast => func.airBitcast(inst), |
| 1829 | 1829 | .block => func.airBlock(inst), |
| 1830 | .trap => func.airTrap(inst), | |
| 1830 | 1831 | .breakpoint => func.airBreakpoint(inst), |
| 1831 | 1832 | .br => func.airBr(inst), |
| 1832 | 1833 | .bool_to_int => func.airBoolToInt(inst), |
| ... | ... | @@ -3287,9 +3288,15 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3287 | 3288 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 3288 | 3289 | } |
| 3289 | 3290 | |
| 3291 | fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | |
| 3292 | try func.addTag(.@"unreachable"); | |
| 3293 | func.finishAir(inst, .none, &.{}); | |
| 3294 | } | |
| 3295 | ||
| 3290 | 3296 | fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3291 | 3297 | // unsupported by wasm itfunc. Can be implemented once we support DWARF |
| 3292 | 3298 | // for wasm |
| 3299 | try func.addTag(.@"unreachable"); | |
| 3293 | 3300 | func.finishAir(inst, .none, &.{}); |
| 3294 | 3301 | } |
| 3295 | 3302 |
src/arch/x86_64/CodeGen.zig+10| ... | ... | @@ -634,6 +634,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 634 | 634 | .bitcast => try self.airBitCast(inst), |
| 635 | 635 | .block => try self.airBlock(inst), |
| 636 | 636 | .br => try self.airBr(inst), |
| 637 | .trap => try self.airTrap(), | |
| 637 | 638 | .breakpoint => try self.airBreakpoint(), |
| 638 | 639 | .ret_addr => try self.airRetAddr(inst), |
| 639 | 640 | .frame_addr => try self.airFrameAddress(inst), |
| ... | ... | @@ -3913,6 +3914,15 @@ fn genVarDbgInfo( |
| 3913 | 3914 | } |
| 3914 | 3915 | } |
| 3915 | 3916 | |
| 3917 | fn airTrap(self: *Self) !void { | |
| 3918 | _ = try self.addInst(.{ | |
| 3919 | .tag = .ud, | |
| 3920 | .ops = Mir.Inst.Ops.encode(.{}), | |
| 3921 | .data = undefined, | |
| 3922 | }); | |
| 3923 | return self.finishAirBookkeeping(); | |
| 3924 | } | |
| 3925 | ||
| 3916 | 3926 | fn airBreakpoint(self: *Self) !void { |
| 3917 | 3927 | _ = try self.addInst(.{ |
| 3918 | 3928 | .tag = .interrupt, |
src/arch/x86_64/Emit.zig+7| ... | ... | @@ -166,6 +166,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 166 | 166 | |
| 167 | 167 | .@"test" => try emit.mirTest(inst), |
| 168 | 168 | |
| 169 | .ud => try emit.mirUndefinedInstruction(), | |
| 169 | 170 | .interrupt => try emit.mirInterrupt(inst), |
| 170 | 171 | .nop => {}, // just skip it |
| 171 | 172 | |
| ... | ... | @@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void { |
| 234 | 235 | } |
| 235 | 236 | } |
| 236 | 237 | |
| 238 | fn mirUndefinedInstruction(emit: *Emit) InnerError!void { | |
| 239 | return lowerToZoEnc(.ud2, emit.code); | |
| 240 | } | |
| 241 | ||
| 237 | 242 | fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 238 | 243 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 239 | 244 | assert(tag == .interrupt); |
| ... | ... | @@ -1279,6 +1284,7 @@ const Tag = enum { |
| 1279 | 1284 | push, |
| 1280 | 1285 | pop, |
| 1281 | 1286 | @"test", |
| 1287 | ud2, | |
| 1282 | 1288 | int3, |
| 1283 | 1289 | nop, |
| 1284 | 1290 | imul, |
| ... | ... | @@ -1571,6 +1577,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { |
| 1571 | 1577 | .zo => return switch (tag) { |
| 1572 | 1578 | .ret_near => OpCode.init(&.{0xc3}), |
| 1573 | 1579 | .ret_far => OpCode.init(&.{0xcb}), |
| 1580 | .ud2 => OpCode.init(&.{ 0x0F, 0x0B }), | |
| 1574 | 1581 | .int3 => OpCode.init(&.{0xcc}), |
| 1575 | 1582 | .nop => OpCode.init(&.{0x90}), |
| 1576 | 1583 | .syscall => OpCode.init(&.{ 0x0f, 0x05 }), |
src/arch/x86_64/Mir.zig+3| ... | ... | @@ -329,6 +329,9 @@ pub const Inst = struct { |
| 329 | 329 | /// TODO handle more cases |
| 330 | 330 | @"test", |
| 331 | 331 | |
| 332 | /// Undefined Instruction | |
| 333 | ud, | |
| 334 | ||
| 332 | 335 | /// Breakpoint form: |
| 333 | 336 | /// 0b00 int3 |
| 334 | 337 | interrupt, |
src/codegen/c.zig+6| ... | ... | @@ -2741,6 +2741,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2741 | 2741 | .const_ty => unreachable, // excluded from function bodies |
| 2742 | 2742 | .arg => try airArg(f, inst), |
| 2743 | 2743 | |
| 2744 | .trap => try airTrap(f.object.writer()), | |
| 2744 | 2745 | .breakpoint => try airBreakpoint(f.object.writer()), |
| 2745 | 2746 | .ret_addr => try airRetAddr(f, inst), |
| 2746 | 2747 | .frame_addr => try airFrameAddress(f, inst), |
| ... | ... | @@ -4428,6 +4429,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4428 | 4429 | return local; |
| 4429 | 4430 | } |
| 4430 | 4431 | |
| 4432 | fn airTrap(writer: anytype) !CValue { | |
| 4433 | try writer.writeAll("zig_trap();\n"); | |
| 4434 | return .none; | |
| 4435 | } | |
| 4436 | ||
| 4431 | 4437 | fn airBreakpoint(writer: anytype) !CValue { |
| 4432 | 4438 | try writer.writeAll("zig_breakpoint();\n"); |
| 4433 | 4439 | return .none; |
src/codegen/llvm.zig+8| ... | ... | @@ -4590,6 +4590,7 @@ pub const FuncGen = struct { |
| 4590 | 4590 | .block => try self.airBlock(inst), |
| 4591 | 4591 | .br => try self.airBr(inst), |
| 4592 | 4592 | .switch_br => try self.airSwitchBr(inst), |
| 4593 | .trap => try self.airTrap(inst), | |
| 4593 | 4594 | .breakpoint => try self.airBreakpoint(inst), |
| 4594 | 4595 | .ret_addr => try self.airRetAddr(inst), |
| 4595 | 4596 | .frame_addr => try self.airFrameAddress(inst), |
| ... | ... | @@ -8256,6 +8257,13 @@ pub const FuncGen = struct { |
| 8256 | 8257 | return fg.load(ptr, ptr_ty); |
| 8257 | 8258 | } |
| 8258 | 8259 | |
| 8260 | fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | |
| 8261 | _ = inst; | |
| 8262 | const llvm_fn = self.getIntrinsic("llvm.trap", &.{}); | |
| 8263 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, ""); | |
| 8264 | return null; | |
| 8265 | } | |
| 8266 | ||
| 8259 | 8267 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8260 | 8268 | _ = inst; |
| 8261 | 8269 | const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{}); |
src/print_air.zig+1| ... | ... | @@ -194,6 +194,7 @@ const Writer = struct { |
| 194 | 194 | .c_va_end, |
| 195 | 195 | => try w.writeUnOp(s, inst), |
| 196 | 196 | |
| 197 | .trap, | |
| 197 | 198 | .breakpoint, |
| 198 | 199 | .unreach, |
| 199 | 200 | .ret_addr, |
src/print_zir.zig+2-1| ... | ... | @@ -196,7 +196,6 @@ const Writer = struct { |
| 196 | 196 | .error_name, |
| 197 | 197 | .panic, |
| 198 | 198 | .panic_comptime, |
| 199 | .set_cold, | |
| 200 | 199 | .set_runtime_safety, |
| 201 | 200 | .sqrt, |
| 202 | 201 | .sin, |
| ... | ... | @@ -411,6 +410,7 @@ const Writer = struct { |
| 411 | 410 | .alloc_inferred_comptime_mut, |
| 412 | 411 | .ret_ptr, |
| 413 | 412 | .ret_type, |
| 413 | .trap, | |
| 414 | 414 | => try self.writeNode(stream, inst), |
| 415 | 415 | |
| 416 | 416 | .error_value, |
| ... | ... | @@ -503,6 +503,7 @@ const Writer = struct { |
| 503 | 503 | .fence, |
| 504 | 504 | .set_float_mode, |
| 505 | 505 | .set_align_stack, |
| 506 | .set_cold, | |
| 506 | 507 | .wasm_memory_size, |
| 507 | 508 | .error_to_int, |
| 508 | 509 | .int_to_error, |