https://github.com/chadaustin created https://github.com/llvm/llvm-project/pull/222828
For parity with gcc, allow an explicit -fbuiltin in freestanding compilations while preserving -fno-builtin as the default. This allows memcpy to be inlined, especially important when targeting platforms with support for unaligned loads and stores. Preserve the override when generating cc1 arguments. Fixes #20418 >From be4cad383de92186cf68da2b24b2690ef435d4a0 Mon Sep 17 00:00:00 2001 From: Chad Austin <[email protected]> Date: Thu, 10 Sep 2026 17:48:54 -0700 Subject: [PATCH] [clang] Allow -fbuiltin to override -ffreestanding Honor an explicit -fbuiltin in freestanding compilations while preserving -fno-builtin as the default. Preserve the override when generating cc1 arguments. Fixes #20418 --- clang/docs/ReleaseNotes.md | 4 ++ clang/docs/UsersManual.md | 3 +- clang/include/clang/Options/Options.td | 3 +- clang/lib/Driver/ToolChains/Clang.cpp | 49 ++++++++++++++++--- clang/lib/Frontend/CompilerInvocation.cpp | 23 +++++++-- .../CodeGen/PR3589-freestanding-libcalls.c | 6 +++ 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 12b0da9b299a6..90016ec2577d7 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -261,6 +261,10 @@ features cannot lower the translation-unit ABI level; - All options of the `-fzero-call-used-regs` compiler flag are now allowed on RISC-V. +- `-fbuiltin` can now explicitly enable builtin function optimizations in + freestanding compilations. `-ffreestanding` continues to disable builtin + functions by default. (#GH20418) + ### Removed Compiler Flags ### Attribute Changes in Clang diff --git a/clang/docs/UsersManual.md b/clang/docs/UsersManual.md index 03f6a07d1a02c..2f8cd60b196d1 100644 --- a/clang/docs/UsersManual.md +++ b/clang/docs/UsersManual.md @@ -1199,7 +1199,8 @@ Passing the `-ffreestanding` flag causes Clang to build for a freestanding (rather than a hosted) environment. The flag has the following effects: - the `__STDC_HOSTED__` predefined macro will expand to `0`, -- builtin functions are disabled by default (`-fno-builtins`), +- builtin functions are disabled by default (`-fno-builtin`), but can be + explicitly enabled with `-fbuiltin`, - unwind tables are disabled by default (`fno-asynchronous-unwind-tables -fno-unwind-tables`), and - does not treat the global `main` function as a special function. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index f7e22ee84a9f4..79e29be24faf3 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2177,7 +2177,8 @@ defm borland_extensions : BoolFOption<"borland-extensions", "Accept non-standard constructs supported by the Borland compiler">, NegFlag<SetFalse>>; def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption, FC1Option]>; + Visibility<[ClangOption, CC1Option, CLOption, DXCOption, FlangOption, + FC1Option]>; def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>, Flags<[]>, HelpText<"Load the clang builtins module map file.">; defm caret_diagnostics : BoolFOption<"caret-diagnostics", diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ab852bf0e0043..29dabeba26979 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -61,6 +61,7 @@ #include "llvm/TargetParser/RISCVTargetParser.h" #include <cctype> #include <iterator> +#include <optional> using namespace clang::driver; using namespace clang::driver::tools; @@ -4021,16 +4022,48 @@ static void RenderOpenACCOptions(const Driver &D, const ArgList &Args, static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, const ArgList &Args, ArgStringList &CmdArgs) { - // -fbuiltin is default unless -mkernel is used. - bool UseBuiltins = - Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, - !Args.hasArg(options::OPT_mkernel)); + bool KernelOrKext = false; + bool Freestanding = false; + bool UseBuiltins = true; + std::optional<bool> ExplicitUseBuiltins; + for (const Arg *A : Args) { + switch (A->getOption().getID()) { + case options::OPT_fbuiltin: + A->claim(); + ExplicitUseBuiltins = true; + UseBuiltins = true; + break; + case options::OPT_fno_builtin: + A->claim(); + ExplicitUseBuiltins = false; + UseBuiltins = false; + break; + case options::OPT_ffreestanding: + A->claim(); + Freestanding = true; + UseBuiltins = false; + break; + case options::OPT_fhosted: + A->claim(); + Freestanding = KernelOrKext; + UseBuiltins = ExplicitUseBuiltins.value_or(!Freestanding); + break; + case options::OPT_mkernel: + case options::OPT_fapple_kext: + A->claim(); + KernelOrKext = true; + Freestanding = true; + UseBuiltins = false; + break; + default: + break; + } + } + if (!UseBuiltins) CmdArgs.push_back("-fno-builtin"); - - // -ffreestanding implies -fno-builtin. - if (Args.hasArg(options::OPT_ffreestanding)) - UseBuiltins = false; + else if (Freestanding) + CmdArgs.push_back("-fbuiltin"); // Process the -fno-builtin-* options. for (const Arg *A : Args.filtered(options::OPT_fno_builtin_)) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 037647f76bd1d..ad396d8b9000b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1615,8 +1615,8 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, else if (Opts.OptimizeSize == 2) GenerateArg(Consumer, OPT_O, "z"); - // SimplifyLibCalls is set only in the absence of -fno-builtin and - // -ffreestanding. We'll consider that when generating them. + // SimplifyLibCalls is derived from LangOptions::NoBuiltin. We'll consider + // that when generating -f[no-]builtin. // NoBuiltinFuncs are generated by LangOptions. @@ -3875,6 +3875,8 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts, if (Opts.NoBuiltin && !Opts.Freestanding) GenerateArg(Consumer, OPT_fno_builtin); + else if (!Opts.NoBuiltin && Opts.Freestanding) + GenerateArg(Consumer, OPT_fbuiltin); if (!Opts.NoBuiltin) for (const auto &Func : Opts.NoBuiltinFuncs) @@ -4294,7 +4296,22 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Args.hasFlag(OPT_fconvergent_functions, OPT_fno_convergent_functions, HasConvergentOperations); - Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.NoBuiltin = false; + for (const Arg *A : Args) { + switch (A->getOption().getID()) { + case OPT_fbuiltin: + A->claim(); + Opts.NoBuiltin = false; + break; + case OPT_fno_builtin: + case OPT_ffreestanding: + A->claim(); + Opts.NoBuiltin = true; + break; + default: + break; + } + } if (!Opts.NoBuiltin) getAllNoBuiltinFuncValues(Args, Opts.NoBuiltinFuncs); if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) { diff --git a/clang/test/CodeGen/PR3589-freestanding-libcalls.c b/clang/test/CodeGen/PR3589-freestanding-libcalls.c index d691d8f25e114..ca336d7f6bf57 100644 --- a/clang/test/CodeGen/PR3589-freestanding-libcalls.c +++ b/clang/test/CodeGen/PR3589-freestanding-libcalls.c @@ -1,6 +1,12 @@ // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | grep 'declare i32 @printf' | count 1 // RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm %s -o - | grep 'declare noundef i32 @puts' | count 1 // RUN: %clang_cc1 -triple i386-unknown-unknown -ffreestanding -O2 -emit-llvm %s -o - | not grep 'declare noundef i32 @puts' +// RUN: %clang_cc1 -round-trip-args -triple i386-unknown-unknown -ffreestanding -fbuiltin -O2 -emit-llvm %s -o - | grep 'declare noundef i32 @puts' | count 1 +// RUN: %clang_cc1 -round-trip-args -triple i386-unknown-unknown -fbuiltin -ffreestanding -O2 -emit-llvm %s -o - | not grep 'declare noundef i32 @puts' +// RUN: %clang -target i386-unknown-unknown -ffreestanding -fbuiltin -O2 -emit-llvm -S %s -o - | grep 'declare noundef i32 @puts' | count 1 +// RUN: %clang -target i386-unknown-unknown -fbuiltin -ffreestanding -O2 -emit-llvm -S %s -o - | not grep 'declare noundef i32 @puts' +// RUN: %clang -target i386-unknown-unknown -ffreestanding -fbuiltin -ffreestanding -O2 -emit-llvm -S %s -o - | not grep 'declare noundef i32 @puts' +// RUN: %clang -target i386-unknown-unknown -ffreestanding -fbuiltin -fno-builtin -O2 -emit-llvm -S %s -o - | not grep 'declare noundef i32 @puts' int printf(const char *, ...); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
