authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-04 16:20:31-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-04 16:20:31-05:00
loge7f128c2051b086cdb1c03da041745b560bbaa3e
tree89d06ee67639dfa0260c5beabc344fb33099df0d
parentc9d990d79083f117564837f762c3e225d7fbc5cf
parent4eb3f50fcf6fcfb6b8013571be00b9eeeb909833
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14782 from r00ster91/trap

add `@trap` builtin

28 files changed, 203 insertions(+), 34 deletions(-)

doc/langref.html.in+16-1
......@@ -7818,12 +7818,14 @@ comptime {
78187818 <p>
78197819 This function inserts a platform-specific debug trap instruction which causes
78207820 debuggers to break there.
7821 Unlike for {#syntax#}@trap(){#endsyntax#}, execution may continue after this point if the program is resumed.
78217822 </p>
78227823 <p>
78237824 This function is only valid within function scope.
78247825 </p>
7825
7826 {#see_also|@trap#}
78267827 {#header_close#}
7828
78277829 {#header_open|@mulAdd#}
78287830 <pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre>
78297831 <p>
......@@ -9393,6 +9395,19 @@ fn List(comptime T: type) type {
93939395 </p>
93949396 {#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
93969411 {#header_open|@truncate#}
93979412 <pre>{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}</pre>
93989413 <p>
lib/docs/main.js-4
......@@ -1187,10 +1187,6 @@ const NAV_MODES = {
11871187 payloadHtml += "panic";
11881188 break;
11891189 }
1190 case "set_cold": {
1191 payloadHtml += "setCold";
1192 break;
1193 }
11941190 case "set_runtime_safety": {
11951191 payloadHtml += "setRuntimeSafety";
11961192 break;
lib/zig.h+8-2
......@@ -180,10 +180,16 @@ typedef char bool;
180180#define zig_export(sig, symbol, name) __asm(name " = " symbol)
181181#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
183191#if zig_has_builtin(debugtrap)
184192#define zig_breakpoint() __builtin_debugtrap()
185#elif zig_has_builtin(trap) || defined(zig_gnuc)
186#define zig_breakpoint() __builtin_trap()
187193#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
188194#define zig_breakpoint() __debugbreak()
189195#elif defined(__i386__) || defined(__x86_64__)
src/Air.zig+9-1
......@@ -232,7 +232,14 @@ pub const Inst = struct {
232232 /// Result type is always noreturn; no instructions in a block follow this one.
233233 /// Uses the `br` field.
234234 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.
236243 /// Result type is always void.
237244 breakpoint,
238245 /// Yields the return address of the current function.
......@@ -1186,6 +1193,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
11861193 .ret,
11871194 .ret_load,
11881195 .unreach,
1196 .trap,
11891197 => return Type.initTag(.noreturn),
11901198
11911199 .breakpoint,
src/AstGen.zig+17-4
......@@ -2609,8 +2609,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26092609 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
26102610 .breakpoint,
26112611 .fence,
2612 .set_align_stack,
26132612 .set_float_mode,
2613 .set_align_stack,
2614 .set_cold,
26142615 => break :b true,
26152616 else => break :b false,
26162617 },
......@@ -2630,6 +2631,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26302631 .repeat_inline,
26312632 .panic,
26322633 .panic_comptime,
2634 .trap,
26332635 .check_comptime_control_flow,
26342636 => {
26352637 noreturn_src_node = statement;
......@@ -2658,7 +2660,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26582660 .validate_struct_init_comptime,
26592661 .validate_array_init,
26602662 .validate_array_init_comptime,
2661 .set_cold,
26622663 .set_runtime_safety,
26632664 .closure_capture,
26642665 .memcpy,
......@@ -8081,6 +8082,14 @@ fn builtinCall(
80818082 });
80828083 return rvalue(gz, ri, result, node);
80838084 },
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 },
80848093
80858094 .src => {
80868095 const token_starts = tree.tokens.items(.start);
......@@ -8100,7 +8109,7 @@ fn builtinCall(
81008109 .error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node),
81018110 .frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node),
81028111 .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),
81048113
81058114 .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
81068115 .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
......@@ -8114,7 +8123,6 @@ fn builtinCall(
81148123 .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int),
81158124 .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .embed_file),
81168125 .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),
81188126 .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety),
81198127 .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt),
81208128 .sin => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sin),
......@@ -8174,6 +8182,11 @@ fn builtinCall(
81748182 try emitDbgNode(gz, node);
81758183 return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic);
81768184 },
8185 .trap => {
8186 try emitDbgNode(gz, node);
8187 _ = try gz.addNode(.trap, node);
8188 return rvalue(gz, ri, .void_value, node);
8189 },
81778190 .error_to_int => {
81788191 const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
81798192 const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{
src/Autodoc.zig-1
......@@ -1338,7 +1338,6 @@ fn walkInstruction(
13381338 .embed_file,
13391339 .error_name,
13401340 .panic,
1341 .set_cold, // @check
13421341 .set_runtime_safety, // @check
13431342 .sqrt,
13441343 .sin,
src/BuiltinFn.zig+8
......@@ -109,6 +109,7 @@ pub const Tag = enum {
109109 sub_with_overflow,
110110 tag_name,
111111 This,
112 trap,
112113 truncate,
113114 Type,
114115 type_info,
......@@ -915,6 +916,13 @@ pub const list = list: {
915916 .param_count = 0,
916917 },
917918 },
919 .{
920 "@trap",
921 .{
922 .tag = .trap,
923 .param_count = 0,
924 },
925 },
918926 .{
919927 "@truncate",
920928 .{
src/Liveness.zig+2
......@@ -226,6 +226,7 @@ pub fn categorizeOperand(
226226 .ret_ptr,
227227 .constant,
228228 .const_ty,
229 .trap,
229230 .breakpoint,
230231 .dbg_stmt,
231232 .dbg_inline_begin,
......@@ -848,6 +849,7 @@ fn analyzeInst(
848849 .ret_ptr,
849850 .constant,
850851 .const_ty,
852 .trap,
851853 .breakpoint,
852854 .dbg_stmt,
853855 .dbg_inline_begin,
src/Sema.zig+18-9
......@@ -1101,6 +1101,7 @@ fn analyzeBodyInner(
11011101 .@"unreachable" => break sema.zirUnreachable(block, inst),
11021102 .panic => break sema.zirPanic(block, inst, false),
11031103 .panic_comptime => break sema.zirPanic(block, inst, true),
1104 .trap => break sema.zirTrap(block, inst),
11041105 // zig fmt: on
11051106
11061107 .extended => ext: {
......@@ -1167,6 +1168,11 @@ fn analyzeBodyInner(
11671168 i += 1;
11681169 continue;
11691170 },
1171 .set_cold => {
1172 try sema.zirSetCold(block, extended);
1173 i += 1;
1174 continue;
1175 },
11701176 .breakpoint => {
11711177 if (!block.is_comptime) {
11721178 _ = try block.addNoOp(.breakpoint);
......@@ -1304,11 +1310,6 @@ fn analyzeBodyInner(
13041310 i += 1;
13051311 continue;
13061312 },
1307 .set_cold => {
1308 try sema.zirSetCold(block, inst);
1309 i += 1;
1310 continue;
1311 },
13121313 .set_runtime_safety => {
13131314 try sema.zirSetRuntimeSafety(block, inst);
13141315 i += 1;
......@@ -5144,6 +5145,14 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo
51445145 return always_noreturn;
51455146}
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
51475156fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
51485157 const tracy = trace(@src());
51495158 defer tracy.end();
......@@ -5721,10 +5730,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
57215730 gop.value_ptr.* = .{ .alignment = alignment, .src = src };
57225731}
57235732
5724fn 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");
5733fn 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");
57285737 const func = sema.func orelse return; // does nothing outside a function
57295738 func.is_cold = is_cold;
57305739}
src/Zir.zig+13-8
......@@ -617,7 +617,7 @@ pub const Inst = struct {
617617 /// Uses the `un_node` field.
618618 typeof_log2_int_type,
619619 /// Asserts control-flow will not reach this instruction (`unreachable`).
620 /// Uses the `unreachable` union field.
620 /// Uses the `@"unreachable"` union field.
621621 @"unreachable",
622622 /// Bitwise XOR. `^`
623623 /// Uses the `pl_node` union field. Payload is `Bin`.
......@@ -808,8 +808,9 @@ pub const Inst = struct {
808808 panic,
809809 /// Same as `panic` but forces comptime.
810810 panic_comptime,
811 /// Implement builtin `@setCold`. Uses `un_node`.
812 set_cold,
811 /// Implements `@trap`.
812 /// Uses the `node` field.
813 trap,
813814 /// Implement builtin `@setRuntimeSafety`. Uses `un_node`.
814815 set_runtime_safety,
815816 /// Implement builtin `@sqrt`. Uses `un_node`.
......@@ -1187,7 +1188,6 @@ pub const Inst = struct {
11871188 .bool_to_int,
11881189 .embed_file,
11891190 .error_name,
1190 .set_cold,
11911191 .set_runtime_safety,
11921192 .sqrt,
11931193 .sin,
......@@ -1277,6 +1277,7 @@ pub const Inst = struct {
12771277 .repeat_inline,
12781278 .panic,
12791279 .panic_comptime,
1280 .trap,
12801281 .check_comptime_control_flow,
12811282 => true,
12821283 };
......@@ -1323,7 +1324,6 @@ pub const Inst = struct {
13231324 .validate_deref,
13241325 .@"export",
13251326 .export_value,
1326 .set_cold,
13271327 .set_runtime_safety,
13281328 .memcpy,
13291329 .memset,
......@@ -1553,6 +1553,7 @@ pub const Inst = struct {
15531553 .repeat_inline,
15541554 .panic,
15551555 .panic_comptime,
1556 .trap,
15561557 .for_len,
15571558 .@"try",
15581559 .try_ptr,
......@@ -1561,7 +1562,7 @@ pub const Inst = struct {
15611562 => false,
15621563
15631564 .extended => switch (data.extended.opcode) {
1564 .breakpoint, .fence => true,
1565 .fence, .set_cold, .breakpoint => true,
15651566 else => false,
15661567 },
15671568 };
......@@ -1750,7 +1751,7 @@ pub const Inst = struct {
17501751 .error_name = .un_node,
17511752 .panic = .un_node,
17521753 .panic_comptime = .un_node,
1753 .set_cold = .un_node,
1754 .trap = .node,
17541755 .set_runtime_safety = .un_node,
17551756 .sqrt = .un_node,
17561757 .sin = .un_node,
......@@ -1979,11 +1980,15 @@ pub const Inst = struct {
19791980 /// Implement builtin `@setAlignStack`.
19801981 /// `operand` is payload index to `UnNode`.
19811982 set_align_stack,
1983 /// Implements `@setCold`.
1984 /// `operand` is payload index to `UnNode`.
1985 set_cold,
19821986 /// Implements the `@errSetCast` builtin.
19831987 /// `operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand.
19841988 err_set_cast,
19851989 /// `operand` is payload index to `UnNode`.
19861990 await_nosuspend,
1991 /// Implements `@breakpoint`.
19871992 /// `operand` is `src_node: i32`.
19881993 breakpoint,
19891994 /// Implements the `@select` builtin.
......@@ -1997,7 +2002,7 @@ pub const Inst = struct {
19972002 int_to_error,
19982003 /// Implement builtin `@Type`.
19992004 /// `operand` is payload index to `UnNode`.
2000 /// `small` contains `NameStrategy
2005 /// `small` contains `NameStrategy`.
20012006 reify,
20022007 /// Implements the `@asyncCall` builtin.
20032008 /// `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 {
733733 .bitcast => try self.airBitCast(inst),
734734 .block => try self.airBlock(inst),
735735 .br => try self.airBr(inst),
736 .trap => try self.airTrap(),
736737 .breakpoint => try self.airBreakpoint(),
737738 .ret_addr => try self.airRetAddr(inst),
738739 .frame_addr => try self.airFrameAddress(inst),
......@@ -4194,10 +4195,18 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
41944195 return self.finishAir(inst, result, .{ .none, .none, .none });
41954196}
41964197
4198fn airTrap(self: *Self) !void {
4199 _ = try self.addInst(.{
4200 .tag = .brk,
4201 .data = .{ .imm16 = 0x0001 },
4202 });
4203 return self.finishAirBookkeeping();
4204}
4205
41974206fn airBreakpoint(self: *Self) !void {
41984207 _ = try self.addInst(.{
41994208 .tag = .brk,
4200 .data = .{ .imm16 = 1 },
4209 .data = .{ .imm16 = 0xf000 },
42014210 });
42024211 return self.finishAirBookkeeping();
42034212}
src/arch/arm/CodeGen.zig+9
......@@ -717,6 +717,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
717717 .bitcast => try self.airBitCast(inst),
718718 .block => try self.airBlock(inst),
719719 .br => try self.airBr(inst),
720 .trap => try self.airTrap(),
720721 .breakpoint => try self.airBreakpoint(),
721722 .ret_addr => try self.airRetAddr(inst),
722723 .frame_addr => try self.airFrameAddress(inst),
......@@ -4142,6 +4143,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
41424143 return self.finishAir(inst, result, .{ .none, .none, .none });
41434144}
41444145
4146fn airTrap(self: *Self) !void {
4147 _ = try self.addInst(.{
4148 .tag = .undefined_instruction,
4149 .data = .{ .nop = {} },
4150 });
4151 return self.finishAirBookkeeping();
4152}
4153
41454154fn airBreakpoint(self: *Self) !void {
41464155 _ = try self.addInst(.{
41474156 .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
22//! machine code
33
44const Emit = @This();
......@@ -15,7 +15,7 @@ const Target = std.Target;
1515const assert = std.debug.assert;
1616const Instruction = bits.Instruction;
1717const Register = bits.Register;
18const log = std.log.scoped(.aarch64_emit);
18const log = std.log.scoped(.aarch32_emit);
1919const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2020const CodeGen = @import("CodeGen.zig");
2121
......@@ -100,6 +100,7 @@ pub fn emitMir(
100100
101101 .b => try emit.mirBranch(inst),
102102
103 .undefined_instruction => try emit.mirUndefinedInstruction(),
103104 .bkpt => try emit.mirExceptionGeneration(inst),
104105
105106 .blx => try emit.mirBranchExchange(inst),
......@@ -494,6 +495,10 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
494495 }
495496}
496497
498fn mirUndefinedInstruction(emit: *Emit) !void {
499 try emit.writeInstruction(Instruction.undefinedInstruction());
500}
501
497502fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void {
498503 const tag = emit.mir.instructions.items(.tag)[inst];
499504 const imm16 = emit.mir.instructions.items(.data)[inst].imm16;
src/arch/arm/Mir.zig+2
......@@ -35,6 +35,8 @@ pub const Inst = struct {
3535 asr,
3636 /// Branch
3737 b,
38 /// Undefined instruction
39 undefined_instruction,
3840 /// Breakpoint
3941 bkpt,
4042 /// Branch with Link and Exchange
src/arch/arm/bits.zig+11
......@@ -307,6 +307,9 @@ pub const Instruction = union(enum) {
307307 fixed: u4 = 0b1111,
308308 cond: u4,
309309 },
310 undefined_instruction: packed struct {
311 imm32: u32 = 0xe7ffdefe,
312 },
310313 breakpoint: packed struct {
311314 imm4: u4,
312315 fixed_1: u4 = 0b0111,
......@@ -613,6 +616,7 @@ pub const Instruction = union(enum) {
613616 .branch => |v| @bitCast(u32, v),
614617 .branch_exchange => |v| @bitCast(u32, v),
615618 .supervisor_call => |v| @bitCast(u32, v),
619 .undefined_instruction => |v| v.imm32,
616620 .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),
617621 };
618622 }
......@@ -890,6 +894,13 @@ pub const Instruction = union(enum) {
890894 };
891895 }
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
893904 fn breakpoint(imm: u16) Instruction {
894905 return Instruction{
895906 .breakpoint = .{
src/arch/riscv64/CodeGen.zig+9
......@@ -547,6 +547,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
547547 .bitcast => try self.airBitCast(inst),
548548 .block => try self.airBlock(inst),
549549 .br => try self.airBr(inst),
550 .trap => try self.airTrap(),
550551 .breakpoint => try self.airBreakpoint(),
551552 .ret_addr => try self.airRetAddr(inst),
552553 .frame_addr => try self.airFrameAddress(inst),
......@@ -1649,6 +1650,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
16491650 return self.finishAir(inst, mcv, .{ .none, .none, .none });
16501651}
16511652
1653fn airTrap(self: *Self) !void {
1654 _ = try self.addInst(.{
1655 .tag = .unimp,
1656 .data = .{ .nop = {} },
1657 });
1658 return self.finishAirBookkeeping();
1659}
1660
16521661fn airBreakpoint(self: *Self) !void {
16531662 _ = try self.addInst(.{
16541663 .tag = .ebreak,
src/arch/riscv64/Emit.zig+2
......@@ -51,6 +51,7 @@ pub fn emitMir(
5151
5252 .ebreak => try emit.mirSystem(inst),
5353 .ecall => try emit.mirSystem(inst),
54 .unimp => try emit.mirSystem(inst),
5455
5556 .dbg_line => try emit.mirDbgLine(inst),
5657
......@@ -153,6 +154,7 @@ fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void {
153154 switch (tag) {
154155 .ebreak => try emit.writeInstruction(Instruction.ebreak),
155156 .ecall => try emit.writeInstruction(Instruction.ecall),
157 .unimp => try emit.writeInstruction(Instruction.unimp),
156158 else => unreachable,
157159 }
158160}
src/arch/riscv64/Mir.zig+1
......@@ -32,6 +32,7 @@ pub const Inst = struct {
3232 dbg_epilogue_begin,
3333 /// Pseudo-instruction: Update debug line
3434 dbg_line,
35 unimp,
3536 ebreak,
3637 ecall,
3738 jalr,
src/arch/riscv64/bits.zig+1
......@@ -380,6 +380,7 @@ pub const Instruction = union(enum) {
380380
381381 pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000);
382382 pub const ebreak = iType(0b1110011, 0b000, .zero, .zero, 0x001);
383 pub const unimp = iType(0, 0, .zero, .zero, 0);
383384};
384385
385386pub 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 {
562562 .bitcast => try self.airBitCast(inst),
563563 .block => try self.airBlock(inst),
564564 .br => try self.airBr(inst),
565 .trap => try self.airTrap(),
565566 .breakpoint => try self.airBreakpoint(),
566567 .ret_addr => @panic("TODO try self.airRetAddr(inst)"),
567568 .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
......@@ -1156,6 +1157,21 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
11561157 return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
11571158}
11581159
1160fn 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
11591175fn airBreakpoint(self: *Self) !void {
11601176 // ta 0x01
11611177 _ = try self.addInst(.{
src/arch/wasm/CodeGen.zig+7
......@@ -1827,6 +1827,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18271827 .arg => func.airArg(inst),
18281828 .bitcast => func.airBitcast(inst),
18291829 .block => func.airBlock(inst),
1830 .trap => func.airTrap(inst),
18301831 .breakpoint => func.airBreakpoint(inst),
18311832 .br => func.airBr(inst),
18321833 .bool_to_int => func.airBoolToInt(inst),
......@@ -3287,9 +3288,15 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
32873288 func.finishAir(inst, result, &.{ty_op.operand});
32883289}
32893290
3291fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3292 try func.addTag(.@"unreachable");
3293 func.finishAir(inst, .none, &.{});
3294}
3295
32903296fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
32913297 // unsupported by wasm itfunc. Can be implemented once we support DWARF
32923298 // for wasm
3299 try func.addTag(.@"unreachable");
32933300 func.finishAir(inst, .none, &.{});
32943301}
32953302
src/arch/x86_64/CodeGen.zig+10
......@@ -634,6 +634,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
634634 .bitcast => try self.airBitCast(inst),
635635 .block => try self.airBlock(inst),
636636 .br => try self.airBr(inst),
637 .trap => try self.airTrap(),
637638 .breakpoint => try self.airBreakpoint(),
638639 .ret_addr => try self.airRetAddr(inst),
639640 .frame_addr => try self.airFrameAddress(inst),
......@@ -3913,6 +3914,15 @@ fn genVarDbgInfo(
39133914 }
39143915}
39153916
3917fn 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
39163926fn airBreakpoint(self: *Self) !void {
39173927 _ = try self.addInst(.{
39183928 .tag = .interrupt,
src/arch/x86_64/Emit.zig+7
......@@ -166,6 +166,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
166166
167167 .@"test" => try emit.mirTest(inst),
168168
169 .ud => try emit.mirUndefinedInstruction(),
169170 .interrupt => try emit.mirInterrupt(inst),
170171 .nop => {}, // just skip it
171172
......@@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
234235 }
235236}
236237
238fn mirUndefinedInstruction(emit: *Emit) InnerError!void {
239 return lowerToZoEnc(.ud2, emit.code);
240}
241
237242fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
238243 const tag = emit.mir.instructions.items(.tag)[inst];
239244 assert(tag == .interrupt);
......@@ -1279,6 +1284,7 @@ const Tag = enum {
12791284 push,
12801285 pop,
12811286 @"test",
1287 ud2,
12821288 int3,
12831289 nop,
12841290 imul,
......@@ -1571,6 +1577,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
15711577 .zo => return switch (tag) {
15721578 .ret_near => OpCode.init(&.{0xc3}),
15731579 .ret_far => OpCode.init(&.{0xcb}),
1580 .ud2 => OpCode.init(&.{ 0x0F, 0x0B }),
15741581 .int3 => OpCode.init(&.{0xcc}),
15751582 .nop => OpCode.init(&.{0x90}),
15761583 .syscall => OpCode.init(&.{ 0x0f, 0x05 }),
src/arch/x86_64/Mir.zig+3
......@@ -329,6 +329,9 @@ pub const Inst = struct {
329329 /// TODO handle more cases
330330 @"test",
331331
332 /// Undefined Instruction
333 ud,
334
332335 /// Breakpoint form:
333336 /// 0b00 int3
334337 interrupt,
src/codegen/c.zig+6
......@@ -2741,6 +2741,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
27412741 .const_ty => unreachable, // excluded from function bodies
27422742 .arg => try airArg(f, inst),
27432743
2744 .trap => try airTrap(f.object.writer()),
27442745 .breakpoint => try airBreakpoint(f.object.writer()),
27452746 .ret_addr => try airRetAddr(f, inst),
27462747 .frame_addr => try airFrameAddress(f, inst),
......@@ -4428,6 +4429,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44284429 return local;
44294430}
44304431
4432fn airTrap(writer: anytype) !CValue {
4433 try writer.writeAll("zig_trap();\n");
4434 return .none;
4435}
4436
44314437fn airBreakpoint(writer: anytype) !CValue {
44324438 try writer.writeAll("zig_breakpoint();\n");
44334439 return .none;
src/codegen/llvm.zig+8
......@@ -4590,6 +4590,7 @@ pub const FuncGen = struct {
45904590 .block => try self.airBlock(inst),
45914591 .br => try self.airBr(inst),
45924592 .switch_br => try self.airSwitchBr(inst),
4593 .trap => try self.airTrap(inst),
45934594 .breakpoint => try self.airBreakpoint(inst),
45944595 .ret_addr => try self.airRetAddr(inst),
45954596 .frame_addr => try self.airFrameAddress(inst),
......@@ -8256,6 +8257,13 @@ pub const FuncGen = struct {
82568257 return fg.load(ptr, ptr_ty);
82578258 }
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
82598267 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
82608268 _ = inst;
82618269 const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});
src/print_air.zig+1
......@@ -194,6 +194,7 @@ const Writer = struct {
194194 .c_va_end,
195195 => try w.writeUnOp(s, inst),
196196
197 .trap,
197198 .breakpoint,
198199 .unreach,
199200 .ret_addr,
src/print_zir.zig+2-1
......@@ -196,7 +196,6 @@ const Writer = struct {
196196 .error_name,
197197 .panic,
198198 .panic_comptime,
199 .set_cold,
200199 .set_runtime_safety,
201200 .sqrt,
202201 .sin,
......@@ -411,6 +410,7 @@ const Writer = struct {
411410 .alloc_inferred_comptime_mut,
412411 .ret_ptr,
413412 .ret_type,
413 .trap,
414414 => try self.writeNode(stream, inst),
415415
416416 .error_value,
......@@ -503,6 +503,7 @@ const Writer = struct {
503503 .fence,
504504 .set_float_mode,
505505 .set_align_stack,
506 .set_cold,
506507 .wasm_memory_size,
507508 .error_to_int,
508509 .int_to_error,