diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -596,6 +596,10 @@ if (!getCodeGenOpts().RecordCommandLine.empty()) EmitCommandLineMetadata(); + if (LangOpts.Freestanding) { + getModule().addModuleFlag(llvm::Module::Override, "force-inline-libc", 1); + } + EmitTargetMetadata(); } diff --git a/clang/test/CodeGen/freestanding-disables-libc.c b/clang/test/CodeGen/freestanding-disables-libc.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/freestanding-disables-libc.c @@ -0,0 +1,11 @@ +// NOTE: Test that IR module specifies a "force-inline-libc" attribute in freestanding mode. +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | not grep 'force-inline-libc' +// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm %s -o - | not grep 'force-inline-libc' +// RUN: %clang_cc1 -triple i386-unknown-unknown -ffreestanding -O2 -emit-llvm %s -o - | grep 'force-inline-libc' + +// NOTE: Test that assembly doesn't call memcpy function in freestanding mode. +// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -S %s -o - | grep 'memcpy' +// RUN: %clang_cc1 -triple i386-unknown-unknown -ffreestanding -O2 -S %s -o - | not grep 'memcpy' + +struct BigStruct { char payload[4096]; }; +struct BigStruct PassByValue(struct BigStruct value) { return value; } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6090,6 +6090,9 @@ // beyond the given memory regions. But fixing this isn't easy, and most // people don't care. + assert(MF->getFunction().getParent()->getModuleFlag("force-inline-libc") == + nullptr); + // Emit a library call. TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5480,6 +5480,14 @@ } } +static bool IsForceInlineLibc(const SelectionDAG &DAG) { + const Module *M = DAG.getMachineFunction().getFunction().getParent(); + if (auto *MD = mdconst::extract_or_null( + M->getModuleFlag("force-inline-libc"))) + return MD->getZExtValue(); + return false; +} + /// Lower the call to the specified intrinsic function. If we want to emit this /// as a call to a named external function, return the name. Otherwise, lower it /// and return null. @@ -5553,10 +5561,11 @@ unsigned Align = MinAlign(DstAlign, SrcAlign); bool isVol = MCI.isVolatile(); bool isTC = I.isTailCall() && isInTailCallPosition(&I, DAG.getTarget()); + bool IsAlwaysInline = IsForceInlineLibc(DAG); // FIXME: Support passing different dest/src alignments to the memcpy DAG // node. SDValue MC = DAG.getMemcpy(getRoot(), sdl, Op1, Op2, Op3, Align, isVol, - false, isTC, + IsAlwaysInline, isTC, MachinePointerInfo(I.getArgOperand(0)), MachinePointerInfo(I.getArgOperand(1))); updateDAGForMaybeTailCall(MC);