| author | |
| committer | |
| log | 65368683ad92b858d0a391cb29d37c0476784b40 |
| tree | 741bea50bb76c77683a4c48d02f8ee63bd35c1e0 |
| parent | d6bd00e85500fa1a7909695ae5943be438f7521d |
This introduces a new builtin function that compiles down to something that results in an illegal instruction exception/interrupt.
It can be used to exit a program abnormally.
This implements the builtin for all backends.26 files changed, 178 insertions(+), 10 deletions(-)
doc/langref.html.in+16-1| ... | @@ -7818,12 +7818,14 @@ comptime { | ... | @@ -7818,12 +7818,14 @@ comptime { |
| 7818 | <p> | 7818 | <p> |
| 7819 | This function inserts a platform-specific debug trap instruction which causes | 7819 | This function inserts a platform-specific debug trap instruction which causes |
| 7820 | debuggers to break there. | 7820 | debuggers to break there. |
| 7821 | Unlike for {#syntax#}@trap(){#endsyntax#}, execution may continue after this point if the program is resumed. | ||
| 7821 | </p> | 7822 | </p> |
| 7822 | <p> | 7823 | <p> |
| 7823 | This function is only valid within function scope. | 7824 | This function is only valid within function scope. |
| 7824 | </p> | 7825 | </p> |
| 7825 | 7826 | {#see_also|@trap#} | |
| 7826 | {#header_close#} | 7827 | {#header_close#} |
| 7828 | |||
| 7827 | {#header_open|@mulAdd#} | 7829 | {#header_open|@mulAdd#} |
| 7828 | <pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre> | 7830 | <pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre> |
| 7829 | <p> | 7831 | <p> |
| ... | @@ -9393,6 +9395,19 @@ fn List(comptime T: type) type { | ... | @@ -9393,6 +9395,19 @@ fn List(comptime T: type) type { |
| 9393 | </p> | 9395 | </p> |
| 9394 | {#header_close#} | 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 | {#header_open|@truncate#} | 9411 | {#header_open|@truncate#} |
| 9397 | <pre>{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}</pre> | 9412 | <pre>{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}</pre> |
| 9398 | <p> | 9413 | <p> |
lib/zig.h+8-2| ... | @@ -180,10 +180,16 @@ typedef char bool; | ... | @@ -180,10 +180,16 @@ typedef char bool; |
| 180 | #define zig_export(sig, symbol, name) __asm(name " = " symbol) | 180 | #define zig_export(sig, symbol, name) __asm(name " = " symbol) |
| 181 | #endif | 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 | #if zig_has_builtin(debugtrap) | 191 | #if zig_has_builtin(debugtrap) |
| 184 | #define zig_breakpoint() __builtin_debugtrap() | 192 | #define zig_breakpoint() __builtin_debugtrap() |
| 185 | #elif zig_has_builtin(trap) || defined(zig_gnuc) | ||
| 186 | #define zig_breakpoint() __builtin_trap() | ||
| 187 | #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) | 193 | #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) |
| 188 | #define zig_breakpoint() __debugbreak() | 194 | #define zig_breakpoint() __debugbreak() |
| 189 | #elif defined(__i386__) || defined(__x86_64__) | 195 | #elif defined(__i386__) || defined(__x86_64__) |
src/Air.zig+9-1| ... | @@ -232,7 +232,14 @@ pub const Inst = struct { | ... | @@ -232,7 +232,14 @@ pub const Inst = struct { |
| 232 | /// Result type is always noreturn; no instructions in a block follow this one. | 232 | /// Result type is always noreturn; no instructions in a block follow this one. |
| 233 | /// Uses the `br` field. | 233 | /// Uses the `br` field. |
| 234 | br, | 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 | /// Result type is always void. | 243 | /// Result type is always void. |
| 237 | breakpoint, | 244 | breakpoint, |
| 238 | /// Yields the return address of the current function. | 245 | /// Yields the return address of the current function. |
| ... | @@ -1186,6 +1193,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1186,6 +1193,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1186 | .ret, | 1193 | .ret, |
| 1187 | .ret_load, | 1194 | .ret_load, |
| 1188 | .unreach, | 1195 | .unreach, |
| 1196 | .trap, | ||
| 1189 | => return Type.initTag(.noreturn), | 1197 | => return Type.initTag(.noreturn), |
| 1190 | 1198 | ||
| 1191 | .breakpoint, | 1199 | .breakpoint, |
src/AstGen.zig+7-1| ... | @@ -2631,6 +2631,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2631,6 +2631,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2631 | .repeat_inline, | 2631 | .repeat_inline, |
| 2632 | .panic, | 2632 | .panic, |
| 2633 | .panic_comptime, | 2633 | .panic_comptime, |
| 2634 | .trap, | ||
| 2634 | .check_comptime_control_flow, | 2635 | .check_comptime_control_flow, |
| 2635 | => { | 2636 | => { |
| 2636 | noreturn_src_node = statement; | 2637 | noreturn_src_node = statement; |
| ... | @@ -8105,7 +8106,7 @@ fn builtinCall( | ... | @@ -8105,7 +8106,7 @@ fn builtinCall( |
| 8105 | .error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node), | 8106 | .error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node), |
| 8106 | .frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node), | 8107 | .frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node), |
| 8107 | .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node), | 8108 | .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node), |
| 8108 | .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), | 8109 | .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), |
| 8109 | 8110 | ||
| 8110 | .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info), | 8111 | .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info), |
| 8111 | .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of), | 8112 | .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of), |
| ... | @@ -8178,6 +8179,11 @@ fn builtinCall( | ... | @@ -8178,6 +8179,11 @@ fn builtinCall( |
| 8178 | try emitDbgNode(gz, node); | 8179 | try emitDbgNode(gz, node); |
| 8179 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic); | 8180 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic); |
| 8180 | }, | 8181 | }, |
| 8182 | .trap => { | ||
| 8183 | try emitDbgNode(gz, node); | ||
| 8184 | _ = try gz.addNode(.trap, node); | ||
| 8185 | return rvalue(gz, ri, .void_value, node); | ||
| 8186 | }, | ||
| 8181 | .error_to_int => { | 8187 | .error_to_int => { |
| 8182 | const operand = try expr(gz, scope, .{ .rl = .none }, params[0]); | 8188 | const operand = try expr(gz, scope, .{ .rl = .none }, params[0]); |
| 8183 | const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{ | 8189 | const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{ |
src/BuiltinFn.zig+8| ... | @@ -109,6 +109,7 @@ pub const Tag = enum { | ... | @@ -109,6 +109,7 @@ pub const Tag = enum { |
| 109 | sub_with_overflow, | 109 | sub_with_overflow, |
| 110 | tag_name, | 110 | tag_name, |
| 111 | This, | 111 | This, |
| 112 | trap, | ||
| 112 | truncate, | 113 | truncate, |
| 113 | Type, | 114 | Type, |
| 114 | type_info, | 115 | type_info, |
| ... | @@ -915,6 +916,13 @@ pub const list = list: { | ... | @@ -915,6 +916,13 @@ pub const list = list: { |
| 915 | .param_count = 0, | 916 | .param_count = 0, |
| 916 | }, | 917 | }, |
| 917 | }, | 918 | }, |
| 919 | .{ | ||
| 920 | "@trap", | ||
| 921 | .{ | ||
| 922 | .tag = .trap, | ||
| 923 | .param_count = 0, | ||
| 924 | }, | ||
| 925 | }, | ||
| 918 | .{ | 926 | .{ |
| 919 | "@truncate", | 927 | "@truncate", |
| 920 | .{ | 928 | .{ |
src/Liveness.zig+2| ... | @@ -226,6 +226,7 @@ pub fn categorizeOperand( | ... | @@ -226,6 +226,7 @@ pub fn categorizeOperand( |
| 226 | .ret_ptr, | 226 | .ret_ptr, |
| 227 | .constant, | 227 | .constant, |
| 228 | .const_ty, | 228 | .const_ty, |
| 229 | .trap, | ||
| 229 | .breakpoint, | 230 | .breakpoint, |
| 230 | .dbg_stmt, | 231 | .dbg_stmt, |
| 231 | .dbg_inline_begin, | 232 | .dbg_inline_begin, |
| ... | @@ -848,6 +849,7 @@ fn analyzeInst( | ... | @@ -848,6 +849,7 @@ fn analyzeInst( |
| 848 | .ret_ptr, | 849 | .ret_ptr, |
| 849 | .constant, | 850 | .constant, |
| 850 | .const_ty, | 851 | .const_ty, |
| 852 | .trap, | ||
| 851 | .breakpoint, | 853 | .breakpoint, |
| 852 | .dbg_stmt, | 854 | .dbg_stmt, |
| 853 | .dbg_inline_begin, | 855 | .dbg_inline_begin, |
src/Sema.zig+9| ... | @@ -1101,6 +1101,7 @@ fn analyzeBodyInner( | ... | @@ -1101,6 +1101,7 @@ fn analyzeBodyInner( |
| 1101 | .@"unreachable" => break sema.zirUnreachable(block, inst), | 1101 | .@"unreachable" => break sema.zirUnreachable(block, inst), |
| 1102 | .panic => break sema.zirPanic(block, inst, false), | 1102 | .panic => break sema.zirPanic(block, inst, false), |
| 1103 | .panic_comptime => break sema.zirPanic(block, inst, true), | 1103 | .panic_comptime => break sema.zirPanic(block, inst, true), |
| 1104 | .trap => break sema.zirTrap(block, inst), | ||
| 1104 | // zig fmt: on | 1105 | // zig fmt: on |
| 1105 | 1106 | ||
| 1106 | .extended => ext: { | 1107 | .extended => ext: { |
| ... | @@ -5144,6 +5145,14 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo | ... | @@ -5144,6 +5145,14 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo |
| 5144 | return always_noreturn; | 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 | fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5156 | fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5148 | const tracy = trace(@src()); | 5157 | const tracy = trace(@src()); |
| 5149 | defer tracy.end(); | 5158 | defer tracy.end(); |
src/Zir.zig+9-2| ... | @@ -617,7 +617,7 @@ pub const Inst = struct { | ... | @@ -617,7 +617,7 @@ pub const Inst = struct { |
| 617 | /// Uses the `un_node` field. | 617 | /// Uses the `un_node` field. |
| 618 | typeof_log2_int_type, | 618 | typeof_log2_int_type, |
| 619 | /// Asserts control-flow will not reach this instruction (`unreachable`). | 619 | /// Asserts control-flow will not reach this instruction (`unreachable`). |
| 620 | /// Uses the `unreachable` union field. | 620 | /// Uses the `@"unreachable"` union field. |
| 621 | @"unreachable", | 621 | @"unreachable", |
| 622 | /// Bitwise XOR. `^` | 622 | /// Bitwise XOR. `^` |
| 623 | /// Uses the `pl_node` union field. Payload is `Bin`. | 623 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| ... | @@ -808,6 +808,9 @@ pub const Inst = struct { | ... | @@ -808,6 +808,9 @@ pub const Inst = struct { |
| 808 | panic, | 808 | panic, |
| 809 | /// Same as `panic` but forces comptime. | 809 | /// Same as `panic` but forces comptime. |
| 810 | panic_comptime, | 810 | panic_comptime, |
| 811 | /// Implements `@trap`. | ||
| 812 | /// Uses the `node` field. | ||
| 813 | trap, | ||
| 811 | /// Implement builtin `@setRuntimeSafety`. Uses `un_node`. | 814 | /// Implement builtin `@setRuntimeSafety`. Uses `un_node`. |
| 812 | set_runtime_safety, | 815 | set_runtime_safety, |
| 813 | /// Implement builtin `@sqrt`. Uses `un_node`. | 816 | /// Implement builtin `@sqrt`. Uses `un_node`. |
| ... | @@ -1274,6 +1277,7 @@ pub const Inst = struct { | ... | @@ -1274,6 +1277,7 @@ pub const Inst = struct { |
| 1274 | .repeat_inline, | 1277 | .repeat_inline, |
| 1275 | .panic, | 1278 | .panic, |
| 1276 | .panic_comptime, | 1279 | .panic_comptime, |
| 1280 | .trap, | ||
| 1277 | .check_comptime_control_flow, | 1281 | .check_comptime_control_flow, |
| 1278 | => true, | 1282 | => true, |
| 1279 | }; | 1283 | }; |
| ... | @@ -1549,6 +1553,7 @@ pub const Inst = struct { | ... | @@ -1549,6 +1553,7 @@ pub const Inst = struct { |
| 1549 | .repeat_inline, | 1553 | .repeat_inline, |
| 1550 | .panic, | 1554 | .panic, |
| 1551 | .panic_comptime, | 1555 | .panic_comptime, |
| 1556 | .trap, | ||
| 1552 | .for_len, | 1557 | .for_len, |
| 1553 | .@"try", | 1558 | .@"try", |
| 1554 | .try_ptr, | 1559 | .try_ptr, |
| ... | @@ -1746,6 +1751,7 @@ pub const Inst = struct { | ... | @@ -1746,6 +1751,7 @@ pub const Inst = struct { |
| 1746 | .error_name = .un_node, | 1751 | .error_name = .un_node, |
| 1747 | .panic = .un_node, | 1752 | .panic = .un_node, |
| 1748 | .panic_comptime = .un_node, | 1753 | .panic_comptime = .un_node, |
| 1754 | .trap = .node, | ||
| 1749 | .set_runtime_safety = .un_node, | 1755 | .set_runtime_safety = .un_node, |
| 1750 | .sqrt = .un_node, | 1756 | .sqrt = .un_node, |
| 1751 | .sin = .un_node, | 1757 | .sin = .un_node, |
| ... | @@ -1982,6 +1988,7 @@ pub const Inst = struct { | ... | @@ -1982,6 +1988,7 @@ pub const Inst = struct { |
| 1982 | err_set_cast, | 1988 | err_set_cast, |
| 1983 | /// `operand` is payload index to `UnNode`. | 1989 | /// `operand` is payload index to `UnNode`. |
| 1984 | await_nosuspend, | 1990 | await_nosuspend, |
| 1991 | /// Implements `@breakpoint`. | ||
| 1985 | /// `operand` is `src_node: i32`. | 1992 | /// `operand` is `src_node: i32`. |
| 1986 | breakpoint, | 1993 | breakpoint, |
| 1987 | /// Implements the `@select` builtin. | 1994 | /// Implements the `@select` builtin. |
| ... | @@ -1995,7 +2002,7 @@ pub const Inst = struct { | ... | @@ -1995,7 +2002,7 @@ pub const Inst = struct { |
| 1995 | int_to_error, | 2002 | int_to_error, |
| 1996 | /// Implement builtin `@Type`. | 2003 | /// Implement builtin `@Type`. |
| 1997 | /// `operand` is payload index to `UnNode`. | 2004 | /// `operand` is payload index to `UnNode`. |
| 1998 | /// `small` contains `NameStrategy | 2005 | /// `small` contains `NameStrategy`. |
| 1999 | reify, | 2006 | reify, |
| 2000 | /// Implements the `@asyncCall` builtin. | 2007 | /// Implements the `@asyncCall` builtin. |
| 2001 | /// `operand` is payload index to `AsyncCall`. | 2008 | /// `operand` is payload index to `AsyncCall`. |
src/arch/aarch64/CodeGen.zig+10-1| ... | @@ -737,6 +737,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -737,6 +737,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 737 | .bitcast => try self.airBitCast(inst), | 737 | .bitcast => try self.airBitCast(inst), |
| 738 | .block => try self.airBlock(inst), | 738 | .block => try self.airBlock(inst), |
| 739 | .br => try self.airBr(inst), | 739 | .br => try self.airBr(inst), |
| 740 | .trap => try self.airTrap(), | ||
| 740 | .breakpoint => try self.airBreakpoint(), | 741 | .breakpoint => try self.airBreakpoint(), |
| 741 | .ret_addr => try self.airRetAddr(inst), | 742 | .ret_addr => try self.airRetAddr(inst), |
| 742 | .frame_addr => try self.airFrameAddress(inst), | 743 | .frame_addr => try self.airFrameAddress(inst), |
| ... | @@ -4198,10 +4199,18 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4198,10 +4199,18 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4198 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 4199 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 4199 | } | 4200 | } |
| 4200 | 4201 | ||
| 4202 | fn airTrap(self: *Self) !void { | ||
| 4203 | _ = try self.addInst(.{ | ||
| 4204 | .tag = .brk, | ||
| 4205 | .data = .{ .imm16 = 0x0001 }, | ||
| 4206 | }); | ||
| 4207 | return self.finishAirBookkeeping(); | ||
| 4208 | } | ||
| 4209 | |||
| 4201 | fn airBreakpoint(self: *Self) !void { | 4210 | fn airBreakpoint(self: *Self) !void { |
| 4202 | _ = try self.addInst(.{ | 4211 | _ = try self.addInst(.{ |
| 4203 | .tag = .brk, | 4212 | .tag = .brk, |
| 4204 | .data = .{ .imm16 = 1 }, | 4213 | .data = .{ .imm16 = 0xf000 }, |
| 4205 | }); | 4214 | }); |
| 4206 | return self.finishAirBookkeeping(); | 4215 | return self.finishAirBookkeeping(); |
| 4207 | } | 4216 | } |
src/arch/arm/CodeGen.zig+9| ... | @@ -721,6 +721,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -721,6 +721,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 721 | .bitcast => try self.airBitCast(inst), | 721 | .bitcast => try self.airBitCast(inst), |
| 722 | .block => try self.airBlock(inst), | 722 | .block => try self.airBlock(inst), |
| 723 | .br => try self.airBr(inst), | 723 | .br => try self.airBr(inst), |
| 724 | .trap => try self.airTrap(), | ||
| 724 | .breakpoint => try self.airBreakpoint(), | 725 | .breakpoint => try self.airBreakpoint(), |
| 725 | .ret_addr => try self.airRetAddr(inst), | 726 | .ret_addr => try self.airRetAddr(inst), |
| 726 | .frame_addr => try self.airFrameAddress(inst), | 727 | .frame_addr => try self.airFrameAddress(inst), |
| ... | @@ -4146,6 +4147,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4146,6 +4147,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4146 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 4147 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 4147 | } | 4148 | } |
| 4148 | 4149 | ||
| 4150 | fn airTrap(self: *Self) !void { | ||
| 4151 | _ = try self.addInst(.{ | ||
| 4152 | .tag = .undefined_instruction, | ||
| 4153 | .data = .{ .nop = {} }, | ||
| 4154 | }); | ||
| 4155 | return self.finishAirBookkeeping(); | ||
| 4156 | } | ||
| 4157 | |||
| 4149 | fn airBreakpoint(self: *Self) !void { | 4158 | fn airBreakpoint(self: *Self) !void { |
| 4150 | _ = try self.addInst(.{ | 4159 | _ = try self.addInst(.{ |
| 4151 | .tag = .bkpt, | 4160 | .tag = .bkpt, |
src/arch/arm/Emit.zig+7-2| ... | @@ -1,4 +1,4 @@ | ... | @@ -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 | //! machine code | 2 | //! machine code |
| 3 | 3 | ||
| 4 | const Emit = @This(); | 4 | const Emit = @This(); |
| ... | @@ -15,7 +15,7 @@ const Target = std.Target; | ... | @@ -15,7 +15,7 @@ const Target = std.Target; |
| 15 | const assert = std.debug.assert; | 15 | const assert = std.debug.assert; |
| 16 | const Instruction = bits.Instruction; | 16 | const Instruction = bits.Instruction; |
| 17 | const Register = bits.Register; | 17 | const Register = bits.Register; |
| 18 | const log = std.log.scoped(.aarch64_emit); | 18 | const log = std.log.scoped(.aarch32_emit); |
| 19 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 19 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 20 | const CodeGen = @import("CodeGen.zig"); | 20 | const CodeGen = @import("CodeGen.zig"); |
| 21 | 21 | ||
| ... | @@ -100,6 +100,7 @@ pub fn emitMir( | ... | @@ -100,6 +100,7 @@ pub fn emitMir( |
| 100 | 100 | ||
| 101 | .b => try emit.mirBranch(inst), | 101 | .b => try emit.mirBranch(inst), |
| 102 | 102 | ||
| 103 | .undefined_instruction => try emit.mirUndefinedInstruction(), | ||
| 103 | .bkpt => try emit.mirExceptionGeneration(inst), | 104 | .bkpt => try emit.mirExceptionGeneration(inst), |
| 104 | 105 | ||
| 105 | .blx => try emit.mirBranchExchange(inst), | 106 | .blx => try emit.mirBranchExchange(inst), |
| ... | @@ -494,6 +495,10 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -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 | fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void { | 502 | fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 498 | const tag = emit.mir.instructions.items(.tag)[inst]; | 503 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 499 | const imm16 = emit.mir.instructions.items(.data)[inst].imm16; | 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,6 +35,8 @@ pub const Inst = struct { |
| 35 | asr, | 35 | asr, |
| 36 | /// Branch | 36 | /// Branch |
| 37 | b, | 37 | b, |
| 38 | /// Undefined instruction | ||
| 39 | undefined_instruction, | ||
| 38 | /// Breakpoint | 40 | /// Breakpoint |
| 39 | bkpt, | 41 | bkpt, |
| 40 | /// Branch with Link and Exchange | 42 | /// Branch with Link and Exchange |
src/arch/arm/bits.zig+11| ... | @@ -307,6 +307,9 @@ pub const Instruction = union(enum) { | ... | @@ -307,6 +307,9 @@ pub const Instruction = union(enum) { |
| 307 | fixed: u4 = 0b1111, | 307 | fixed: u4 = 0b1111, |
| 308 | cond: u4, | 308 | cond: u4, |
| 309 | }, | 309 | }, |
| 310 | undefined_instruction: packed struct { | ||
| 311 | imm32: u32 = 0xe7ffdefe, | ||
| 312 | }, | ||
| 310 | breakpoint: packed struct { | 313 | breakpoint: packed struct { |
| 311 | imm4: u4, | 314 | imm4: u4, |
| 312 | fixed_1: u4 = 0b0111, | 315 | fixed_1: u4 = 0b0111, |
| ... | @@ -613,6 +616,7 @@ pub const Instruction = union(enum) { | ... | @@ -613,6 +616,7 @@ pub const Instruction = union(enum) { |
| 613 | .branch => |v| @bitCast(u32, v), | 616 | .branch => |v| @bitCast(u32, v), |
| 614 | .branch_exchange => |v| @bitCast(u32, v), | 617 | .branch_exchange => |v| @bitCast(u32, v), |
| 615 | .supervisor_call => |v| @bitCast(u32, v), | 618 | .supervisor_call => |v| @bitCast(u32, v), |
| 619 | .undefined_instruction => |v| v.imm32, | ||
| 616 | .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), | 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,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 | fn breakpoint(imm: u16) Instruction { | 904 | fn breakpoint(imm: u16) Instruction { |
| 894 | return Instruction{ | 905 | return Instruction{ |
| 895 | .breakpoint = .{ | 906 | .breakpoint = .{ |
src/arch/riscv64/CodeGen.zig+9| ... | @@ -550,6 +550,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -550,6 +550,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 550 | .bitcast => try self.airBitCast(inst), | 550 | .bitcast => try self.airBitCast(inst), |
| 551 | .block => try self.airBlock(inst), | 551 | .block => try self.airBlock(inst), |
| 552 | .br => try self.airBr(inst), | 552 | .br => try self.airBr(inst), |
| 553 | .trap => try self.airTrap(), | ||
| 553 | .breakpoint => try self.airBreakpoint(), | 554 | .breakpoint => try self.airBreakpoint(), |
| 554 | .ret_addr => try self.airRetAddr(inst), | 555 | .ret_addr => try self.airRetAddr(inst), |
| 555 | .frame_addr => try self.airFrameAddress(inst), | 556 | .frame_addr => try self.airFrameAddress(inst), |
| ... | @@ -1652,6 +1653,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1652,6 +1653,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1652 | return self.finishAir(inst, mcv, .{ .none, .none, .none }); | 1653 | return self.finishAir(inst, mcv, .{ .none, .none, .none }); |
| 1653 | } | 1654 | } |
| 1654 | 1655 | ||
| 1656 | fn airTrap(self: *Self) !void { | ||
| 1657 | _ = try self.addInst(.{ | ||
| 1658 | .tag = .unimp, | ||
| 1659 | .data = .{ .nop = {} }, | ||
| 1660 | }); | ||
| 1661 | return self.finishAirBookkeeping(); | ||
| 1662 | } | ||
| 1663 | |||
| 1655 | fn airBreakpoint(self: *Self) !void { | 1664 | fn airBreakpoint(self: *Self) !void { |
| 1656 | _ = try self.addInst(.{ | 1665 | _ = try self.addInst(.{ |
| 1657 | .tag = .ebreak, | 1666 | .tag = .ebreak, |
src/arch/riscv64/Emit.zig+2| ... | @@ -51,6 +51,7 @@ pub fn emitMir( | ... | @@ -51,6 +51,7 @@ pub fn emitMir( |
| 51 | 51 | ||
| 52 | .ebreak => try emit.mirSystem(inst), | 52 | .ebreak => try emit.mirSystem(inst), |
| 53 | .ecall => try emit.mirSystem(inst), | 53 | .ecall => try emit.mirSystem(inst), |
| 54 | .unimp => try emit.mirSystem(inst), | ||
| 54 | 55 | ||
| 55 | .dbg_line => try emit.mirDbgLine(inst), | 56 | .dbg_line => try emit.mirDbgLine(inst), |
| 56 | 57 | ||
| ... | @@ -153,6 +154,7 @@ fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -153,6 +154,7 @@ fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 153 | switch (tag) { | 154 | switch (tag) { |
| 154 | .ebreak => try emit.writeInstruction(Instruction.ebreak), | 155 | .ebreak => try emit.writeInstruction(Instruction.ebreak), |
| 155 | .ecall => try emit.writeInstruction(Instruction.ecall), | 156 | .ecall => try emit.writeInstruction(Instruction.ecall), |
| 157 | .unimp => try emit.writeInstruction(Instruction.unimp), | ||
| 156 | else => unreachable, | 158 | else => unreachable, |
| 157 | } | 159 | } |
| 158 | } | 160 | } |
src/arch/riscv64/Mir.zig+1| ... | @@ -32,6 +32,7 @@ pub const Inst = struct { | ... | @@ -32,6 +32,7 @@ pub const Inst = struct { |
| 32 | dbg_epilogue_begin, | 32 | dbg_epilogue_begin, |
| 33 | /// Pseudo-instruction: Update debug line | 33 | /// Pseudo-instruction: Update debug line |
| 34 | dbg_line, | 34 | dbg_line, |
| 35 | unimp, | ||
| 35 | ebreak, | 36 | ebreak, |
| 36 | ecall, | 37 | ecall, |
| 37 | jalr, | 38 | jalr, |
src/arch/riscv64/bits.zig+1| ... | @@ -380,6 +380,7 @@ pub const Instruction = union(enum) { | ... | @@ -380,6 +380,7 @@ pub const Instruction = union(enum) { |
| 380 | 380 | ||
| 381 | pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000); | 381 | pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000); |
| 382 | pub const ebreak = iType(0b1110011, 0b000, .zero, .zero, 0x001); | 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 | pub const Register = enum(u6) { | 386 | pub const Register = enum(u6) { |
src/arch/sparc64/CodeGen.zig+16| ... | @@ -566,6 +566,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -566,6 +566,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 566 | .bitcast => try self.airBitCast(inst), | 566 | .bitcast => try self.airBitCast(inst), |
| 567 | .block => try self.airBlock(inst), | 567 | .block => try self.airBlock(inst), |
| 568 | .br => try self.airBr(inst), | 568 | .br => try self.airBr(inst), |
| 569 | .trap => try self.airTrap(), | ||
| 569 | .breakpoint => try self.airBreakpoint(), | 570 | .breakpoint => try self.airBreakpoint(), |
| 570 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), | 571 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), |
| 571 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), | 572 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), |
| ... | @@ -1160,6 +1161,21 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1160,6 +1161,21 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1160 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); | 1161 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); |
| 1161 | } | 1162 | } |
| 1162 | 1163 | ||
| 1164 | fn airTrap(self: *Self) !void { | ||
| 1165 | // ta 0x05 | ||
| 1166 | _ = try self.addInst(.{ | ||
| 1167 | .tag = .tcc, | ||
| 1168 | .data = .{ | ||
| 1169 | .trap = .{ | ||
| 1170 | .is_imm = true, | ||
| 1171 | .cond = .al, | ||
| 1172 | .rs2_or_imm = .{ .imm = 0x05 }, | ||
| 1173 | }, | ||
| 1174 | }, | ||
| 1175 | }); | ||
| 1176 | return self.finishAirBookkeeping(); | ||
| 1177 | } | ||
| 1178 | |||
| 1163 | fn airBreakpoint(self: *Self) !void { | 1179 | fn airBreakpoint(self: *Self) !void { |
| 1164 | // ta 0x01 | 1180 | // ta 0x01 |
| 1165 | _ = try self.addInst(.{ | 1181 | _ = try self.addInst(.{ |
src/arch/wasm/CodeGen.zig+6| ... | @@ -1829,6 +1829,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1829,6 +1829,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1829 | .arg => func.airArg(inst), | 1829 | .arg => func.airArg(inst), |
| 1830 | .bitcast => func.airBitcast(inst), | 1830 | .bitcast => func.airBitcast(inst), |
| 1831 | .block => func.airBlock(inst), | 1831 | .block => func.airBlock(inst), |
| 1832 | .trap => func.airTrap(inst), | ||
| 1832 | .breakpoint => func.airBreakpoint(inst), | 1833 | .breakpoint => func.airBreakpoint(inst), |
| 1833 | .br => func.airBr(inst), | 1834 | .br => func.airBr(inst), |
| 1834 | .bool_to_int => func.airBoolToInt(inst), | 1835 | .bool_to_int => func.airBoolToInt(inst), |
| ... | @@ -3289,6 +3290,11 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3289,6 +3290,11 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3289 | func.finishAir(inst, result, &.{ty_op.operand}); | 3290 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 3290 | } | 3291 | } |
| 3291 | 3292 | ||
| 3293 | fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ||
| 3294 | try func.addTag(.@"unreachable"); | ||
| 3295 | func.finishAir(inst, .none, &.{}); | ||
| 3296 | } | ||
| 3297 | |||
| 3292 | fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3298 | fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3293 | // unsupported by wasm itfunc. Can be implemented once we support DWARF | 3299 | // unsupported by wasm itfunc. Can be implemented once we support DWARF |
| 3294 | // for wasm | 3300 | // for wasm |
src/arch/x86_64/CodeGen.zig+10| ... | @@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 638 | .bitcast => try self.airBitCast(inst), | 638 | .bitcast => try self.airBitCast(inst), |
| 639 | .block => try self.airBlock(inst), | 639 | .block => try self.airBlock(inst), |
| 640 | .br => try self.airBr(inst), | 640 | .br => try self.airBr(inst), |
| 641 | .trap => try self.airTrap(), | ||
| 641 | .breakpoint => try self.airBreakpoint(), | 642 | .breakpoint => try self.airBreakpoint(), |
| 642 | .ret_addr => try self.airRetAddr(inst), | 643 | .ret_addr => try self.airRetAddr(inst), |
| 643 | .frame_addr => try self.airFrameAddress(inst), | 644 | .frame_addr => try self.airFrameAddress(inst), |
| ... | @@ -3917,6 +3918,15 @@ fn genVarDbgInfo( | ... | @@ -3917,6 +3918,15 @@ fn genVarDbgInfo( |
| 3917 | } | 3918 | } |
| 3918 | } | 3919 | } |
| 3919 | 3920 | ||
| 3921 | fn airTrap(self: *Self) !void { | ||
| 3922 | _ = try self.addInst(.{ | ||
| 3923 | .tag = .ud, | ||
| 3924 | .ops = Mir.Inst.Ops.encode(.{}), | ||
| 3925 | .data = undefined, | ||
| 3926 | }); | ||
| 3927 | return self.finishAirBookkeeping(); | ||
| 3928 | } | ||
| 3929 | |||
| 3920 | fn airBreakpoint(self: *Self) !void { | 3930 | fn airBreakpoint(self: *Self) !void { |
| 3921 | _ = try self.addInst(.{ | 3931 | _ = try self.addInst(.{ |
| 3922 | .tag = .interrupt, | 3932 | .tag = .interrupt, |
src/arch/x86_64/Emit.zig+7| ... | @@ -166,6 +166,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -166,6 +166,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 166 | 166 | ||
| 167 | .@"test" => try emit.mirTest(inst), | 167 | .@"test" => try emit.mirTest(inst), |
| 168 | 168 | ||
| 169 | .ud => try emit.mirUndefinedInstruction(), | ||
| 169 | .interrupt => try emit.mirInterrupt(inst), | 170 | .interrupt => try emit.mirInterrupt(inst), |
| 170 | .nop => {}, // just skip it | 171 | .nop => {}, // just skip it |
| 171 | 172 | ||
| ... | @@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void { | ... | @@ -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 | fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 242 | fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 238 | const tag = emit.mir.instructions.items(.tag)[inst]; | 243 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 239 | assert(tag == .interrupt); | 244 | assert(tag == .interrupt); |
| ... | @@ -1279,6 +1284,7 @@ const Tag = enum { | ... | @@ -1279,6 +1284,7 @@ const Tag = enum { |
| 1279 | push, | 1284 | push, |
| 1280 | pop, | 1285 | pop, |
| 1281 | @"test", | 1286 | @"test", |
| 1287 | ud2, | ||
| 1282 | int3, | 1288 | int3, |
| 1283 | nop, | 1289 | nop, |
| 1284 | imul, | 1290 | imul, |
| ... | @@ -1571,6 +1577,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { | ... | @@ -1571,6 +1577,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode { |
| 1571 | .zo => return switch (tag) { | 1577 | .zo => return switch (tag) { |
| 1572 | .ret_near => OpCode.init(&.{0xc3}), | 1578 | .ret_near => OpCode.init(&.{0xc3}), |
| 1573 | .ret_far => OpCode.init(&.{0xcb}), | 1579 | .ret_far => OpCode.init(&.{0xcb}), |
| 1580 | .ud2 => OpCode.init(&.{ 0x0F, 0x0B }), | ||
| 1574 | .int3 => OpCode.init(&.{0xcc}), | 1581 | .int3 => OpCode.init(&.{0xcc}), |
| 1575 | .nop => OpCode.init(&.{0x90}), | 1582 | .nop => OpCode.init(&.{0x90}), |
| 1576 | .syscall => OpCode.init(&.{ 0x0f, 0x05 }), | 1583 | .syscall => OpCode.init(&.{ 0x0f, 0x05 }), |
src/arch/x86_64/Mir.zig+3| ... | @@ -329,6 +329,9 @@ pub const Inst = struct { | ... | @@ -329,6 +329,9 @@ pub const Inst = struct { |
| 329 | /// TODO handle more cases | 329 | /// TODO handle more cases |
| 330 | @"test", | 330 | @"test", |
| 331 | 331 | ||
| 332 | /// Undefined Instruction | ||
| 333 | ud, | ||
| 334 | |||
| 332 | /// Breakpoint form: | 335 | /// Breakpoint form: |
| 333 | /// 0b00 int3 | 336 | /// 0b00 int3 |
| 334 | interrupt, | 337 | interrupt, |
src/codegen/c.zig+6| ... | @@ -2741,6 +2741,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2741,6 +2741,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2741 | .const_ty => unreachable, // excluded from function bodies | 2741 | .const_ty => unreachable, // excluded from function bodies |
| 2742 | .arg => try airArg(f, inst), | 2742 | .arg => try airArg(f, inst), |
| 2743 | 2743 | ||
| 2744 | .trap => try airTrap(f.object.writer()), | ||
| 2744 | .breakpoint => try airBreakpoint(f.object.writer()), | 2745 | .breakpoint => try airBreakpoint(f.object.writer()), |
| 2745 | .ret_addr => try airRetAddr(f, inst), | 2746 | .ret_addr => try airRetAddr(f, inst), |
| 2746 | .frame_addr => try airFrameAddress(f, inst), | 2747 | .frame_addr => try airFrameAddress(f, inst), |
| ... | @@ -4428,6 +4429,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4428,6 +4429,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4428 | return local; | 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 | fn airBreakpoint(writer: anytype) !CValue { | 4437 | fn airBreakpoint(writer: anytype) !CValue { |
| 4432 | try writer.writeAll("zig_breakpoint();\n"); | 4438 | try writer.writeAll("zig_breakpoint();\n"); |
| 4433 | return .none; | 4439 | return .none; |
src/codegen/llvm.zig+8| ... | @@ -4590,6 +4590,7 @@ pub const FuncGen = struct { | ... | @@ -4590,6 +4590,7 @@ pub const FuncGen = struct { |
| 4590 | .block => try self.airBlock(inst), | 4590 | .block => try self.airBlock(inst), |
| 4591 | .br => try self.airBr(inst), | 4591 | .br => try self.airBr(inst), |
| 4592 | .switch_br => try self.airSwitchBr(inst), | 4592 | .switch_br => try self.airSwitchBr(inst), |
| 4593 | .trap => try self.airTrap(inst), | ||
| 4593 | .breakpoint => try self.airBreakpoint(inst), | 4594 | .breakpoint => try self.airBreakpoint(inst), |
| 4594 | .ret_addr => try self.airRetAddr(inst), | 4595 | .ret_addr => try self.airRetAddr(inst), |
| 4595 | .frame_addr => try self.airFrameAddress(inst), | 4596 | .frame_addr => try self.airFrameAddress(inst), |
| ... | @@ -8256,6 +8257,13 @@ pub const FuncGen = struct { | ... | @@ -8256,6 +8257,13 @@ pub const FuncGen = struct { |
| 8256 | return fg.load(ptr, ptr_ty); | 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 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8267 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8260 | _ = inst; | 8268 | _ = inst; |
| 8261 | const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{}); | 8269 | const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{}); |
src/print_air.zig+1| ... | @@ -194,6 +194,7 @@ const Writer = struct { | ... | @@ -194,6 +194,7 @@ const Writer = struct { |
| 194 | .c_va_end, | 194 | .c_va_end, |
| 195 | => try w.writeUnOp(s, inst), | 195 | => try w.writeUnOp(s, inst), |
| 196 | 196 | ||
| 197 | .trap, | ||
| 197 | .breakpoint, | 198 | .breakpoint, |
| 198 | .unreach, | 199 | .unreach, |
| 199 | .ret_addr, | 200 | .ret_addr, |
src/print_zir.zig+1| ... | @@ -410,6 +410,7 @@ const Writer = struct { | ... | @@ -410,6 +410,7 @@ const Writer = struct { |
| 410 | .alloc_inferred_comptime_mut, | 410 | .alloc_inferred_comptime_mut, |
| 411 | .ret_ptr, | 411 | .ret_ptr, |
| 412 | .ret_type, | 412 | .ret_type, |
| 413 | .trap, | ||
| 413 | => try self.writeNode(stream, inst), | 414 | => try self.writeNode(stream, inst), |
| 414 | 415 | ||
| 415 | .error_value, | 416 | .error_value, |