mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
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.
This commit is contained in:
parent
d6bd00e855
commit
65368683ad
26 changed files with 178 additions and 10 deletions
|
|
@ -7818,12 +7818,14 @@ comptime {
|
|||
<p>
|
||||
This function inserts a platform-specific debug trap instruction which causes
|
||||
debuggers to break there.
|
||||
Unlike for {#syntax#}@trap(){#endsyntax#}, execution may continue after this point if the program is resumed.
|
||||
</p>
|
||||
<p>
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
|
||||
{#see_also|@trap#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@mulAdd#}
|
||||
<pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
|
@ -9393,6 +9395,19 @@ fn List(comptime T: type) type {
|
|||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@trap#}
|
||||
<pre>{#syntax#}@trap() noreturn{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function inserts a platform-specific trap/jam instruction which can be used to exit the program abnormally.
|
||||
This may be implemented by explicitly emitting an invalid instruction which may cause an illegal instruction exception of some sort.
|
||||
Unlike for {#syntax#}@breakpoint(){#endsyntax#}, execution does not continue after this point.
|
||||
</p>
|
||||
<p>
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
{#see_also|@breakpoint#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@truncate#}
|
||||
<pre>{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
|
|
|||
10
lib/zig.h
10
lib/zig.h
|
|
@ -180,10 +180,16 @@ typedef char bool;
|
|||
#define zig_export(sig, symbol, name) __asm(name " = " symbol)
|
||||
#endif
|
||||
|
||||
#if zig_has_builtin(trap)
|
||||
#define zig_trap() __builtin_trap()
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#define zig_trap() __asm__ volatile("ud2");
|
||||
#else
|
||||
#define zig_trap() raise(SIGILL)
|
||||
#endif
|
||||
|
||||
#if zig_has_builtin(debugtrap)
|
||||
#define zig_breakpoint() __builtin_debugtrap()
|
||||
#elif zig_has_builtin(trap) || defined(zig_gnuc)
|
||||
#define zig_breakpoint() __builtin_trap()
|
||||
#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#define zig_breakpoint() __debugbreak()
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
|
|
|
|||
10
src/Air.zig
10
src/Air.zig
|
|
@ -232,7 +232,14 @@ pub const Inst = struct {
|
|||
/// Result type is always noreturn; no instructions in a block follow this one.
|
||||
/// Uses the `br` field.
|
||||
br,
|
||||
/// Lowers to a hardware trap instruction, or the next best thing.
|
||||
/// Lowers to a trap/jam instruction causing program abortion.
|
||||
/// This may lower to an instruction known to be invalid.
|
||||
/// Sometimes, for the lack of a better instruction, `trap` and `breakpoint` may compile down to the same code.
|
||||
/// Result type is always noreturn; no instructions in a block follow this one.
|
||||
trap,
|
||||
/// Lowers to a trap instruction causing debuggers to break here, or the next best thing.
|
||||
/// The debugger or something else may allow the program to resume after this point.
|
||||
/// Sometimes, for the lack of a better instruction, `trap` and `breakpoint` may compile down to the same code.
|
||||
/// Result type is always void.
|
||||
breakpoint,
|
||||
/// Yields the return address of the current function.
|
||||
|
|
@ -1186,6 +1193,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
|||
.ret,
|
||||
.ret_load,
|
||||
.unreach,
|
||||
.trap,
|
||||
=> return Type.initTag(.noreturn),
|
||||
|
||||
.breakpoint,
|
||||
|
|
|
|||
|
|
@ -2631,6 +2631,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
.trap,
|
||||
.check_comptime_control_flow,
|
||||
=> {
|
||||
noreturn_src_node = statement;
|
||||
|
|
@ -8105,7 +8106,7 @@ fn builtinCall(
|
|||
.error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node),
|
||||
.frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node),
|
||||
.frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
|
||||
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
|
||||
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
|
||||
|
||||
.type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
|
||||
.size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
|
||||
|
|
@ -8178,6 +8179,11 @@ fn builtinCall(
|
|||
try emitDbgNode(gz, node);
|
||||
return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic);
|
||||
},
|
||||
.trap => {
|
||||
try emitDbgNode(gz, node);
|
||||
_ = try gz.addNode(.trap, node);
|
||||
return rvalue(gz, ri, .void_value, node);
|
||||
},
|
||||
.error_to_int => {
|
||||
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
|
||||
const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ pub const Tag = enum {
|
|||
sub_with_overflow,
|
||||
tag_name,
|
||||
This,
|
||||
trap,
|
||||
truncate,
|
||||
Type,
|
||||
type_info,
|
||||
|
|
@ -915,6 +916,13 @@ pub const list = list: {
|
|||
.param_count = 0,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@trap",
|
||||
.{
|
||||
.tag = .trap,
|
||||
.param_count = 0,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@truncate",
|
||||
.{
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ pub fn categorizeOperand(
|
|||
.ret_ptr,
|
||||
.constant,
|
||||
.const_ty,
|
||||
.trap,
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.dbg_inline_begin,
|
||||
|
|
@ -848,6 +849,7 @@ fn analyzeInst(
|
|||
.ret_ptr,
|
||||
.constant,
|
||||
.const_ty,
|
||||
.trap,
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.dbg_inline_begin,
|
||||
|
|
|
|||
|
|
@ -1101,6 +1101,7 @@ fn analyzeBodyInner(
|
|||
.@"unreachable" => break sema.zirUnreachable(block, inst),
|
||||
.panic => break sema.zirPanic(block, inst, false),
|
||||
.panic_comptime => break sema.zirPanic(block, inst, true),
|
||||
.trap => break sema.zirTrap(block, inst),
|
||||
// zig fmt: on
|
||||
|
||||
.extended => ext: {
|
||||
|
|
@ -5144,6 +5145,14 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo
|
|||
return always_noreturn;
|
||||
}
|
||||
|
||||
fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
|
||||
const src_node = sema.code.instructions.items(.data)[inst].node;
|
||||
const src = LazySrcLoc.nodeOffset(src_node);
|
||||
sema.src = src;
|
||||
_ = try block.addNoOp(.trap);
|
||||
return always_noreturn;
|
||||
}
|
||||
|
||||
fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
|
|
|||
11
src/Zir.zig
11
src/Zir.zig
|
|
@ -617,7 +617,7 @@ pub const Inst = struct {
|
|||
/// Uses the `un_node` field.
|
||||
typeof_log2_int_type,
|
||||
/// Asserts control-flow will not reach this instruction (`unreachable`).
|
||||
/// Uses the `unreachable` union field.
|
||||
/// Uses the `@"unreachable"` union field.
|
||||
@"unreachable",
|
||||
/// Bitwise XOR. `^`
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
|
|
@ -808,6 +808,9 @@ pub const Inst = struct {
|
|||
panic,
|
||||
/// Same as `panic` but forces comptime.
|
||||
panic_comptime,
|
||||
/// Implements `@trap`.
|
||||
/// Uses the `node` field.
|
||||
trap,
|
||||
/// Implement builtin `@setRuntimeSafety`. Uses `un_node`.
|
||||
set_runtime_safety,
|
||||
/// Implement builtin `@sqrt`. Uses `un_node`.
|
||||
|
|
@ -1274,6 +1277,7 @@ pub const Inst = struct {
|
|||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
.trap,
|
||||
.check_comptime_control_flow,
|
||||
=> true,
|
||||
};
|
||||
|
|
@ -1549,6 +1553,7 @@ pub const Inst = struct {
|
|||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
.trap,
|
||||
.for_len,
|
||||
.@"try",
|
||||
.try_ptr,
|
||||
|
|
@ -1746,6 +1751,7 @@ pub const Inst = struct {
|
|||
.error_name = .un_node,
|
||||
.panic = .un_node,
|
||||
.panic_comptime = .un_node,
|
||||
.trap = .node,
|
||||
.set_runtime_safety = .un_node,
|
||||
.sqrt = .un_node,
|
||||
.sin = .un_node,
|
||||
|
|
@ -1982,6 +1988,7 @@ pub const Inst = struct {
|
|||
err_set_cast,
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
await_nosuspend,
|
||||
/// Implements `@breakpoint`.
|
||||
/// `operand` is `src_node: i32`.
|
||||
breakpoint,
|
||||
/// Implements the `@select` builtin.
|
||||
|
|
@ -1995,7 +2002,7 @@ pub const Inst = struct {
|
|||
int_to_error,
|
||||
/// Implement builtin `@Type`.
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
/// `small` contains `NameStrategy
|
||||
/// `small` contains `NameStrategy`.
|
||||
reify,
|
||||
/// Implements the `@asyncCall` builtin.
|
||||
/// `operand` is payload index to `AsyncCall`.
|
||||
|
|
|
|||
|
|
@ -737,6 +737,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.trap => try self.airTrap(),
|
||||
.breakpoint => try self.airBreakpoint(),
|
||||
.ret_addr => try self.airRetAddr(inst),
|
||||
.frame_addr => try self.airFrameAddress(inst),
|
||||
|
|
@ -4198,10 +4199,18 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
|
|||
return self.finishAir(inst, result, .{ .none, .none, .none });
|
||||
}
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .brk,
|
||||
.data = .{ .imm16 = 0x0001 },
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .brk,
|
||||
.data = .{ .imm16 = 1 },
|
||||
.data = .{ .imm16 = 0xf000 },
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -721,6 +721,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.trap => try self.airTrap(),
|
||||
.breakpoint => try self.airBreakpoint(),
|
||||
.ret_addr => try self.airRetAddr(inst),
|
||||
.frame_addr => try self.airFrameAddress(inst),
|
||||
|
|
@ -4146,6 +4147,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
|
|||
return self.finishAir(inst, result, .{ .none, .none, .none });
|
||||
}
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .undefined_instruction,
|
||||
.data = .{ .nop = {} },
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .bkpt,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//! This file contains the functionality for lowering AArch64 MIR into
|
||||
//! This file contains the functionality for lowering AArch32 MIR into
|
||||
//! machine code
|
||||
|
||||
const Emit = @This();
|
||||
|
|
@ -15,7 +15,7 @@ const Target = std.Target;
|
|||
const assert = std.debug.assert;
|
||||
const Instruction = bits.Instruction;
|
||||
const Register = bits.Register;
|
||||
const log = std.log.scoped(.aarch64_emit);
|
||||
const log = std.log.scoped(.aarch32_emit);
|
||||
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
|
||||
const CodeGen = @import("CodeGen.zig");
|
||||
|
||||
|
|
@ -100,6 +100,7 @@ pub fn emitMir(
|
|||
|
||||
.b => try emit.mirBranch(inst),
|
||||
|
||||
.undefined_instruction => try emit.mirUndefinedInstruction(),
|
||||
.bkpt => try emit.mirExceptionGeneration(inst),
|
||||
|
||||
.blx => try emit.mirBranchExchange(inst),
|
||||
|
|
@ -494,6 +495,10 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
|
|||
}
|
||||
}
|
||||
|
||||
fn mirUndefinedInstruction(emit: *Emit) !void {
|
||||
try emit.writeInstruction(Instruction.undefinedInstruction());
|
||||
}
|
||||
|
||||
fn mirExceptionGeneration(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const imm16 = emit.mir.instructions.items(.data)[inst].imm16;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ pub const Inst = struct {
|
|||
asr,
|
||||
/// Branch
|
||||
b,
|
||||
/// Undefined instruction
|
||||
undefined_instruction,
|
||||
/// Breakpoint
|
||||
bkpt,
|
||||
/// Branch with Link and Exchange
|
||||
|
|
|
|||
|
|
@ -307,6 +307,9 @@ pub const Instruction = union(enum) {
|
|||
fixed: u4 = 0b1111,
|
||||
cond: u4,
|
||||
},
|
||||
undefined_instruction: packed struct {
|
||||
imm32: u32 = 0xe7ffdefe,
|
||||
},
|
||||
breakpoint: packed struct {
|
||||
imm4: u4,
|
||||
fixed_1: u4 = 0b0111,
|
||||
|
|
@ -613,6 +616,7 @@ pub const Instruction = union(enum) {
|
|||
.branch => |v| @bitCast(u32, v),
|
||||
.branch_exchange => |v| @bitCast(u32, v),
|
||||
.supervisor_call => |v| @bitCast(u32, v),
|
||||
.undefined_instruction => |v| v.imm32,
|
||||
.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),
|
||||
};
|
||||
}
|
||||
|
|
@ -890,6 +894,13 @@ pub const Instruction = union(enum) {
|
|||
};
|
||||
}
|
||||
|
||||
// This instruction has no official mnemonic equivalent so it is public as-is.
|
||||
pub fn undefinedInstruction() Instruction {
|
||||
return Instruction{
|
||||
.undefined_instruction = .{},
|
||||
};
|
||||
}
|
||||
|
||||
fn breakpoint(imm: u16) Instruction {
|
||||
return Instruction{
|
||||
.breakpoint = .{
|
||||
|
|
|
|||
|
|
@ -550,6 +550,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.trap => try self.airTrap(),
|
||||
.breakpoint => try self.airBreakpoint(),
|
||||
.ret_addr => try self.airRetAddr(inst),
|
||||
.frame_addr => try self.airFrameAddress(inst),
|
||||
|
|
@ -1652,6 +1653,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
|
|||
return self.finishAir(inst, mcv, .{ .none, .none, .none });
|
||||
}
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .unimp,
|
||||
.data = .{ .nop = {} },
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ebreak,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ pub fn emitMir(
|
|||
|
||||
.ebreak => try emit.mirSystem(inst),
|
||||
.ecall => try emit.mirSystem(inst),
|
||||
.unimp => try emit.mirSystem(inst),
|
||||
|
||||
.dbg_line => try emit.mirDbgLine(inst),
|
||||
|
||||
|
|
@ -153,6 +154,7 @@ fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void {
|
|||
switch (tag) {
|
||||
.ebreak => try emit.writeInstruction(Instruction.ebreak),
|
||||
.ecall => try emit.writeInstruction(Instruction.ecall),
|
||||
.unimp => try emit.writeInstruction(Instruction.unimp),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ pub const Inst = struct {
|
|||
dbg_epilogue_begin,
|
||||
/// Pseudo-instruction: Update debug line
|
||||
dbg_line,
|
||||
unimp,
|
||||
ebreak,
|
||||
ecall,
|
||||
jalr,
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ pub const Instruction = union(enum) {
|
|||
|
||||
pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000);
|
||||
pub const ebreak = iType(0b1110011, 0b000, .zero, .zero, 0x001);
|
||||
pub const unimp = iType(0, 0, .zero, .zero, 0);
|
||||
};
|
||||
|
||||
pub const Register = enum(u6) {
|
||||
|
|
|
|||
|
|
@ -566,6 +566,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.trap => try self.airTrap(),
|
||||
.breakpoint => try self.airBreakpoint(),
|
||||
.ret_addr => @panic("TODO try self.airRetAddr(inst)"),
|
||||
.frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
|
||||
|
|
@ -1160,6 +1161,21 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
|
|||
return self.finishAir(inst, .dead, .{ branch.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
// ta 0x05
|
||||
_ = try self.addInst(.{
|
||||
.tag = .tcc,
|
||||
.data = .{
|
||||
.trap = .{
|
||||
.is_imm = true,
|
||||
.cond = .al,
|
||||
.rs2_or_imm = .{ .imm = 0x05 },
|
||||
},
|
||||
},
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
// ta 0x01
|
||||
_ = try self.addInst(.{
|
||||
|
|
|
|||
|
|
@ -1829,6 +1829,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
|||
.arg => func.airArg(inst),
|
||||
.bitcast => func.airBitcast(inst),
|
||||
.block => func.airBlock(inst),
|
||||
.trap => func.airTrap(inst),
|
||||
.breakpoint => func.airBreakpoint(inst),
|
||||
.br => func.airBr(inst),
|
||||
.bool_to_int => func.airBoolToInt(inst),
|
||||
|
|
@ -3289,6 +3290,11 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
|||
func.finishAir(inst, result, &.{ty_op.operand});
|
||||
}
|
||||
|
||||
fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
try func.addTag(.@"unreachable");
|
||||
func.finishAir(inst, .none, &.{});
|
||||
}
|
||||
|
||||
fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
// unsupported by wasm itfunc. Can be implemented once we support DWARF
|
||||
// for wasm
|
||||
|
|
|
|||
|
|
@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.trap => try self.airTrap(),
|
||||
.breakpoint => try self.airBreakpoint(),
|
||||
.ret_addr => try self.airRetAddr(inst),
|
||||
.frame_addr => try self.airFrameAddress(inst),
|
||||
|
|
@ -3917,6 +3918,15 @@ fn genVarDbgInfo(
|
|||
}
|
||||
}
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ud,
|
||||
.ops = Mir.Inst.Ops.encode(.{}),
|
||||
.data = undefined,
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .interrupt,
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
|
|||
|
||||
.@"test" => try emit.mirTest(inst),
|
||||
|
||||
.ud => try emit.mirUndefinedInstruction(),
|
||||
.interrupt => try emit.mirInterrupt(inst),
|
||||
.nop => {}, // just skip it
|
||||
|
||||
|
|
@ -234,6 +235,10 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
|
|||
}
|
||||
}
|
||||
|
||||
fn mirUndefinedInstruction(emit: *Emit) InnerError!void {
|
||||
return lowerToZoEnc(.ud2, emit.code);
|
||||
}
|
||||
|
||||
fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
assert(tag == .interrupt);
|
||||
|
|
@ -1279,6 +1284,7 @@ const Tag = enum {
|
|||
push,
|
||||
pop,
|
||||
@"test",
|
||||
ud2,
|
||||
int3,
|
||||
nop,
|
||||
imul,
|
||||
|
|
@ -1571,6 +1577,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
|
|||
.zo => return switch (tag) {
|
||||
.ret_near => OpCode.init(&.{0xc3}),
|
||||
.ret_far => OpCode.init(&.{0xcb}),
|
||||
.ud2 => OpCode.init(&.{ 0x0F, 0x0B }),
|
||||
.int3 => OpCode.init(&.{0xcc}),
|
||||
.nop => OpCode.init(&.{0x90}),
|
||||
.syscall => OpCode.init(&.{ 0x0f, 0x05 }),
|
||||
|
|
|
|||
|
|
@ -329,6 +329,9 @@ pub const Inst = struct {
|
|||
/// TODO handle more cases
|
||||
@"test",
|
||||
|
||||
/// Undefined Instruction
|
||||
ud,
|
||||
|
||||
/// Breakpoint form:
|
||||
/// 0b00 int3
|
||||
interrupt,
|
||||
|
|
|
|||
|
|
@ -2741,6 +2741,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
|
|||
.const_ty => unreachable, // excluded from function bodies
|
||||
.arg => try airArg(f, inst),
|
||||
|
||||
.trap => try airTrap(f.object.writer()),
|
||||
.breakpoint => try airBreakpoint(f.object.writer()),
|
||||
.ret_addr => try airRetAddr(f, inst),
|
||||
.frame_addr => try airFrameAddress(f, inst),
|
||||
|
|
@ -4428,6 +4429,11 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
|
|||
return local;
|
||||
}
|
||||
|
||||
fn airTrap(writer: anytype) !CValue {
|
||||
try writer.writeAll("zig_trap();\n");
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn airBreakpoint(writer: anytype) !CValue {
|
||||
try writer.writeAll("zig_breakpoint();\n");
|
||||
return .none;
|
||||
|
|
|
|||
|
|
@ -4590,6 +4590,7 @@ pub const FuncGen = struct {
|
|||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.switch_br => try self.airSwitchBr(inst),
|
||||
.trap => try self.airTrap(inst),
|
||||
.breakpoint => try self.airBreakpoint(inst),
|
||||
.ret_addr => try self.airRetAddr(inst),
|
||||
.frame_addr => try self.airFrameAddress(inst),
|
||||
|
|
@ -8256,6 +8257,13 @@ pub const FuncGen = struct {
|
|||
return fg.load(ptr, ptr_ty);
|
||||
}
|
||||
|
||||
fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
|
||||
_ = inst;
|
||||
const llvm_fn = self.getIntrinsic("llvm.trap", &.{});
|
||||
_ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, "");
|
||||
return null;
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
|
||||
_ = inst;
|
||||
const llvm_fn = self.getIntrinsic("llvm.debugtrap", &.{});
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ const Writer = struct {
|
|||
.c_va_end,
|
||||
=> try w.writeUnOp(s, inst),
|
||||
|
||||
.trap,
|
||||
.breakpoint,
|
||||
.unreach,
|
||||
.ret_addr,
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ const Writer = struct {
|
|||
.alloc_inferred_comptime_mut,
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
.trap,
|
||||
=> try self.writeNode(stream, inst),
|
||||
|
||||
.error_value,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue