Index: llvm/include/llvm/IR/AutoUpgrade.h =================================================================== --- llvm/include/llvm/IR/AutoUpgrade.h +++ llvm/include/llvm/IR/AutoUpgrade.h @@ -60,6 +60,9 @@ void UpgradeSectionAttributes(Module &M); + /// Correct any IR that is relying on old function attribute behavior. + void UpgradeFunctionAttributes(Function &F); + /// If the given TBAA tag uses the scalar TBAA format, create a new node /// corresponding to the upgrade to the struct-path aware TBAA format. /// Otherwise return the \p TBAANode itself. Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2962,6 +2962,7 @@ return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point + // and function that need to have their function attributes upgraded. for (Function &F : *TheModule) { MDLoader->upgradeDebugIntrinsics(F); Function *NewFn; @@ -2972,6 +2973,8 @@ // loaded in the same LLVMContext (LTO scenario). In this case we should // remangle intrinsics names as well. RemangledIntrinsics[&F] = Remangled.getValue(); + // Look for functions that rely on old function attribute behavior. + UpgradeFunctionAttributes(F); } // Look for global variables which need to be renamed. Index: llvm/lib/IR/AutoUpgrade.cpp =================================================================== --- llvm/lib/IR/AutoUpgrade.cpp +++ llvm/lib/IR/AutoUpgrade.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/InstVisitor.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" @@ -4073,6 +4074,40 @@ } } + +// Prior to LLVM 10.0, the strictfp attribute could be used on individual +// callsites within a function that did not also have the strictfp attribute. +// Since 10.0, if strict FP semantics are needed within a function, the +// function must have the strictfp attribute and all calls within the function +// must also have the strictfp attribute. This latter restriction is +// necessary to prevent unwanted libcall simplification when a function is +// being cloned (such as for inlining). +// +// The "dangling" strictfp attribute usage was only used to prevent constant +// folding and other libcall simplification. The nobuiltin attribute on the +// callsite has the same effect. +struct StrictFPUpgradeVisitor : public InstVisitor { + StrictFPUpgradeVisitor() {} + + void visitCallBase(CallBase &Call) { + if (!Call.isStrictFP()) + return; + // If we get here, the caller doesn't have the strictfp attribute + // but this callsite does. Replace the strictfp attribute with nobuiltin. + Call.removeAttribute(AttributeList::FunctionIndex, Attribute::StrictFP); + Call.addAttribute(AttributeList::FunctionIndex, Attribute::NoBuiltin); + } +}; + +void llvm::UpgradeFunctionAttributes(Function &F) { + // If a function definition doesn't have the strictfp attribute, + // convert any callsite strictfp attributes to nobuiltin. + if (!F.isDeclaration() && !F.hasFnAttribute(Attribute::StrictFP)) { + StrictFPUpgradeVisitor SFPV; + SFPV.visit(F); + } +} + static bool isOldLoopArgument(Metadata *MD) { auto *T = dyn_cast_or_null(MD); if (!T) Index: llvm/test/Bitcode/compatibility-5.0.ll =================================================================== --- llvm/test/Bitcode/compatibility-5.0.ll +++ llvm/test/Bitcode/compatibility-5.0.ll @@ -1250,8 +1250,10 @@ call void @f.nobuiltin() builtin ; CHECK: call void @f.nobuiltin() #43 + ; When used in a non-strictfp function the strictfp callsite attribute + ; should get translated to nobuiltin. call void @f.strictfp() strictfp - ; CHECK: call void @f.strictfp() #44 + ; CHECK: call void @f.strictfp() #9 call fastcc noalias i32* @f.noalias() noinline ; CHECK: call fastcc noalias i32* @f.noalias() #12 @@ -1672,7 +1674,6 @@ ; CHECK: attributes #41 = { speculatable } ; CHECK: attributes #42 = { inaccessiblemem_or_argmemonly nounwind willreturn } ; CHECK: attributes #43 = { builtin } -; CHECK: attributes #44 = { strictfp } ;; Metadata Index: llvm/test/Bitcode/compatibility-6.0.ll =================================================================== --- llvm/test/Bitcode/compatibility-6.0.ll +++ llvm/test/Bitcode/compatibility-6.0.ll @@ -1261,8 +1261,10 @@ call void @f.nobuiltin() builtin ; CHECK: call void @f.nobuiltin() #43 + ; When used in a non-strictfp function the strictfp callsite attribute + ; should get translated to nobuiltin. call void @f.strictfp() strictfp - ; CHECK: call void @f.strictfp() #44 + ; CHECK: call void @f.strictfp() #9 call fastcc noalias i32* @f.noalias() noinline ; CHECK: call fastcc noalias i32* @f.noalias() #12 @@ -1683,7 +1685,6 @@ ; CHECK: attributes #41 = { speculatable } ; CHECK: attributes #42 = { inaccessiblemem_or_argmemonly nounwind willreturn } ; CHECK: attributes #43 = { builtin } -; CHECK: attributes #44 = { strictfp } ;; Metadata