[clang] [clang][codegen] Don't mark "int" TBAA on FP libcalls with indirect args (PR #108853)
Benjamin Maxwell via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 24 05:11:30 PDT 2024
https://github.com/MacDue updated https://github.com/llvm/llvm-project/pull/108853
>From ec50a22e21ab44daafe3913847bf831fdf398f79 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Mon, 16 Sep 2024 16:27:23 +0000
Subject: [PATCH 1/6] Precommit math-libcalls-tbaa-indirect-args.c
---
.../math-libcalls-tbaa-indirect-args.c | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
diff --git a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
new file mode 100644
index 00000000000000..dd013dcc8b3ca8
--- /dev/null
+++ b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
@@ -0,0 +1,38 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple=x86_64-w64-mingw32 -fmath-errno -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK
+
+long double powl(long double a, long double b);
+
+// Negative test: powl is a floating-point math function that is
+// ConstWithoutErrnoAndExceptions, however, for this target long doubles are
+// passed indirectly via a pointer. Annotating the call with "int" TBAA metadata
+// will cause the setup for the BYVAL arguments to be incorrectly optimized out.
+
+// CHECK-LABEL: define dso_local void @test_powl(
+// CHECK-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret(x86_fp80) align 16 [[AGG_RESULT:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[TMP:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: [[BYVAL_TEMP1:%.*]] = alloca x86_fp80, align 16
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3:[0-9]+]]
+// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BYVAL_TEMP]], align 16, !tbaa [[TBAA3:![0-9]+]]
+// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
+// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BYVAL_TEMP1]], align 16, !tbaa [[TBAA3]]
+// CHECK-NEXT: call void @powl(ptr dead_on_unwind nonnull writable sret(x86_fp80) align 16 [[TMP]], ptr noundef nonnull [[BYVAL_TEMP]], ptr noundef nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA7:![0-9]+]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3]]
+// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
+// CHECK-NEXT: store x86_fp80 [[TMP0]], ptr [[AGG_RESULT]], align 16, !tbaa [[TBAA3]]
+// CHECK-NEXT: ret void
+//
+long double test_powl() {
+ return powl(2.0L, 2.0L); // Don't emit TBAA metadata
+}
+//.
+// CHECK: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK: [[META4]] = !{!"long double", [[META5:![0-9]+]], i64 0}
+// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK: [[META6]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
+// CHECK: [[META8]] = !{!"int", [[META5]], i64 0}
+//.
>From 15391d71f60f019727be88dbeef510f69852e547 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Mon, 16 Sep 2024 16:14:01 +0000
Subject: [PATCH 2/6] [clang][codegen] Don't mark "int" TBAA on FP libcalls
with indirect args
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.
---
clang/lib/CodeGen/CGBuiltin.cpp | 24 +++++++++++++++----
clang/lib/CodeGen/CGExpr.cpp | 6 ++++-
clang/lib/CodeGen/CodeGenFunction.h | 3 ++-
.../math-libcalls-tbaa-indirect-args.c | 4 +---
4 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 942468204f054c..7a4e9811afd605 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -691,23 +691,37 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
const CallExpr *E, llvm::Constant *calleeValue) {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
CGCallee callee = CGCallee::forDirect(calleeValue, GlobalDecl(FD));
+ llvm::CallBase *callOrInvoke = nullptr;
+ CGFunctionInfo const *FnInfo = nullptr;
RValue Call =
- CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot());
+ CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot(),
+ /*Chain=*/nullptr, &callOrInvoke, &FnInfo);
if (unsigned BuiltinID = FD->getBuiltinID()) {
// Check whether a FP math builtin function, such as BI__builtin_expf
ASTContext &Context = CGF.getContext();
bool ConstWithoutErrnoAndExceptions =
Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
+
+ // Before annotating this libcall with "int" TBAA metadata check all
+ // arguments are passed directly. On some targets, types such as "long
+ // double" are passed indirectly via a pointer, and annotating the call with
+ // "int" TBAA metadata will lead to set up for those arguments being
+ // incorrectly optimized out.
+ bool AllArgumentsPassedDirectly =
+ llvm::all_of(FnInfo->arguments(), [&](auto const &ArgInfo) {
+ return ArgInfo.info.isDirect() || ArgInfo.info.isExtend();
+ });
+
// Restrict to target with errno, for example, MacOS doesn't set errno.
// TODO: Support builtin function with complex type returned, eg: cacosh
- if (ConstWithoutErrnoAndExceptions && CGF.CGM.getLangOpts().MathErrno &&
- !CGF.Builder.getIsFPConstrained() && Call.isScalar()) {
+ if (AllArgumentsPassedDirectly && ConstWithoutErrnoAndExceptions &&
+ CGF.CGM.getLangOpts().MathErrno && !CGF.Builder.getIsFPConstrained() &&
+ Call.isScalar()) {
// Emit "int" TBAA metadata on FP math libcalls.
clang::QualType IntTy = Context.IntTy;
TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy);
- Instruction *Inst = cast<llvm::Instruction>(Call.getScalarVal());
- CGF.CGM.DecorateInstructionWithTBAA(Inst, TBAAInfo);
+ CGF.CGM.DecorateInstructionWithTBAA(callOrInvoke, TBAAInfo);
}
}
return Call;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 35b5daaf6d4b55..9166db4c74128c 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5932,7 +5932,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
const CGCallee &OrigCallee, const CallExpr *E,
ReturnValueSlot ReturnValue,
llvm::Value *Chain,
- llvm::CallBase **CallOrInvoke) {
+ llvm::CallBase **CallOrInvoke,
+ CGFunctionInfo const **ResolvedFnInfo) {
// Get the actual function type. The callee type will always be a pointer to
// function type or a block pointer type.
assert(CalleeType->isFunctionPointerType() &&
@@ -6111,6 +6112,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
Args, FnType, /*ChainCall=*/Chain);
+ if (ResolvedFnInfo)
+ *ResolvedFnInfo = &FnInfo;
+
// C99 6.5.2.2p6:
// If the expression that denotes the called function has a type
// that does not include a prototype, [the default argument
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 2df17e83bae2ee..a29fcf43bca9a5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4397,7 +4397,8 @@ class CodeGenFunction : public CodeGenTypeCache {
}
RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E,
ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr,
- llvm::CallBase **CallOrInvoke = nullptr);
+ llvm::CallBase **CallOrInvoke = nullptr,
+ CGFunctionInfo const **ResolvedFnInfo = nullptr);
// If a Call or Invoke instruction was emitted for this CallExpr, this method
// writes the pointer to `CallOrInvoke` if it's not null.
diff --git a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
index dd013dcc8b3ca8..56c6b3ec00bc7e 100644
--- a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
+++ b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
@@ -19,7 +19,7 @@ long double powl(long double a, long double b);
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BYVAL_TEMP1]], align 16, !tbaa [[TBAA3]]
// CHECK-NEXT: call void @powl(ptr dead_on_unwind nonnull writable sret(x86_fp80) align 16 [[TMP]], ptr noundef nonnull [[BYVAL_TEMP]], ptr noundef nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
-// CHECK-NEXT: [[TMP0:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA7:![0-9]+]]
+// CHECK-NEXT: [[TMP0:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA3]]
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3]]
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
// CHECK-NEXT: store x86_fp80 [[TMP0]], ptr [[AGG_RESULT]], align 16, !tbaa [[TBAA3]]
@@ -33,6 +33,4 @@ long double test_powl() {
// CHECK: [[META4]] = !{!"long double", [[META5:![0-9]+]], i64 0}
// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
// CHECK: [[META6]] = !{!"Simple C/C++ TBAA"}
-// CHECK: [[TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
-// CHECK: [[META8]] = !{!"int", [[META5]], i64 0}
//.
>From 8734e6d4c31fd92067f450779c53232a23af0671 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Tue, 17 Sep 2024 12:48:40 +0000
Subject: [PATCH 3/6] Check return info too
---
clang/lib/CodeGen/CGBuiltin.cpp | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 7a4e9811afd605..180504cce3a5b4 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -703,19 +703,28 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
bool ConstWithoutErrnoAndExceptions =
Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
+ auto isDirectOrIgnore = [&](ABIArgInfo const &info) {
+ // For a non-aggregate types direct/extend means the type will be used
+ // directly (or a sign/zero extension of it) on the call (not a
+ // input/output pointer).
+ return info.isDirect() || info.isExtend() || info.isIgnore();
+ };
+
// Before annotating this libcall with "int" TBAA metadata check all
- // arguments are passed directly. On some targets, types such as "long
- // double" are passed indirectly via a pointer, and annotating the call with
- // "int" TBAA metadata will lead to set up for those arguments being
- // incorrectly optimized out.
- bool AllArgumentsPassedDirectly =
- llvm::all_of(FnInfo->arguments(), [&](auto const &ArgInfo) {
- return ArgInfo.info.isDirect() || ArgInfo.info.isExtend();
- });
+ // arguments/results are passed directly. On some targets, types such as
+ // "long double" are passed indirectly via a pointer, and annotating the
+ // call with "int" TBAA metadata will lead to set up for those arguments
+ // being incorrectly optimized out.
+ bool ReturnAndAllArgumentsDirect =
+ isDirectOrIgnore(FnInfo->getReturnInfo()) &&
+ llvm::all_of(FnInfo->arguments(),
+ [&](CGFunctionInfoArgInfo const &ArgInfo) {
+ return isDirectOrIgnore(ArgInfo.info);
+ });
// Restrict to target with errno, for example, MacOS doesn't set errno.
// TODO: Support builtin function with complex type returned, eg: cacosh
- if (AllArgumentsPassedDirectly && ConstWithoutErrnoAndExceptions &&
+ if (ReturnAndAllArgumentsDirect && ConstWithoutErrnoAndExceptions &&
CGF.CGM.getLangOpts().MathErrno && !CGF.Builder.getIsFPConstrained() &&
Call.isScalar()) {
// Emit "int" TBAA metadata on FP math libcalls.
>From 3f3972ad22c0b1da956deb1d155f8706cf691f13 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Tue, 17 Sep 2024 16:06:44 +0000
Subject: [PATCH 4/6] Extend test
---
.../math-libcalls-tbaa-indirect-args.c | 224 +++++++++++++++---
1 file changed, 195 insertions(+), 29 deletions(-)
diff --git a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
index 56c6b3ec00bc7e..6b4df35068b15a 100644
--- a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
+++ b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
@@ -1,36 +1,202 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
-// RUN: %clang_cc1 -triple=x86_64-w64-mingw32 -fmath-errno -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "(@powl|@cargl|!|load|store)" --version 5
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple x86_64-pc-win64 -o - | FileCheck %s -check-prefixes=CHECK-WIN64
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple i686-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK-I686
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple powerpc-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK-PPC
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple armv7-none-linux-gnueabi -o - | FileCheck %s -check-prefixes=CHECK-ARM
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s -check-prefixes=CHECK-ARM-HF
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple thumbv7k-apple-watchos2.0 -o - -target-abi aapcs16 | FileCheck %s -check-prefixes=CHECK-THUMB
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple aarch64-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK-AARCH
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple spir -o - | FileCheck %s -check-prefixes=CHECK-SPIR
+// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple x86_64-w64-mingw32 -o - | FileCheck %s -check-prefixes=CHECK-MINGW32
+
+// This file checks that if arguments/results are passed indirectly (i.e. via
+// pointers), then the "int" TBAA metadata is not set on the FP libcall as this
+// can lead to optimizations incorrectly optimizing out the setup for the call.
long double powl(long double a, long double b);
-// Negative test: powl is a floating-point math function that is
-// ConstWithoutErrnoAndExceptions, however, for this target long doubles are
-// passed indirectly via a pointer. Annotating the call with "int" TBAA metadata
-// will cause the setup for the BYVAL arguments to be incorrectly optimized out.
+// CHECK-LABEL: define dso_local x86_fp80 @test_powl(
+// CHECK-SAME: x86_fp80 noundef [[A:%.*]], x86_fp80 noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK: [[CALL:%.*]] = tail call x86_fp80 @powl(x86_fp80 noundef [[A]], x86_fp80 noundef [[B]]) #[[ATTR5:[0-9]+]], !tbaa [[TBAA2:![0-9]+]]
+//
+// CHECK-WIN64-LABEL: define dso_local x86_fp80 @test_powl(
+// CHECK-WIN64-SAME: x86_fp80 noundef [[A:%.*]], x86_fp80 noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-WIN64: [[CALL:%.*]] = tail call x86_fp80 @powl(x86_fp80 noundef [[A]], x86_fp80 noundef [[B]]) #[[ATTR5:[0-9]+]], !tbaa [[TBAA2:![0-9]+]]
+//
+// CHECK-I686-LABEL: define dso_local x86_fp80 @test_powl(
+// CHECK-I686-SAME: x86_fp80 noundef [[A:%.*]], x86_fp80 noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-I686: [[CALL:%.*]] = tail call x86_fp80 @powl(x86_fp80 noundef [[A]], x86_fp80 noundef [[B]]) #[[ATTR5:[0-9]+]], !tbaa [[TBAA3:![0-9]+]]
+//
+// CHECK-PPC-LABEL: define dso_local ppc_fp128 @test_powl(
+// CHECK-PPC-SAME: ppc_fp128 noundef [[A:%.*]], ppc_fp128 noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-PPC: [[CALL:%.*]] = tail call ppc_fp128 @powl(ppc_fp128 noundef [[A]], ppc_fp128 noundef [[B]]) #[[ATTR3:[0-9]+]], !tbaa [[TBAA2:![0-9]+]]
+//
+// CHECK-ARM-LABEL: define dso_local double @test_powl(
+// CHECK-ARM-SAME: double noundef [[A:%.*]], double noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-ARM: [[CALL:%.*]] = tail call double @powl(double noundef [[A]], double noundef [[B]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA3:![0-9]+]]
+//
+// CHECK-ARM-HF-LABEL: define dso_local double @test_powl(
+// CHECK-ARM-HF-SAME: double noundef [[A:%.*]], double noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-ARM-HF: [[CALL:%.*]] = tail call double @powl(double noundef [[A]], double noundef [[B]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA3:![0-9]+]]
+//
+// CHECK-THUMB-LABEL: define double @test_powl(
+// CHECK-THUMB-SAME: double noundef [[A:%.*]], double noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-THUMB: [[CALL:%.*]] = tail call double @powl(double noundef [[A]], double noundef [[B]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA3:![0-9]+]]
+//
+// CHECK-AARCH-LABEL: define dso_local fp128 @test_powl(
+// CHECK-AARCH-SAME: fp128 noundef [[A:%.*]], fp128 noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-AARCH: [[CALL:%.*]] = tail call fp128 @powl(fp128 noundef [[A]], fp128 noundef [[B]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA2:![0-9]+]]
+//
+// CHECK-SPIR-LABEL: define dso_local spir_func double @test_powl(
+// CHECK-SPIR-SAME: double noundef [[A:%.*]], double noundef [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-SPIR: [[CALL:%.*]] = tail call spir_func double @powl(double noundef [[A]], double noundef [[B]]) #[[ATTR3:[0-9]+]], !tbaa [[TBAA2:![0-9]+]]
+//
+// CHECK-MINGW32-LABEL: define dso_local void @test_powl(
+// CHECK-MINGW32-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret(x86_fp80) align 16 [[AGG_RESULT:%.*]], ptr nocapture noundef readonly [[TMP0:%.*]], ptr nocapture noundef readonly [[TMP1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-MINGW32: [[A:%.*]] = load x86_fp80, ptr [[TMP0]], align 16, !tbaa [[TBAA3:![0-9]+]]
+// CHECK-MINGW32: [[B:%.*]] = load x86_fp80, ptr [[TMP1]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: store x86_fp80 [[A]], ptr [[BYVAL_TEMP:%.*]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: store x86_fp80 [[B]], ptr [[BYVAL_TEMP1:%.*]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: call void @powl(ptr dead_on_unwind nonnull writable sret(x86_fp80) align 16 [[TMP:%.*]], ptr noundef nonnull [[BYVAL_TEMP]], ptr noundef nonnull [[BYVAL_TEMP1]]) #[[ATTR3:[0-9]+]]
+// CHECK-MINGW32: [[TMP2:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: store x86_fp80 [[TMP2]], ptr [[AGG_RESULT]], align 16, !tbaa [[TBAA3]]
+//
+long double test_powl(long double a, long double b) {
+ return powl(a, b); // Don't emit TBAA metadata
+}
-// CHECK-LABEL: define dso_local void @test_powl(
-// CHECK-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret(x86_fp80) align 16 [[AGG_RESULT:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
-// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP:%.*]] = alloca x86_fp80, align 16
-// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca x86_fp80, align 16
-// CHECK-NEXT: [[BYVAL_TEMP1:%.*]] = alloca x86_fp80, align 16
-// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3:[0-9]+]]
-// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BYVAL_TEMP]], align 16, !tbaa [[TBAA3:![0-9]+]]
-// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
-// CHECK-NEXT: store x86_fp80 0xK40008000000000000000, ptr [[BYVAL_TEMP1]], align 16, !tbaa [[TBAA3]]
-// CHECK-NEXT: call void @powl(ptr dead_on_unwind nonnull writable sret(x86_fp80) align 16 [[TMP]], ptr noundef nonnull [[BYVAL_TEMP]], ptr noundef nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
-// CHECK-NEXT: [[TMP0:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA3]]
-// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3]]
-// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr nonnull [[BYVAL_TEMP1]]) #[[ATTR3]]
-// CHECK-NEXT: store x86_fp80 [[TMP0]], ptr [[AGG_RESULT]], align 16, !tbaa [[TBAA3]]
-// CHECK-NEXT: ret void
-//
-long double test_powl() {
- return powl(2.0L, 2.0L); // Don't emit TBAA metadata
+// CHECK-LABEL: define dso_local { x86_fp80, x86_fp80 } @test_cargl(
+// CHECK-SAME: ptr nocapture noundef readonly byval({ x86_fp80, x86_fp80 }) align 16 [[CLD:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// CHECK: [[CLD_REAL:%.*]] = load x86_fp80, ptr [[CLD]], align 16
+// CHECK: [[CLD_IMAG:%.*]] = load x86_fp80, ptr [[CLD_IMAGP:%.*]], align 16
+// CHECK: store x86_fp80 [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 16
+// CHECK: store x86_fp80 [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 16
+// CHECK: [[CALL:%.*]] = tail call x86_fp80 @cargl(ptr noundef nonnull byval({ x86_fp80, x86_fp80 }) align 16 [[BYVAL_TEMP]]) #[[ATTR5]]
+//
+// CHECK-WIN64-LABEL: define dso_local { x86_fp80, x86_fp80 } @test_cargl(
+// CHECK-WIN64-SAME: ptr nocapture noundef readonly byval({ x86_fp80, x86_fp80 }) align 16 [[CLD:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// CHECK-WIN64: [[CLD_REAL:%.*]] = load x86_fp80, ptr [[CLD]], align 16
+// CHECK-WIN64: [[CLD_IMAG:%.*]] = load x86_fp80, ptr [[CLD_IMAGP:%.*]], align 16
+// CHECK-WIN64: store x86_fp80 [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 16
+// CHECK-WIN64: store x86_fp80 [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 16
+// CHECK-WIN64: [[CALL:%.*]] = tail call x86_fp80 @cargl(ptr noundef nonnull byval({ x86_fp80, x86_fp80 }) align 16 [[BYVAL_TEMP]]) #[[ATTR5]]
+//
+// CHECK-I686-LABEL: define dso_local void @test_cargl(
+// CHECK-I686-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret({ x86_fp80, x86_fp80 }) align 4 [[AGG_RESULT:%.*]], ptr nocapture noundef readonly byval({ x86_fp80, x86_fp80 }) align 4 [[CLD:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// CHECK-I686: [[CLD_REAL:%.*]] = load x86_fp80, ptr [[CLD]], align 4
+// CHECK-I686: [[CLD_IMAG:%.*]] = load x86_fp80, ptr [[CLD_IMAGP:%.*]], align 4
+// CHECK-I686: store x86_fp80 [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 4
+// CHECK-I686: store x86_fp80 [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 4
+// CHECK-I686: [[CALL:%.*]] = tail call x86_fp80 @cargl(ptr noundef nonnull byval({ x86_fp80, x86_fp80 }) align 4 [[BYVAL_TEMP]]) #[[ATTR5]]
+// CHECK-I686: store x86_fp80 [[MUL_RL:%.*]], ptr [[AGG_RESULT]], align 4
+// CHECK-I686: store x86_fp80 [[MUL_IR:%.*]], ptr [[AGG_RESULT_IMAGP:%.*]], align 4
+//
+// CHECK-PPC-LABEL: define dso_local void @test_cargl(
+// CHECK-PPC-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret({ ppc_fp128, ppc_fp128 }) align 16 [[AGG_RESULT:%.*]], ptr nocapture noundef readonly byval({ ppc_fp128, ppc_fp128 }) align 16 [[CLD:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-PPC: [[CLD_REAL:%.*]] = load ppc_fp128, ptr [[CLD]], align 16
+// CHECK-PPC: [[CLD_IMAG:%.*]] = load ppc_fp128, ptr [[CLD_IMAGP:%.*]], align 16
+// CHECK-PPC: store ppc_fp128 [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 16
+// CHECK-PPC: store ppc_fp128 [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 16
+// CHECK-PPC: [[CALL:%.*]] = tail call ppc_fp128 @cargl(ptr noundef nonnull byval({ ppc_fp128, ppc_fp128 }) align 16 [[BYVAL_TEMP]]) #[[ATTR3]]
+// CHECK-PPC: store ppc_fp128 [[MUL_RL:%.*]], ptr [[AGG_RESULT]], align 16
+// CHECK-PPC: store ppc_fp128 [[MUL_IR:%.*]], ptr [[AGG_RESULT_IMAGP:%.*]], align 16
+//
+// CHECK-ARM-LABEL: define dso_local void @test_cargl(
+// CHECK-ARM-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret({ double, double }) align 8 [[AGG_RESULT:%.*]], [2 x i64] noundef [[CLD_COERCE:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-ARM: [[CALL:%.*]] = tail call double @cargl([2 x i64] noundef [[CLD_COERCE]]) #[[ATTR2]], !tbaa [[TBAA3]]
+// CHECK-ARM: store double [[MUL_RL:%.*]], ptr [[AGG_RESULT]], align 8
+// CHECK-ARM: store double [[MUL_IR:%.*]], ptr [[AGG_RESULT_IMAGP:%.*]], align 8
+//
+// CHECK-ARM-HF-LABEL: define dso_local { double, double } @test_cargl(
+// CHECK-ARM-HF-SAME: { double, double } noundef [[CLD_COERCE:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-ARM-HF: [[CALL:%.*]] = tail call double @cargl({ double, double } noundef [[CLD_COERCE]]) #[[ATTR2]], !tbaa [[TBAA3]]
+//
+// CHECK-THUMB-LABEL: define { double, double } @test_cargl(
+// CHECK-THUMB-SAME: [2 x double] noundef [[CLD_COERCE:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-THUMB: [[CALL:%.*]] = tail call double @cargl([2 x double] noundef [[CLD_COERCE]]) #[[ATTR2]], !tbaa [[TBAA3]]
+//
+// CHECK-AARCH-LABEL: define dso_local { fp128, fp128 } @test_cargl(
+// CHECK-AARCH-SAME: [2 x fp128] noundef alignstack(16) [[CLD_COERCE:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-AARCH: [[CALL:%.*]] = tail call fp128 @cargl([2 x fp128] noundef alignstack(16) [[CLD_COERCE]]) #[[ATTR2]], !tbaa [[TBAA2]]
+//
+// CHECK-SPIR-LABEL: define dso_local spir_func void @test_cargl(
+// CHECK-SPIR-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret({ double, double }) align 8 [[AGG_RESULT:%.*]], ptr nocapture noundef readonly byval({ double, double }) align 8 [[CLD:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-SPIR: [[CLD_REAL:%.*]] = load double, ptr [[CLD]], align 8
+// CHECK-SPIR: [[CLD_IMAG:%.*]] = load double, ptr [[CLD_IMAGP:%.*]], align 8
+// CHECK-SPIR: store double [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 8
+// CHECK-SPIR: store double [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 8
+// CHECK-SPIR: [[CALL:%.*]] = tail call spir_func double @cargl(ptr noundef nonnull byval({ double, double }) align 8 [[BYVAL_TEMP]]) #[[ATTR3]]
+// CHECK-SPIR: store double [[MUL_RL:%.*]], ptr [[AGG_RESULT]], align 8
+// CHECK-SPIR: store double [[MUL_IR:%.*]], ptr [[AGG_RESULT_IMAGP:%.*]], align 8
+//
+// CHECK-MINGW32-LABEL: define dso_local void @test_cargl(
+// CHECK-MINGW32-SAME: ptr dead_on_unwind noalias nocapture writable writeonly sret({ x86_fp80, x86_fp80 }) align 16 [[AGG_RESULT:%.*]], ptr nocapture noundef readonly [[CLD:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-MINGW32: [[CLD_REAL:%.*]] = load x86_fp80, ptr [[CLD]], align 16
+// CHECK-MINGW32: [[CLD_IMAG:%.*]] = load x86_fp80, ptr [[CLD_IMAGP:%.*]], align 16
+// CHECK-MINGW32: store x86_fp80 [[CLD_REAL]], ptr [[BYVAL_TEMP:%.*]], align 16
+// CHECK-MINGW32: store x86_fp80 [[CLD_IMAG]], ptr [[BYVAL_TEMP_IMAGP:%.*]], align 16
+// CHECK-MINGW32: call void @cargl(ptr dead_on_unwind nonnull writable sret(x86_fp80) align 16 [[TMP:%.*]], ptr noundef nonnull [[BYVAL_TEMP]]) #[[ATTR3]]
+// CHECK-MINGW32: [[TMP0:%.*]] = load x86_fp80, ptr [[TMP]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: [[CLD_REAL3:%.*]] = load x86_fp80, ptr [[CLD]], align 16
+// CHECK-MINGW32: [[CLD_IMAG5:%.*]] = load x86_fp80, ptr [[CLD_IMAGP]], align 16
+// CHECK-MINGW32: store x86_fp80 [[MUL_RL:%.*]], ptr [[AGG_RESULT]], align 16
+// CHECK-MINGW32: store x86_fp80 [[MUL_IR:%.*]], ptr [[AGG_RESULT_IMAGP:%.*]], align 16
+//
+_Complex long double test_cargl(_Complex long double cld) {
+ long double v2 = __builtin_cargl(cld);
+ _Complex long double tmp = v2 * cld;
+ return tmp;
}
+
+//.
+// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+// CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// CHECK: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-WIN64: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK-WIN64: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+// CHECK-WIN64: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// CHECK-WIN64: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-I686: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK-I686: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK-I686: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK-I686: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-PPC: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK-PPC: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+// CHECK-PPC: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// CHECK-PPC: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-ARM: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK-ARM: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK-ARM: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK-ARM: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-ARM-HF: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK-ARM-HF: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK-ARM-HF: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK-ARM-HF: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-THUMB: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK-THUMB: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK-THUMB: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK-THUMB: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-AARCH: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK-AARCH: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+// CHECK-AARCH: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// CHECK-AARCH: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// CHECK-SPIR: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// CHECK-SPIR: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+// CHECK-SPIR: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// CHECK-SPIR: [[META5]] = !{!"Simple C/C++ TBAA"}
//.
-// CHECK: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
-// CHECK: [[META4]] = !{!"long double", [[META5:![0-9]+]], i64 0}
-// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
-// CHECK: [[META6]] = !{!"Simple C/C++ TBAA"}
+// CHECK-MINGW32: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// CHECK-MINGW32: [[META4]] = !{!"long double", [[META5:![0-9]+]], i64 0}
+// CHECK-MINGW32: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK-MINGW32: [[META6]] = !{!"Simple C/C++ TBAA"}
//.
>From 85aff86b12008710ea55bb03342f6fa600b35280 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Wed, 18 Sep 2024 12:04:58 +0000
Subject: [PATCH 5/6] Fixups
---
clang/lib/CodeGen/CGBuiltin.cpp | 42 +++++++++++++++------------------
1 file changed, 19 insertions(+), 23 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 180504cce3a5b4..c1cd7afbdb8056 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -687,6 +687,22 @@ static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) {
return CGF.Builder.CreateICmpSLT(V, Zero);
}
+/// Checks no arguments or results are passed indirectly in the ABI (i.e. via a
+/// hidden pointer). This is used to check annotating FP libcalls (that could
+/// set `errno`) with "int" TBAA metadata is safe. If any floating-point
+/// arguments are passed indirectly, setup for the call could be incorrectly
+/// optimized out.
+static bool HasNoIndirectArgumentsOrResults(CGFunctionInfo const &FnInfo) {
+ auto IsIndirect = [&](ABIArgInfo const &info) {
+ return info.isIndirect() || info.isIndirectAliased() || info.isInAlloca();
+ };
+ return !IsIndirect(FnInfo.getReturnInfo()) &&
+ llvm::none_of(FnInfo.arguments(),
+ [&](CGFunctionInfoArgInfo const &ArgInfo) {
+ return IsIndirect(ArgInfo.info);
+ });
+}
+
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
const CallExpr *E, llvm::Constant *calleeValue) {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
@@ -702,31 +718,11 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
ASTContext &Context = CGF.getContext();
bool ConstWithoutErrnoAndExceptions =
Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
-
- auto isDirectOrIgnore = [&](ABIArgInfo const &info) {
- // For a non-aggregate types direct/extend means the type will be used
- // directly (or a sign/zero extension of it) on the call (not a
- // input/output pointer).
- return info.isDirect() || info.isExtend() || info.isIgnore();
- };
-
- // Before annotating this libcall with "int" TBAA metadata check all
- // arguments/results are passed directly. On some targets, types such as
- // "long double" are passed indirectly via a pointer, and annotating the
- // call with "int" TBAA metadata will lead to set up for those arguments
- // being incorrectly optimized out.
- bool ReturnAndAllArgumentsDirect =
- isDirectOrIgnore(FnInfo->getReturnInfo()) &&
- llvm::all_of(FnInfo->arguments(),
- [&](CGFunctionInfoArgInfo const &ArgInfo) {
- return isDirectOrIgnore(ArgInfo.info);
- });
-
// Restrict to target with errno, for example, MacOS doesn't set errno.
// TODO: Support builtin function with complex type returned, eg: cacosh
- if (ReturnAndAllArgumentsDirect && ConstWithoutErrnoAndExceptions &&
- CGF.CGM.getLangOpts().MathErrno && !CGF.Builder.getIsFPConstrained() &&
- Call.isScalar()) {
+ if (ConstWithoutErrnoAndExceptions && CGF.CGM.getLangOpts().MathErrno &&
+ !CGF.Builder.getIsFPConstrained() && Call.isScalar() &&
+ HasNoIndirectArgumentsOrResults(*FnInfo)) {
// Emit "int" TBAA metadata on FP math libcalls.
clang::QualType IntTy = Context.IntTy;
TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy);
>From c5d02c1bc7f37dde098598cd155bff55a4ee63de Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Tue, 24 Sep 2024 12:09:30 +0000
Subject: [PATCH 6/6] Add ilogbl test case
---
.../math-libcalls-tbaa-indirect-args.c | 52 ++++++++++++++++++-
1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
index 6b4df35068b15a..b94f9641decc8e 100644
--- a/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
+++ b/clang/test/CodeGen/math-libcalls-tbaa-indirect-args.c
@@ -1,4 +1,4 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "(@powl|@cargl|!|load|store)" --version 5
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "(@powl|@cargl|@ilogbl|!|load|store)" --version 5
// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK
// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple x86_64-pc-win64 -o - | FileCheck %s -check-prefixes=CHECK-WIN64
// RUN: %clang_cc1 %s -O3 -fmath-errno -emit-llvm -triple i686-unknown-unknown -o - | FileCheck %s -check-prefixes=CHECK-I686
@@ -63,7 +63,7 @@ long double powl(long double a, long double b);
// CHECK-MINGW32: store x86_fp80 [[TMP2]], ptr [[AGG_RESULT]], align 16, !tbaa [[TBAA3]]
//
long double test_powl(long double a, long double b) {
- return powl(a, b); // Don't emit TBAA metadata
+ return powl(a, b);
}
// CHECK-LABEL: define dso_local { x86_fp80, x86_fp80 } @test_cargl(
@@ -149,6 +149,54 @@ _Complex long double test_cargl(_Complex long double cld) {
return tmp;
}
+
+int ilogbl(long double a);
+
+// CHECK-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-SAME: x86_fp80 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK: [[CALL:%.*]] = tail call i32 @ilogbl(x86_fp80 noundef [[A]]) #[[ATTR5]], !tbaa [[TBAA2]]
+//
+// CHECK-WIN64-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-WIN64-SAME: x86_fp80 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-WIN64: [[CALL:%.*]] = tail call i32 @ilogbl(x86_fp80 noundef [[A]]) #[[ATTR5]], !tbaa [[TBAA2]]
+//
+// CHECK-I686-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-I686-SAME: x86_fp80 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-I686: [[CALL:%.*]] = tail call i32 @ilogbl(x86_fp80 noundef [[A]]) #[[ATTR5]], !tbaa [[TBAA3]]
+//
+// CHECK-PPC-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-PPC-SAME: ppc_fp128 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-PPC: [[CALL:%.*]] = tail call i32 @ilogbl(ppc_fp128 noundef [[A]]) #[[ATTR3]], !tbaa [[TBAA2]]
+//
+// CHECK-ARM-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-ARM-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-ARM: [[CALL:%.*]] = tail call i32 @ilogbl(double noundef [[A]]) #[[ATTR2]], !tbaa [[TBAA3]]
+//
+// CHECK-ARM-HF-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-ARM-HF-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-ARM-HF: [[CALL:%.*]] = tail call i32 @ilogbl(double noundef [[A]]) #[[ATTR2]], !tbaa [[TBAA3]]
+//
+// CHECK-THUMB-LABEL: define i32 @test_ilogb(
+// CHECK-THUMB-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-THUMB: [[CALL:%.*]] = tail call i32 @ilogbl(double noundef [[A]]) #[[ATTR2]], !tbaa [[TBAA3]]
+//
+// CHECK-AARCH-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-AARCH-SAME: fp128 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-AARCH: [[CALL:%.*]] = tail call i32 @ilogbl(fp128 noundef [[A]]) #[[ATTR2]], !tbaa [[TBAA2]]
+//
+// CHECK-SPIR-LABEL: define dso_local spir_func i32 @test_ilogb(
+// CHECK-SPIR-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-SPIR: [[CALL:%.*]] = tail call spir_func i32 @ilogbl(double noundef [[A]]) #[[ATTR3]], !tbaa [[TBAA2]]
+//
+// CHECK-MINGW32-LABEL: define dso_local i32 @test_ilogb(
+// CHECK-MINGW32-SAME: ptr nocapture noundef readonly [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-MINGW32: [[A:%.*]] = load x86_fp80, ptr [[TMP0]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: store x86_fp80 [[A]], ptr [[BYVAL_TEMP:%.*]], align 16, !tbaa [[TBAA3]]
+// CHECK-MINGW32: [[CALL:%.*]] = call i32 @ilogbl(ptr noundef nonnull [[BYVAL_TEMP]]) #[[ATTR3]]
+//
+int test_ilogb(long double a) {
+ return ilogbl(a);
+}
//.
// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
More information about the cfe-commits
mailing list