diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1655,11 +1655,11 @@ for maximum fuzzing signal. ``optnone`` This function attribute indicates that most optimization passes will skip - this function, with the exception of interprocedural optimization passes. - Code generation defaults to the "fast" instruction selector. - This attribute cannot be used together with the ``alwaysinline`` - attribute; this attribute is also incompatible - with the ``minsize`` attribute and the ``optsize`` attribute. + this function. Interprocedural optimizations should treat this function as + though it were defined in an isolated module/object. Code generation + defaults to the "fast" instruction selector. This attribute cannot be used + together with the ``alwaysinline`` attribute; this attribute is also + incompatible with the ``minsize`` attribute and the ``optsize`` attribute. This attribute requires the ``noinline`` attribute to be specified on the function as well, so the function is never inlined into any caller. diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -1207,7 +1207,8 @@ // Otherwise, if we have a single return value case, and if the function is // a declaration, maybe we can constant fold it. - if (F && F->isDeclaration() && canConstantFoldCallTo(&CB, F)) { + if (F && (F->isDeclaration() || F->hasOptNone()) && + canConstantFoldCallTo(&CB, F)) { SmallVector Operands; for (auto AI = CB.arg_begin(), E = CB.arg_end(); AI != E; ++AI) { if (AI->get()->getType()->isStructTy()) @@ -1380,7 +1381,7 @@ // The common case is that we aren't tracking the callee, either because we // are not doing interprocedural analysis or the callee is indirect, or is // external. Handle these cases first. - if (!F || F->isDeclaration()) + if (!F || F->isDeclaration() || F->hasOptNone()) return handleCallOverdefined(CB); // If this is a single/zero retval case, see if we're tracking the function. @@ -1940,6 +1941,10 @@ for (Function &F : M) { if (F.isDeclaration()) continue; + if (F.hasOptNone()) { + Solver.MarkBlockExecutable(&F.front()); + continue; + } Solver.addAnalysis(F, getAnalysis(F)); @@ -1992,7 +1997,7 @@ // constants if we have found them to be of constant values. for (Function &F : M) { - if (F.isDeclaration()) + if (F.isDeclaration() || F.hasOptNone()) continue; SmallVector BlocksToErase; diff --git a/llvm/test/Transforms/SCCP/optnone.ll b/llvm/test/Transforms/SCCP/optnone.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SCCP/optnone.ll @@ -0,0 +1,15 @@ +; RUN: opt < %s -ipsccp -instcombine -S | FileCheck %s + +attributes #0 = { noinline optnone } + +define i32 @callee() #0 { + ret i32 52 +} + +define i32 @caller() { + ; CHECK: define i32 @caller() + ; CHECK: ret i32 %X + %X = call i32 @callee() + ret i32 %X +} +