Author: Allen Date: 2024-07-31T09:01:20+08:00 New Revision: 9589c128ae40df3e2277487544e693f3887f7d63
URL: https://github.com/llvm/llvm-project/commit/9589c128ae40df3e2277487544e693f3887f7d63 DIFF: https://github.com/llvm/llvm-project/commit/9589c128ae40df3e2277487544e693f3887f7d63.diff LOG: [clang codegen] Emit int TBAA metadata on more FP math libcalls (#100302) Follow #96025, except expf, more FP math libcalls in libm should also be supported. Fix https://github.com/llvm/llvm-project/issues/86635 Added: clang/test/CodeGen/math-libcalls-tbaa.c Modified: clang/lib/CodeGen/CGBuiltin.cpp Removed: clang/test/CodeGen/math-libcalls-tbaa.cpp ################################################################################ diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index f0651c280ff95..0c2ee446aa303 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -692,23 +692,15 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD, RValue Call = CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot()); - // Check the supported intrinsic. if (unsigned BuiltinID = FD->getBuiltinID()) { - auto IsErrnoIntrinsic = [&]() -> unsigned { - switch (BuiltinID) { - case Builtin::BIexpf: - case Builtin::BI__builtin_expf: - case Builtin::BI__builtin_expf128: - return true; - } - // TODO: support more FP math libcalls - return false; - }(); - + // Check whether a FP math builtin function, such as BI__builtin_expf + ASTContext &Context = CGF.getContext(); + bool ConstWithoutErrnoAndExceptions = + Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); // Restrict to target with errno, for example, MacOS doesn't set errno. - if (IsErrnoIntrinsic && CGF.CGM.getLangOpts().MathErrno && - !CGF.Builder.getIsFPConstrained()) { - ASTContext &Context = CGF.getContext(); + // TODO: Support builtin function with complex type returned, eg: cacosh + if (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); diff --git a/clang/test/CodeGen/math-libcalls-tbaa.c b/clang/test/CodeGen/math-libcalls-tbaa.c new file mode 100644 index 0000000000000..9c86eea67d14d --- /dev/null +++ b/clang/test/CodeGen/math-libcalls-tbaa.c @@ -0,0 +1,170 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,NONEWSTRUCTPATHTBAA +// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -new-struct-path-tbaa -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,NEWSTRUCTPATHTBAA + +float expf(float); +double remainder(double, double); +double fabs(double); +double frexp(double, int *exp); +void sincos(float a, float *s, float *c); +float _Complex cacoshf(float _Complex); +float crealf(float _Complex); + +// Emit int TBAA metadata on FP math libcalls, which is useful for alias analysis + +// CHECK-LABEL: define dso_local float @test_expf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9:[0-9]+]], !tbaa [[TBAA6:![0-9]+]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] +// CHECK-NEXT: ret float [[MUL]] +// +float test_expf (float num[]) { + const float expm2 = expf(num[10]); // Emit TBAA metadata on @expf + float tmp = expm2 * num[10]; + return tmp; +} + +// CHECK-LABEL: define dso_local float @test_builtin_expf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9]], !tbaa [[TBAA6]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] +// CHECK-NEXT: ret float [[MUL]] +// +float test_builtin_expf (float num[]) { + const float expm2 = __builtin_expf(num[10]); // Emit TBAA metadata on @expf + float tmp = expm2 * num[10]; + return tmp; +} + +// +// Negative test: fabs cannot set errno +// CHECK-LABEL: define dso_local double @test_fabs( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call double @llvm.fabs.f64(double [[TMP0]]) +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[TMP1]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_fabs (double num[]) { + const double expm2 = fabs(num[10]); // Don't emit TBAA metadata + double tmp = expm2 * num[10]; + return tmp; +} + +// CHECK-LABEL: define dso_local double @test_remainder( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]], double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[CALL:%.*]] = tail call double @remainder(double noundef [[TMP0]], double noundef [[A]]) #[[ATTR9]], !tbaa [[TBAA6]] +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_remainder (double num[], double a) { + const double expm2 = remainder(num[10], a); // Emit TBAA metadata + double tmp = expm2 * num[10]; + return tmp; +} + +// +// TODO: frexp is not subject to any errors, but also writes to +// its int pointer out argument, so it could emit int TBAA metadata. +// CHECK-LABEL: define dso_local double @test_frexp( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[E:%.*]] = alloca i32, align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 16 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[CALL:%.*]] = call double @frexp(double noundef [[TMP0]], ptr noundef nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_frexp (double num[]) { + int e; + double expm2 = frexp(num[2], &e); // Don't emit TBAA metadata + double tmp = expm2 * num[2]; + return tmp; +} + +// +// Negative test: sincos is a library function, but is not a builtin function +// checked in CodeGenFunction::EmitCallExpr. +// CHECK-LABEL: define dso_local float @test_sincos( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SIN:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[COS:%.*]] = alloca float, align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]] +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: call void @sincos(float noundef [[TMP0]], ptr noundef nonnull [[SIN]], ptr noundef nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[SIN]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[COS]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[TMP3]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]] +// CHECK-NEXT: ret float [[ADD]] +// +float test_sincos (float num[]) { + float sin, cos; + sincos(num[2], &sin, &cos); // Don't emit TBAA metadata + float tmp = sin * cos + num[2]; + return tmp; +} + +// TODO: The builtin return a complex type +// CHECK-LABEL: define dso_local float @test_cacoshf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue [2 x float] poison, float [[TMP0]], 0 +// CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue [2 x float] [[DOTFCA_0_INSERT]], float 0.000000e+00, 1 +// CHECK-NEXT: [[CALL:%.*]] = tail call { float, float } @cacoshf([2 x float] noundef alignstack(8) [[DOTFCA_1_INSERT]]) #[[ATTR9]] +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { float, float } [[CALL]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[TMP2]] +// CHECK-NEXT: ret float [[ADD]] +// +float test_cacoshf (float num[]) { + float _Complex z = cacoshf(num[2]); // Don't emit TBAA metadata + float tmp = crealf(z) + num[2]; + return tmp; +} + +//. +// NONEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"} +// NONEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META7]] = !{!"int", [[META4]], i64 0} +// NONEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META9]] = !{!"double", [[META4]], i64 0} +//. +// NEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4} +// NEWSTRUCTPATHTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"} +// NEWSTRUCTPATHTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"} +// NEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"} +// NEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4} +// NEWSTRUCTPATHTBAA: [[META7]] = !{[[META4]], i64 4, !"int"} +// NEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0, i64 8} +// NEWSTRUCTPATHTBAA: [[META9]] = !{[[META4]], i64 8, !"double"} +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// NEWSTRUCTPATHTBAA: {{.*}} +// NONEWSTRUCTPATHTBAA: {{.*}} diff --git a/clang/test/CodeGen/math-libcalls-tbaa.cpp b/clang/test/CodeGen/math-libcalls-tbaa.cpp deleted file mode 100644 index f15938dee0272..0000000000000 --- a/clang/test/CodeGen/math-libcalls-tbaa.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 - -// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,NoNewStructPathTBAA -// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -new-struct-path-tbaa -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,NewStructPathTBAA - -extern "C" float expf(float); - -// Emit int TBAA metadata on FP math libcalls, which is useful for alias analysis - -// CHECK-LABEL: define dso_local float @foo( -// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]], float noundef [[R2INV:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 -// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]] -// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA6:![0-9]+]] -// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] -// CHECK-NEXT: ret float [[MUL]] -// -extern "C" float foo (float num[], float r2inv, int n) { - const float expm2 = expf(num[10]); // Emit TBAA metadata on @expf - float tmp = expm2 * num[10]; - return tmp; -} -//. -// NoNewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} -// NoNewStructPathTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0} -// NoNewStructPathTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} -// NoNewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} -// NoNewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} -// NoNewStructPathTBAA: [[META7]] = !{!"int", [[META4]], i64 0} -//. -// NewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4} -// NewStructPathTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"} -// NewStructPathTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"} -// NewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} -// NewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4} -// NewStructPathTBAA: [[META7]] = !{[[META4]], i64 4, !"int"} -//. -//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: -// NewStructPathTBAA: {{.*}} -// NoNewStructPathTBAA: {{.*}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits