Skip to content

Commit 53907ed

Browse files
authored
[clang][codegen] Don't mark "int" TBAA on FP libcalls with indirect args (#108853)
On some targets, an FP libcall with argument types such as long double will be lowered to pass arguments indirectly via pointers. When this is the case we should not mark the libcall with "int" TBAA as it may lead to incorrect optimizations. Currently, this can be seen for long doubles on x86_64-w64-mingw32. The `load x86_fp80` after the call is (incorrectly) marked with "int" TBAA (overwriting the previous metadata for "long double"). Nothing seems to break due to this currently as the metadata is being incorrectly placed on the load and not the call. But if the metadata is moved to the call (which this patch ensures), LLVM will optimize out the setup for the arguments.
1 parent d853ade commit 53907ed

File tree

4 files changed

+280
-6
lines changed

4 files changed

+280
-6
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -687,12 +687,31 @@ static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) {
687687
return CGF.Builder.CreateICmpSLT(V, Zero);
688688
}
689689

690+
/// Checks no arguments or results are passed indirectly in the ABI (i.e. via a
691+
/// hidden pointer). This is used to check annotating FP libcalls (that could
692+
/// set `errno`) with "int" TBAA metadata is safe. If any floating-point
693+
/// arguments are passed indirectly, setup for the call could be incorrectly
694+
/// optimized out.
695+
static bool HasNoIndirectArgumentsOrResults(CGFunctionInfo const &FnInfo) {
696+
auto IsIndirect = [&](ABIArgInfo const &info) {
697+
return info.isIndirect() || info.isIndirectAliased() || info.isInAlloca();
698+
};
699+
return !IsIndirect(FnInfo.getReturnInfo()) &&
700+
llvm::none_of(FnInfo.arguments(),
701+
[&](CGFunctionInfoArgInfo const &ArgInfo) {
702+
return IsIndirect(ArgInfo.info);
703+
});
704+
}
705+
690706
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
691707
const CallExpr *E, llvm::Constant *calleeValue) {
692708
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
693709
CGCallee callee = CGCallee::forDirect(calleeValue, GlobalDecl(FD));
710+
llvm::CallBase *callOrInvoke = nullptr;
711+
CGFunctionInfo const *FnInfo = nullptr;
694712
RValue Call =
695-
CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot());
713+
CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot(),
714+
/*Chain=*/nullptr, &callOrInvoke, &FnInfo);
696715

697716
if (unsigned BuiltinID = FD->getBuiltinID()) {
698717
// Check whether a FP math builtin function, such as BI__builtin_expf
@@ -702,12 +721,12 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
702721
// Restrict to target with errno, for example, MacOS doesn't set errno.
703722
// TODO: Support builtin function with complex type returned, eg: cacosh
704723
if (ConstWithoutErrnoAndExceptions && CGF.CGM.getLangOpts().MathErrno &&
705-
!CGF.Builder.getIsFPConstrained() && Call.isScalar()) {
724+
!CGF.Builder.getIsFPConstrained() && Call.isScalar() &&
725+
HasNoIndirectArgumentsOrResults(*FnInfo)) {
706726
// Emit "int" TBAA metadata on FP math libcalls.
707727
clang::QualType IntTy = Context.IntTy;
708728
TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy);
709-
Instruction *Inst = cast<llvm::Instruction>(Call.getScalarVal());
710-
CGF.CGM.DecorateInstructionWithTBAA(Inst, TBAAInfo);
729+
CGF.CGM.DecorateInstructionWithTBAA(callOrInvoke, TBAAInfo);
711730
}
712731
}
713732
return Call;

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5932,7 +5932,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
59325932
const CGCallee &OrigCallee, const CallExpr *E,
59335933
ReturnValueSlot ReturnValue,
59345934
llvm::Value *Chain,
5935-
llvm::CallBase **CallOrInvoke) {
5935+
llvm::CallBase **CallOrInvoke,
5936+
CGFunctionInfo const **ResolvedFnInfo) {
59365937
// Get the actual function type. The callee type will always be a pointer to
59375938
// function type or a block pointer type.
59385939
assert(CalleeType->isFunctionPointerType() &&
@@ -6111,6 +6112,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
61116112
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
61126113
Args, FnType, /*ChainCall=*/Chain);
61136114

6115+
if (ResolvedFnInfo)
6116+
*ResolvedFnInfo = &FnInfo;
6117+
61146118
// C99 6.5.2.2p6:
61156119
// If the expression that denotes the called function has a type
61166120
// that does not include a prototype, [the default argument

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4397,7 +4397,8 @@ class CodeGenFunction : public CodeGenTypeCache {
43974397
}
43984398
RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E,
43994399
ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr,
4400-
llvm::CallBase **CallOrInvoke = nullptr);
4400+
llvm::CallBase **CallOrInvoke = nullptr,
4401+
CGFunctionInfo const **ResolvedFnInfo = nullptr);
44014402

44024403
// If a Call or Invoke instruction was emitted for this CallExpr, this method
44034404
// writes the pointer to `CallOrInvoke` if it's not null.

0 commit comments

Comments
 (0)