Skip to content
/ zig Public
forked from ziglang/zig

Commit

Permalink
compiler: Implement @disableIntrinsics() builtin function.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexrp committed Dec 7, 2024
1 parent 4894ac4 commit c454172
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 14 deletions.
2 changes: 2 additions & 0 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.set_float_mode,
.branch_hint,
=> break :b true,
Expand Down Expand Up @@ -9447,6 +9448,7 @@ fn builtinCall(
.frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
.disable_instrumentation => return rvalue(gz, ri, try gz.addNodeExtended(.disable_instrumentation, node), node),
.disable_intrinsics => return rvalue(gz, ri, try gz.addNodeExtended(.disable_intrinsics, 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),
Expand Down
1 change: 1 addition & 0 deletions lib/std/zig/AstRlAnnotate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.frame,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.in_comptime,
.panic,
.trap,
Expand Down
9 changes: 9 additions & 0 deletions lib/std/zig/BuiltinFn.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub const Tag = enum {
branch_hint,
breakpoint,
disable_instrumentation,
disable_intrinsics,
mul_add,
byte_swap,
bit_reverse,
Expand Down Expand Up @@ -262,6 +263,14 @@ pub const list = list: {
.illegal_outside_function = true,
},
},
.{
"@disableIntrinsics",
.{
.tag = .disable_intrinsics,
.param_count = 0,
.illegal_outside_function = true,
},
},
.{
"@mulAdd",
.{
Expand Down
9 changes: 8 additions & 1 deletion lib/std/zig/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1575,7 +1575,11 @@ pub const Inst = struct {
=> false,

.extended => switch (data.extended.opcode) {
.branch_hint, .breakpoint, .disable_instrumentation => true,
.branch_hint,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
=> true,
else => false,
},
};
Expand Down Expand Up @@ -1996,6 +2000,8 @@ pub const Inst = struct {
breakpoint,
/// Implement builtin `@disableInstrumentation`. `operand` is `src_node: i32`.
disable_instrumentation,
/// Implement builtin `@disableIntrinsics`. `operand` is `src_node: i32`.
disable_intrinsics,
/// Implements the `@select` builtin.
/// `operand` is payload index to `Select`.
select,
Expand Down Expand Up @@ -4042,6 +4048,7 @@ fn findDeclsInner(
.await_nosuspend,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.select,
.int_from_error,
.error_from_int,
Expand Down
19 changes: 18 additions & 1 deletion src/InternPool.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5562,8 +5562,9 @@ pub const FuncAnalysis = packed struct(u32) {
/// True if this function has an inferred error set.
inferred_error_set: bool,
disable_instrumentation: bool,
disable_intrinsics: bool,

_: u23 = 0,
_: u22 = 0,

pub const State = enum(u2) {
/// The runtime function has never been referenced.
Expand Down Expand Up @@ -8597,6 +8598,7 @@ pub fn getFuncDecl(
.calls_or_awaits_errorable_fn = false,
.inferred_error_set = false,
.disable_instrumentation = false,
.disable_intrinsics = false,
},
.owner_nav = key.owner_nav,
.ty = key.ty,
Expand Down Expand Up @@ -8700,6 +8702,7 @@ pub fn getFuncDeclIes(
.calls_or_awaits_errorable_fn = false,
.inferred_error_set = true,
.disable_instrumentation = false,
.disable_intrinsics = false,
},
.owner_nav = key.owner_nav,
.ty = func_ty,
Expand Down Expand Up @@ -8891,6 +8894,7 @@ pub fn getFuncInstance(
.calls_or_awaits_errorable_fn = false,
.inferred_error_set = false,
.disable_instrumentation = false,
.disable_intrinsics = false,
},
// This is populated after we create the Nav below. It is not read
// by equality or hashing functions.
Expand Down Expand Up @@ -8990,6 +8994,7 @@ pub fn getFuncInstanceIes(
.calls_or_awaits_errorable_fn = false,
.inferred_error_set = true,
.disable_instrumentation = false,
.disable_intrinsics = false,
},
// This is populated after we create the Nav below. It is not read
// by equality or hashing functions.
Expand Down Expand Up @@ -11780,6 +11785,18 @@ pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void {
@atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
}

pub fn funcSetDisableIntrinsics(ip: *InternPool, func: Index) void {
const unwrapped_func = func.unwrap(ip);
const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
extra_mutex.lock();
defer extra_mutex.unlock();

const analysis_ptr = ip.funcAnalysisPtr(func);
var analysis = analysis_ptr.*;
analysis.disable_intrinsics = true;
@atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
}

pub fn funcZirBodyInst(ip: *const InternPool, func: Index) TrackedInst.Index {
const unwrapped_func = func.unwrap(ip);
const item = unwrapped_func.getItem(ip);
Expand Down
17 changes: 17 additions & 0 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,11 @@ fn analyzeBodyInner(
i += 1;
continue;
},
.disable_intrinsics => {
try sema.zirDisableIntrinsics();
i += 1;
continue;
},
.restore_err_ret_index => {
try sema.zirRestoreErrRetIndex(block, extended);
i += 1;
Expand Down Expand Up @@ -6551,6 +6556,18 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
sema.allow_memoize = false;
}

fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const func = switch (sema.owner.unwrap()) {
.func => |func| func,
.cau => return, // does nothing outside a function
};
ip.funcSetDisableIntrinsics(func);
sema.allow_memoize = false;
}

fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = block.builtinCallArgSrc(extra.node, 0);
Expand Down
29 changes: 17 additions & 12 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,19 @@ pub const Object = struct {
try attributes.addFnAttr(.nosanitize_coverage, &o.builder);
}

const disable_intrinsics = func_analysis.disable_intrinsics or owner_mod.no_builtin;
if (disable_intrinsics) {
// The intent here is for compiler-rt and libc functions to not generate
// infinite recursion. For example, if we are compiling the memcpy function,
// and llvm detects that the body is equivalent to memcpy, it may replace the
// body of memcpy with a call to memcpy, which would then cause a stack
// overflow instead of performing memcpy.
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("no-builtins"),
.value = .empty,
} }, &o.builder);
}

// TODO: disable this if safety is off for the function scope
const ssp_buf_size = owner_mod.stack_protector;
if (ssp_buf_size != 0) {
Expand Down Expand Up @@ -1757,6 +1770,7 @@ pub const Object = struct {
.prev_dbg_line = 0,
.prev_dbg_column = 0,
.err_ret_trace = err_ret_trace,
.disable_intrinsics = disable_intrinsics,
};
defer fg.deinit();
deinit_wip = false;
Expand Down Expand Up @@ -3144,17 +3158,6 @@ pub const Object = struct {
if (owner_mod.unwind_tables) {
try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
}
if (owner_mod.no_builtin) {
// The intent here is for compiler-rt and libc functions to not generate
// infinite recursion. For example, if we are compiling the memcpy function,
// and llvm detects that the body is equivalent to memcpy, it may replace the
// body of memcpy with a call to memcpy, which would then cause a stack
// overflow instead of performing memcpy.
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("no-builtins"),
.value = .empty,
} }, &o.builder);
}
if (owner_mod.optimize_mode == .ReleaseSmall) {
try attributes.addFnAttr(.minsize, &o.builder);
try attributes.addFnAttr(.optsize, &o.builder);
Expand Down Expand Up @@ -4943,6 +4946,8 @@ pub const FuncGen = struct {

sync_scope: Builder.SyncScope,

disable_intrinsics: bool,

const Fuzz = struct {
counters_variable: Builder.Variable.Index,
pcs: std.ArrayListUnmanaged(Builder.Constant),
Expand Down Expand Up @@ -5481,7 +5486,7 @@ pub const FuncGen = struct {
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);

if (self.ng.ownerModule().no_builtin) {
if (self.disable_intrinsics) {
try attributes.addFnAttr(.nobuiltin, &o.builder);
}

Expand Down
1 change: 1 addition & 0 deletions src/print_zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ const Writer = struct {
.frame_address,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.c_va_start,
.in_comptime,
.value_placeholder,
Expand Down

0 comments on commit c454172

Please sign in to comment.