authorgravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2023-03-03 18:35:03+01:00
committergravatar for r00ster91@proton.meWooster <r00ster91@proton.me> 2023-03-04 12:08:19+01:00
log65368683ad92b858d0a391cb29d37c0476784b40
tree741bea50bb76c77683a4c48d02f8ee63bd35c1e0
parentd6bd00e85500fa1a7909695ae5943be438f7521d

add @trap builtin

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 causes7819 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>
78257826 {#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#}
93959397
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#endif181#endif
182182
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),
11901198
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),
81098110
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: on1105 // zig fmt: on
11051106
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}
51465147
5148fn 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
5147fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5156fn 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 `NameStrategy2005 /// `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}
42004201
4202fn airTrap(self: *Self) !void {
4203 _ = try self.addInst(.{
4204 .tag = .brk,
4205 .data = .{ .imm16 = 0x0001 },
4206 });
4207 return self.finishAirBookkeeping();
4208}
4209
4201fn airBreakpoint(self: *Self) !void {4210fn 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}
41484149
4150fn airTrap(self: *Self) !void {
4151 _ = try self.addInst(.{
4152 .tag = .undefined_instruction,
4153 .data = .{ .nop = {} },
4154 });
4155 return self.finishAirBookkeeping();
4156}
4157
4149fn airBreakpoint(self: *Self) !void {4158fn 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 into1//! This file contains the functionality for lowering AArch32 MIR into
2//! machine code2//! machine code
33
4const Emit = @This();4const Emit = @This();
...@@ -15,7 +15,7 @@ const Target = std.Target;...@@ -15,7 +15,7 @@ const Target = std.Target;
15const assert = std.debug.assert;15const assert = std.debug.assert;
16const Instruction = bits.Instruction;16const Instruction = bits.Instruction;
17const Register = bits.Register;17const Register = bits.Register;
18const log = std.log.scoped(.aarch64_emit);18const log = std.log.scoped(.aarch32_emit);
19const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;19const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
20const CodeGen = @import("CodeGen.zig");20const CodeGen = @import("CodeGen.zig");
2121
...@@ -100,6 +100,7 @@ pub fn emitMir(...@@ -100,6 +100,7 @@ pub fn emitMir(
100100
101 .b => try emit.mirBranch(inst),101 .b => try emit.mirBranch(inst),
102102
103 .undefined_instruction => try emit.mirUndefinedInstruction(),
103 .bkpt => try emit.mirExceptionGeneration(inst),104 .bkpt => try emit.mirExceptionGeneration(inst),
104105
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}
496497
498fn mirUndefinedInstruction(emit: *Emit) !void {
499 try emit.writeInstruction(Instruction.undefinedInstruction());
500}
501
497fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void {502fn 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 /// Branch36 /// Branch
37 b,37 b,
38 /// Undefined instruction
39 undefined_instruction,
38 /// Breakpoint40 /// Breakpoint
39 bkpt,41 bkpt,
40 /// Branch with Link and Exchange42 /// 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 }
892896
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}
16541655
1656fn airTrap(self: *Self) !void {
1657 _ = try self.addInst(.{
1658 .tag = .unimp,
1659 .data = .{ .nop = {} },
1660 });
1661 return self.finishAirBookkeeping();
1662}
1663
1655fn airBreakpoint(self: *Self) !void {1664fn 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(
5151
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),
5455
55 .dbg_line => try emit.mirDbgLine(inst),56 .dbg_line => try emit.mirDbgLine(inst),
5657
...@@ -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 line33 /// 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) {
380380
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};
384385
385pub const Register = enum(u6) {386pub 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}
11621163
1164fn 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
1163fn airBreakpoint(self: *Self) !void {1179fn airBreakpoint(self: *Self) !void {
1164 // ta 0x011180 // 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}
32913292
3293fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3294 try func.addTag(.@"unreachable");
3295 func.finishAir(inst, .none, &.{});
3296}
3297
3292fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3298fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3293 // unsupported by wasm itfunc. Can be implemented once we support DWARF3299 // unsupported by wasm itfunc. Can be implemented once we support DWARF
3294 // for wasm3300 // 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}
39193920
3921fn 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
3920fn airBreakpoint(self: *Self) !void {3930fn 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 {
166166
167 .@"test" => try emit.mirTest(inst),167 .@"test" => try emit.mirTest(inst),
168168
169 .ud => try emit.mirUndefinedInstruction(),
169 .interrupt => try emit.mirInterrupt(inst),170 .interrupt => try emit.mirInterrupt(inst),
170 .nop => {}, // just skip it171 .nop => {}, // just skip it
171172
...@@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void {...@@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
234 }235 }
235}236}
236237
238fn mirUndefinedInstruction(emit: *Emit) InnerError!void {
239 return lowerToZoEnc(.ud2, emit.code);
240}
241
237fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {242fn 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 cases329 /// TODO handle more cases
330 @"test",330 @"test",
331331
332 /// Undefined Instruction
333 ud,
334
332 /// Breakpoint form:335 /// Breakpoint form:
333 /// 0b00 int3336 /// 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 bodies2741 .const_ty => unreachable, // excluded from function bodies
2742 .arg => try airArg(f, inst),2742 .arg => try airArg(f, inst),
27432743
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}
44304431
4432fn airTrap(writer: anytype) !CValue {
4433 try writer.writeAll("zig_trap();\n");
4434 return .none;
4435}
4436
4431fn airBreakpoint(writer: anytype) !CValue {4437fn 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 }
82588259
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),
196196
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),
414415
415 .error_value,416 .error_value,