| author | |
| committer | |
| log | ecc76348e6858f00b920d8dc9e44a6e703d8e497 |
| tree | 018e151e85958c8e1b12328865e8b18398956b5e |
| parent | 76558f8c6b8361ab520ea77e4b4cd2bfc8f688ad |
| parent | e11ac026623f8d0f4895cddd6a9bf3c03a866c6d |
| signature |
compiler: Implement `@disableIntrinsics()` builtin function.10 files changed, 107 insertions(+), 28 deletions(-)
lib/std/zig/AstGen.zig+2| ... | ... | @@ -2956,6 +2956,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2956 | 2956 | .extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) { |
| 2957 | 2957 | .breakpoint, |
| 2958 | 2958 | .disable_instrumentation, |
| 2959 | .disable_intrinsics, | |
| 2959 | 2960 | .set_float_mode, |
| 2960 | 2961 | .branch_hint, |
| 2961 | 2962 | => break :b true, |
| ... | ... | @@ -9578,6 +9579,7 @@ fn builtinCall( |
| 9578 | 9579 | .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node), |
| 9579 | 9580 | .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), |
| 9580 | 9581 | .disable_instrumentation => return rvalue(gz, ri, try gz.addNodeExtended(.disable_instrumentation, node), node), |
| 9582 | .disable_intrinsics => return rvalue(gz, ri, try gz.addNodeExtended(.disable_intrinsics, node), node), | |
| 9581 | 9583 | |
| 9582 | 9584 | .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info), |
| 9583 | 9585 | .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of), |
lib/std/zig/AstRlAnnotate.zig+1| ... | ... | @@ -882,6 +882,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. |
| 882 | 882 | .frame, |
| 883 | 883 | .breakpoint, |
| 884 | 884 | .disable_instrumentation, |
| 885 | .disable_intrinsics, | |
| 885 | 886 | .in_comptime, |
| 886 | 887 | .panic, |
| 887 | 888 | .trap, |
lib/std/zig/BuiltinFn.zig+9| ... | ... | @@ -15,6 +15,7 @@ pub const Tag = enum { |
| 15 | 15 | branch_hint, |
| 16 | 16 | breakpoint, |
| 17 | 17 | disable_instrumentation, |
| 18 | disable_intrinsics, | |
| 18 | 19 | mul_add, |
| 19 | 20 | byte_swap, |
| 20 | 21 | bit_reverse, |
| ... | ... | @@ -262,6 +263,14 @@ pub const list = list: { |
| 262 | 263 | .illegal_outside_function = true, |
| 263 | 264 | }, |
| 264 | 265 | }, |
| 266 | .{ | |
| 267 | "@disableIntrinsics", | |
| 268 | .{ | |
| 269 | .tag = .disable_intrinsics, | |
| 270 | .param_count = 0, | |
| 271 | .illegal_outside_function = true, | |
| 272 | }, | |
| 273 | }, | |
| 265 | 274 | .{ |
| 266 | 275 | "@mulAdd", |
| 267 | 276 | .{ |
lib/std/zig/Zir.zig+8-1| ... | ... | @@ -1587,7 +1587,11 @@ pub const Inst = struct { |
| 1587 | 1587 | => false, |
| 1588 | 1588 | |
| 1589 | 1589 | .extended => switch (data.extended.opcode) { |
| 1590 | .branch_hint, .breakpoint, .disable_instrumentation => true, | |
| 1590 | .branch_hint, | |
| 1591 | .breakpoint, | |
| 1592 | .disable_instrumentation, | |
| 1593 | .disable_intrinsics, | |
| 1594 | => true, | |
| 1591 | 1595 | else => false, |
| 1592 | 1596 | }, |
| 1593 | 1597 | }; |
| ... | ... | @@ -2004,6 +2008,8 @@ pub const Inst = struct { |
| 2004 | 2008 | breakpoint, |
| 2005 | 2009 | /// Implement builtin `@disableInstrumentation`. `operand` is `src_node: i32`. |
| 2006 | 2010 | disable_instrumentation, |
| 2011 | /// Implement builtin `@disableIntrinsics`. `operand` is `src_node: i32`. | |
| 2012 | disable_intrinsics, | |
| 2007 | 2013 | /// Implements the `@select` builtin. |
| 2008 | 2014 | /// `operand` is payload index to `Select`. |
| 2009 | 2015 | select, |
| ... | ... | @@ -4332,6 +4338,7 @@ fn findTrackableInner( |
| 4332 | 4338 | .await_nosuspend, |
| 4333 | 4339 | .breakpoint, |
| 4334 | 4340 | .disable_instrumentation, |
| 4341 | .disable_intrinsics, | |
| 4335 | 4342 | .select, |
| 4336 | 4343 | .int_from_error, |
| 4337 | 4344 | .error_from_int, |
lib/zig.h+6| ... | ... | @@ -223,6 +223,12 @@ |
| 223 | 223 | #define zig_restrict |
| 224 | 224 | #endif |
| 225 | 225 | |
| 226 | #if zig_has_attribute(no_builtin) | |
| 227 | #define zig_no_builtin __attribute__((no_builtin)) | |
| 228 | #else | |
| 229 | #define zig_no_builtin | |
| 230 | #endif | |
| 231 | ||
| 226 | 232 | #if zig_has_attribute(aligned) || defined(zig_tinyc) |
| 227 | 233 | #define zig_under_align(alignment) __attribute__((aligned(alignment))) |
| 228 | 234 | #elif defined(zig_msvc) |
src/InternPool.zig+18-1| ... | ... | @@ -6045,8 +6045,9 @@ pub const FuncAnalysis = packed struct(u32) { |
| 6045 | 6045 | /// True if this function has an inferred error set. |
| 6046 | 6046 | inferred_error_set: bool, |
| 6047 | 6047 | disable_instrumentation: bool, |
| 6048 | disable_intrinsics: bool, | |
| 6048 | 6049 | |
| 6049 | _: u24 = 0, | |
| 6050 | _: u23 = 0, | |
| 6050 | 6051 | }; |
| 6051 | 6052 | |
| 6052 | 6053 | pub const Bytes = struct { |
| ... | ... | @@ -9077,6 +9078,7 @@ pub fn getFuncDecl( |
| 9077 | 9078 | .has_error_trace = false, |
| 9078 | 9079 | .inferred_error_set = false, |
| 9079 | 9080 | .disable_instrumentation = false, |
| 9081 | .disable_intrinsics = false, | |
| 9080 | 9082 | }, |
| 9081 | 9083 | .owner_nav = key.owner_nav, |
| 9082 | 9084 | .ty = key.ty, |
| ... | ... | @@ -9186,6 +9188,7 @@ pub fn getFuncDeclIes( |
| 9186 | 9188 | .has_error_trace = false, |
| 9187 | 9189 | .inferred_error_set = true, |
| 9188 | 9190 | .disable_instrumentation = false, |
| 9191 | .disable_intrinsics = false, | |
| 9189 | 9192 | }, |
| 9190 | 9193 | .owner_nav = key.owner_nav, |
| 9191 | 9194 | .ty = func_ty, |
| ... | ... | @@ -9382,6 +9385,7 @@ pub fn getFuncInstance( |
| 9382 | 9385 | .has_error_trace = false, |
| 9383 | 9386 | .inferred_error_set = false, |
| 9384 | 9387 | .disable_instrumentation = false, |
| 9388 | .disable_intrinsics = false, | |
| 9385 | 9389 | }, |
| 9386 | 9390 | // This is populated after we create the Nav below. It is not read |
| 9387 | 9391 | // by equality or hashing functions. |
| ... | ... | @@ -9480,6 +9484,7 @@ pub fn getFuncInstanceIes( |
| 9480 | 9484 | .has_error_trace = false, |
| 9481 | 9485 | .inferred_error_set = true, |
| 9482 | 9486 | .disable_instrumentation = false, |
| 9487 | .disable_intrinsics = false, | |
| 9483 | 9488 | }, |
| 9484 | 9489 | // This is populated after we create the Nav below. It is not read |
| 9485 | 9490 | // by equality or hashing functions. |
| ... | ... | @@ -12313,6 +12318,18 @@ pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void { |
| 12313 | 12318 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); |
| 12314 | 12319 | } |
| 12315 | 12320 | |
| 12321 | pub fn funcSetDisableIntrinsics(ip: *InternPool, func: Index) void { | |
| 12322 | const unwrapped_func = func.unwrap(ip); | |
| 12323 | const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex; | |
| 12324 | extra_mutex.lock(); | |
| 12325 | defer extra_mutex.unlock(); | |
| 12326 | ||
| 12327 | const analysis_ptr = ip.funcAnalysisPtr(func); | |
| 12328 | var analysis = analysis_ptr.*; | |
| 12329 | analysis.disable_intrinsics = true; | |
| 12330 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); | |
| 12331 | } | |
| 12332 | ||
| 12316 | 12333 | pub fn funcZirBodyInst(ip: *const InternPool, func: Index) TrackedInst.Index { |
| 12317 | 12334 | const unwrapped_func = func.unwrap(ip); |
| 12318 | 12335 | const item = unwrapped_func.getItem(ip); |
src/Sema.zig+22| ... | ... | @@ -1409,6 +1409,11 @@ fn analyzeBodyInner( |
| 1409 | 1409 | i += 1; |
| 1410 | 1410 | continue; |
| 1411 | 1411 | }, |
| 1412 | .disable_intrinsics => { | |
| 1413 | try sema.zirDisableIntrinsics(); | |
| 1414 | i += 1; | |
| 1415 | continue; | |
| 1416 | }, | |
| 1412 | 1417 | .restore_err_ret_index => { |
| 1413 | 1418 | try sema.zirRestoreErrRetIndex(block, extended); |
| 1414 | 1419 | i += 1; |
| ... | ... | @@ -6642,6 +6647,23 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 6642 | 6647 | sema.allow_memoize = false; |
| 6643 | 6648 | } |
| 6644 | 6649 | |
| 6650 | fn zirDisableIntrinsics(sema: *Sema) CompileError!void { | |
| 6651 | const pt = sema.pt; | |
| 6652 | const zcu = pt.zcu; | |
| 6653 | const ip = &zcu.intern_pool; | |
| 6654 | const func = switch (sema.owner.unwrap()) { | |
| 6655 | .func => |func| func, | |
| 6656 | .@"comptime", | |
| 6657 | .nav_val, | |
| 6658 | .nav_ty, | |
| 6659 | .type, | |
| 6660 | .memoized_state, | |
| 6661 | => return, // does nothing outside a function | |
| 6662 | }; | |
| 6663 | ip.funcSetDisableIntrinsics(func); | |
| 6664 | sema.allow_memoize = false; | |
| 6665 | } | |
| 6666 | ||
| 6645 | 6667 | fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 6646 | 6668 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 6647 | 6669 | const src = block.builtinCallArgSrc(extra.node, 0); |
src/codegen/c.zig+11-2| ... | ... | @@ -1859,8 +1859,17 @@ pub const DeclGen = struct { |
| 1859 | 1859 | else => unreachable, |
| 1860 | 1860 | } |
| 1861 | 1861 | } |
| 1862 | if (fn_val.getFunction(zcu)) |func| if (func.analysisUnordered(ip).branch_hint == .cold) | |
| 1863 | try w.writeAll("zig_cold "); | |
| 1862 | ||
| 1863 | if (fn_val.getFunction(zcu)) |func| { | |
| 1864 | const func_analysis = func.analysisUnordered(ip); | |
| 1865 | ||
| 1866 | if (func_analysis.branch_hint == .cold) | |
| 1867 | try w.writeAll("zig_cold "); | |
| 1868 | ||
| 1869 | if (kind == .complete and func_analysis.disable_intrinsics or dg.mod.no_builtin) | |
| 1870 | try w.writeAll("zig_no_builtin "); | |
| 1871 | } | |
| 1872 | ||
| 1864 | 1873 | if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); |
| 1865 | 1874 | |
| 1866 | 1875 | var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{}); |
src/codegen/llvm.zig+29-24| ... | ... | @@ -1447,6 +1447,19 @@ pub const Object = struct { |
| 1447 | 1447 | try attributes.addFnAttr(.nosanitize_coverage, &o.builder); |
| 1448 | 1448 | } |
| 1449 | 1449 | |
| 1450 | const disable_intrinsics = func_analysis.disable_intrinsics or owner_mod.no_builtin; | |
| 1451 | if (disable_intrinsics) { | |
| 1452 | // The intent here is for compiler-rt and libc functions to not generate | |
| 1453 | // infinite recursion. For example, if we are compiling the memcpy function, | |
| 1454 | // and llvm detects that the body is equivalent to memcpy, it may replace the | |
| 1455 | // body of memcpy with a call to memcpy, which would then cause a stack | |
| 1456 | // overflow instead of performing memcpy. | |
| 1457 | try attributes.addFnAttr(.{ .string = .{ | |
| 1458 | .kind = try o.builder.string("no-builtins"), | |
| 1459 | .value = .empty, | |
| 1460 | } }, &o.builder); | |
| 1461 | } | |
| 1462 | ||
| 1450 | 1463 | // TODO: disable this if safety is off for the function scope |
| 1451 | 1464 | const ssp_buf_size = owner_mod.stack_protector; |
| 1452 | 1465 | if (ssp_buf_size != 0) { |
| ... | ... | @@ -1750,6 +1763,7 @@ pub const Object = struct { |
| 1750 | 1763 | .prev_dbg_line = 0, |
| 1751 | 1764 | .prev_dbg_column = 0, |
| 1752 | 1765 | .err_ret_trace = err_ret_trace, |
| 1766 | .disable_intrinsics = disable_intrinsics, | |
| 1753 | 1767 | }; |
| 1754 | 1768 | defer fg.deinit(); |
| 1755 | 1769 | deinit_wip = false; |
| ... | ... | @@ -3129,17 +3143,6 @@ pub const Object = struct { |
| 3129 | 3143 | &o.builder, |
| 3130 | 3144 | ); |
| 3131 | 3145 | } |
| 3132 | if (owner_mod.no_builtin) { | |
| 3133 | // The intent here is for compiler-rt and libc functions to not generate | |
| 3134 | // infinite recursion. For example, if we are compiling the memcpy function, | |
| 3135 | // and llvm detects that the body is equivalent to memcpy, it may replace the | |
| 3136 | // body of memcpy with a call to memcpy, which would then cause a stack | |
| 3137 | // overflow instead of performing memcpy. | |
| 3138 | try attributes.addFnAttr(.{ .string = .{ | |
| 3139 | .kind = try o.builder.string("no-builtins"), | |
| 3140 | .value = .empty, | |
| 3141 | } }, &o.builder); | |
| 3142 | } | |
| 3143 | 3146 | if (owner_mod.optimize_mode == .ReleaseSmall) { |
| 3144 | 3147 | try attributes.addFnAttr(.minsize, &o.builder); |
| 3145 | 3148 | try attributes.addFnAttr(.optsize, &o.builder); |
| ... | ... | @@ -4918,6 +4921,8 @@ pub const FuncGen = struct { |
| 4918 | 4921 | |
| 4919 | 4922 | sync_scope: Builder.SyncScope, |
| 4920 | 4923 | |
| 4924 | disable_intrinsics: bool, | |
| 4925 | ||
| 4921 | 4926 | const Fuzz = struct { |
| 4922 | 4927 | counters_variable: Builder.Variable.Index, |
| 4923 | 4928 | pcs: std.ArrayListUnmanaged(Builder.Constant), |
| ... | ... | @@ -5443,7 +5448,7 @@ pub const FuncGen = struct { |
| 5443 | 5448 | var attributes: Builder.FunctionAttributes.Wip = .{}; |
| 5444 | 5449 | defer attributes.deinit(&o.builder); |
| 5445 | 5450 | |
| 5446 | if (self.ng.ownerModule().no_builtin) { | |
| 5451 | if (self.disable_intrinsics) { | |
| 5447 | 5452 | try attributes.addFnAttr(.nobuiltin, &o.builder); |
| 5448 | 5453 | } |
| 5449 | 5454 | |
| ... | ... | @@ -5770,7 +5775,7 @@ pub const FuncGen = struct { |
| 5770 | 5775 | try o.builder.intValue(.i8, 0xaa), |
| 5771 | 5776 | len, |
| 5772 | 5777 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, |
| 5773 | self.ng.ownerModule().no_builtin, | |
| 5778 | self.disable_intrinsics, | |
| 5774 | 5779 | ); |
| 5775 | 5780 | const owner_mod = self.ng.ownerModule(); |
| 5776 | 5781 | if (owner_mod.valgrind) { |
| ... | ... | @@ -5821,7 +5826,7 @@ pub const FuncGen = struct { |
| 5821 | 5826 | try o.builder.intValue(.i8, 0xaa), |
| 5822 | 5827 | len, |
| 5823 | 5828 | .normal, |
| 5824 | self.ng.ownerModule().no_builtin, | |
| 5829 | self.disable_intrinsics, | |
| 5825 | 5830 | ); |
| 5826 | 5831 | const owner_mod = self.ng.ownerModule(); |
| 5827 | 5832 | if (owner_mod.valgrind) { |
| ... | ... | @@ -9735,7 +9740,7 @@ pub const FuncGen = struct { |
| 9735 | 9740 | if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), |
| 9736 | 9741 | len, |
| 9737 | 9742 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, |
| 9738 | self.ng.ownerModule().no_builtin, | |
| 9743 | self.disable_intrinsics, | |
| 9739 | 9744 | ); |
| 9740 | 9745 | if (safety and owner_mod.valgrind) { |
| 9741 | 9746 | try self.valgrindMarkUndef(dest_ptr, len); |
| ... | ... | @@ -10057,7 +10062,7 @@ pub const FuncGen = struct { |
| 10057 | 10062 | fill_byte, |
| 10058 | 10063 | len, |
| 10059 | 10064 | access_kind, |
| 10060 | self.ng.ownerModule().no_builtin, | |
| 10065 | self.disable_intrinsics, | |
| 10061 | 10066 | ); |
| 10062 | 10067 | } |
| 10063 | 10068 | const owner_mod = self.ng.ownerModule(); |
| ... | ... | @@ -10089,7 +10094,7 @@ pub const FuncGen = struct { |
| 10089 | 10094 | fill_byte, |
| 10090 | 10095 | len, |
| 10091 | 10096 | access_kind, |
| 10092 | self.ng.ownerModule().no_builtin, | |
| 10097 | self.disable_intrinsics, | |
| 10093 | 10098 | ); |
| 10094 | 10099 | } |
| 10095 | 10100 | return .none; |
| ... | ... | @@ -10119,7 +10124,7 @@ pub const FuncGen = struct { |
| 10119 | 10124 | fill_byte, |
| 10120 | 10125 | len, |
| 10121 | 10126 | access_kind, |
| 10122 | self.ng.ownerModule().no_builtin, | |
| 10127 | self.disable_intrinsics, | |
| 10123 | 10128 | ); |
| 10124 | 10129 | } |
| 10125 | 10130 | return .none; |
| ... | ... | @@ -10172,7 +10177,7 @@ pub const FuncGen = struct { |
| 10172 | 10177 | elem_abi_align.toLlvm(), |
| 10173 | 10178 | try o.builder.intValue(llvm_usize_ty, elem_abi_size), |
| 10174 | 10179 | access_kind, |
| 10175 | self.ng.ownerModule().no_builtin, | |
| 10180 | self.disable_intrinsics, | |
| 10176 | 10181 | ); |
| 10177 | 10182 | } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align); |
| 10178 | 10183 | const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{ |
| ... | ... | @@ -10206,7 +10211,7 @@ pub const FuncGen = struct { |
| 10206 | 10211 | fill_byte, |
| 10207 | 10212 | len, |
| 10208 | 10213 | access_kind, |
| 10209 | self.ng.ownerModule().no_builtin, | |
| 10214 | self.disable_intrinsics, | |
| 10210 | 10215 | ); |
| 10211 | 10216 | _ = try self.wip.br(end_block); |
| 10212 | 10217 | self.wip.cursor = .{ .block = end_block }; |
| ... | ... | @@ -10249,7 +10254,7 @@ pub const FuncGen = struct { |
| 10249 | 10254 | src_ptr_ty.ptrAlignment(zcu).toLlvm(), |
| 10250 | 10255 | len, |
| 10251 | 10256 | access_kind, |
| 10252 | self.ng.ownerModule().no_builtin, | |
| 10257 | self.disable_intrinsics, | |
| 10253 | 10258 | ); |
| 10254 | 10259 | _ = try self.wip.br(end_block); |
| 10255 | 10260 | self.wip.cursor = .{ .block = end_block }; |
| ... | ... | @@ -10263,7 +10268,7 @@ pub const FuncGen = struct { |
| 10263 | 10268 | src_ptr_ty.ptrAlignment(zcu).toLlvm(), |
| 10264 | 10269 | len, |
| 10265 | 10270 | access_kind, |
| 10266 | self.ng.ownerModule().no_builtin, | |
| 10271 | self.disable_intrinsics, | |
| 10267 | 10272 | ); |
| 10268 | 10273 | return .none; |
| 10269 | 10274 | } |
| ... | ... | @@ -11397,7 +11402,7 @@ pub const FuncGen = struct { |
| 11397 | 11402 | ptr_alignment, |
| 11398 | 11403 | try o.builder.intValue(try o.lowerType(Type.usize), size_bytes), |
| 11399 | 11404 | access_kind, |
| 11400 | fg.ng.ownerModule().no_builtin, | |
| 11405 | fg.disable_intrinsics, | |
| 11401 | 11406 | ); |
| 11402 | 11407 | return result_ptr; |
| 11403 | 11408 | } |
| ... | ... | @@ -11565,7 +11570,7 @@ pub const FuncGen = struct { |
| 11565 | 11570 | elem_ty.abiAlignment(zcu).toLlvm(), |
| 11566 | 11571 | try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(zcu)), |
| 11567 | 11572 | access_kind, |
| 11568 | self.ng.ownerModule().no_builtin, | |
| 11573 | self.disable_intrinsics, | |
| 11569 | 11574 | ); |
| 11570 | 11575 | } |
| 11571 | 11576 |
src/print_zir.zig+1| ... | ... | @@ -531,6 +531,7 @@ const Writer = struct { |
| 531 | 531 | .frame_address, |
| 532 | 532 | .breakpoint, |
| 533 | 533 | .disable_instrumentation, |
| 534 | .disable_intrinsics, | |
| 534 | 535 | .c_va_start, |
| 535 | 536 | .in_comptime, |
| 536 | 537 | .value_placeholder, |