Skip to content

Commit 9589c12

Browse files
authored
[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 #86635
1 parent 80c0e8d commit 9589c12

File tree

3 files changed

+177
-56
lines changed

3 files changed

+177
-56
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -692,23 +692,15 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD,
692692
RValue Call =
693693
CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot());
694694

695-
// Check the supported intrinsic.
696695
if (unsigned BuiltinID = FD->getBuiltinID()) {
697-
auto IsErrnoIntrinsic = [&]() -> unsigned {
698-
switch (BuiltinID) {
699-
case Builtin::BIexpf:
700-
case Builtin::BI__builtin_expf:
701-
case Builtin::BI__builtin_expf128:
702-
return true;
703-
}
704-
// TODO: support more FP math libcalls
705-
return false;
706-
}();
707-
696+
// Check whether a FP math builtin function, such as BI__builtin_expf
697+
ASTContext &Context = CGF.getContext();
698+
bool ConstWithoutErrnoAndExceptions =
699+
Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
708700
// Restrict to target with errno, for example, MacOS doesn't set errno.
709-
if (IsErrnoIntrinsic && CGF.CGM.getLangOpts().MathErrno &&
710-
!CGF.Builder.getIsFPConstrained()) {
711-
ASTContext &Context = CGF.getContext();
701+
// TODO: Support builtin function with complex type returned, eg: cacosh
702+
if (ConstWithoutErrnoAndExceptions && CGF.CGM.getLangOpts().MathErrno &&
703+
!CGF.Builder.getIsFPConstrained() && Call.isScalar()) {
712704
// Emit "int" TBAA metadata on FP math libcalls.
713705
clang::QualType IntTy = Context.IntTy;
714706
TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy);
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
3+
// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,NONEWSTRUCTPATHTBAA
4+
// 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
5+
6+
float expf(float);
7+
double remainder(double, double);
8+
double fabs(double);
9+
double frexp(double, int *exp);
10+
void sincos(float a, float *s, float *c);
11+
float _Complex cacoshf(float _Complex);
12+
float crealf(float _Complex);
13+
14+
// Emit int TBAA metadata on FP math libcalls, which is useful for alias analysis
15+
16+
// CHECK-LABEL: define dso_local float @test_expf(
17+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
18+
// CHECK-NEXT: [[ENTRY:.*:]]
19+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40
20+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]]
21+
// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9:[0-9]+]], !tbaa [[TBAA6:![0-9]+]]
22+
// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]]
23+
// CHECK-NEXT: ret float [[MUL]]
24+
//
25+
float test_expf (float num[]) {
26+
const float expm2 = expf(num[10]); // Emit TBAA metadata on @expf
27+
float tmp = expm2 * num[10];
28+
return tmp;
29+
}
30+
31+
// CHECK-LABEL: define dso_local float @test_builtin_expf(
32+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0]] {
33+
// CHECK-NEXT: [[ENTRY:.*:]]
34+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40
35+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
36+
// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9]], !tbaa [[TBAA6]]
37+
// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]]
38+
// CHECK-NEXT: ret float [[MUL]]
39+
//
40+
float test_builtin_expf (float num[]) {
41+
const float expm2 = __builtin_expf(num[10]); // Emit TBAA metadata on @expf
42+
float tmp = expm2 * num[10];
43+
return tmp;
44+
}
45+
46+
//
47+
// Negative test: fabs cannot set errno
48+
// CHECK-LABEL: define dso_local double @test_fabs(
49+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
50+
// CHECK-NEXT: [[ENTRY:.*:]]
51+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80
52+
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]]
53+
// CHECK-NEXT: [[TMP1:%.*]] = tail call double @llvm.fabs.f64(double [[TMP0]])
54+
// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[TMP1]]
55+
// CHECK-NEXT: ret double [[MUL]]
56+
//
57+
double test_fabs (double num[]) {
58+
const double expm2 = fabs(num[10]); // Don't emit TBAA metadata
59+
double tmp = expm2 * num[10];
60+
return tmp;
61+
}
62+
63+
// CHECK-LABEL: define dso_local double @test_remainder(
64+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]], double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR0]] {
65+
// CHECK-NEXT: [[ENTRY:.*:]]
66+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80
67+
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]]
68+
// CHECK-NEXT: [[CALL:%.*]] = tail call double @remainder(double noundef [[TMP0]], double noundef [[A]]) #[[ATTR9]], !tbaa [[TBAA6]]
69+
// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]]
70+
// CHECK-NEXT: ret double [[MUL]]
71+
//
72+
double test_remainder (double num[], double a) {
73+
const double expm2 = remainder(num[10], a); // Emit TBAA metadata
74+
double tmp = expm2 * num[10];
75+
return tmp;
76+
}
77+
78+
//
79+
// TODO: frexp is not subject to any errors, but also writes to
80+
// its int pointer out argument, so it could emit int TBAA metadata.
81+
// CHECK-LABEL: define dso_local double @test_frexp(
82+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
83+
// CHECK-NEXT: [[ENTRY:.*:]]
84+
// CHECK-NEXT: [[E:%.*]] = alloca i32, align 4
85+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]]
86+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 16
87+
// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]]
88+
// CHECK-NEXT: [[CALL:%.*]] = call double @frexp(double noundef [[TMP0]], ptr noundef nonnull [[E]]) #[[ATTR9]]
89+
// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]]
90+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]]
91+
// CHECK-NEXT: ret double [[MUL]]
92+
//
93+
double test_frexp (double num[]) {
94+
int e;
95+
double expm2 = frexp(num[2], &e); // Don't emit TBAA metadata
96+
double tmp = expm2 * num[2];
97+
return tmp;
98+
}
99+
100+
//
101+
// Negative test: sincos is a library function, but is not a builtin function
102+
// checked in CodeGenFunction::EmitCallExpr.
103+
// CHECK-LABEL: define dso_local float @test_sincos(
104+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
105+
// CHECK-NEXT: [[ENTRY:.*:]]
106+
// CHECK-NEXT: [[SIN:%.*]] = alloca float, align 4
107+
// CHECK-NEXT: [[COS:%.*]] = alloca float, align 4
108+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]]
109+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]]
110+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8
111+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
112+
// CHECK-NEXT: call void @sincos(float noundef [[TMP0]], ptr noundef nonnull [[SIN]], ptr noundef nonnull [[COS]]) #[[ATTR9]]
113+
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[SIN]], align 4, !tbaa [[TBAA2]]
114+
// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[COS]], align 4, !tbaa [[TBAA2]]
115+
// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP1]], [[TMP2]]
116+
// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
117+
// CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[TMP3]]
118+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]]
119+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]]
120+
// CHECK-NEXT: ret float [[ADD]]
121+
//
122+
float test_sincos (float num[]) {
123+
float sin, cos;
124+
sincos(num[2], &sin, &cos); // Don't emit TBAA metadata
125+
float tmp = sin * cos + num[2];
126+
return tmp;
127+
}
128+
129+
// TODO: The builtin return a complex type
130+
// CHECK-LABEL: define dso_local float @test_cacoshf(
131+
// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7]] {
132+
// CHECK-NEXT: [[ENTRY:.*:]]
133+
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8
134+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
135+
// CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue [2 x float] poison, float [[TMP0]], 0
136+
// CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue [2 x float] [[DOTFCA_0_INSERT]], float 0.000000e+00, 1
137+
// CHECK-NEXT: [[CALL:%.*]] = tail call { float, float } @cacoshf([2 x float] noundef alignstack(8) [[DOTFCA_1_INSERT]]) #[[ATTR9]]
138+
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { float, float } [[CALL]], 0
139+
// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
140+
// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[TMP2]]
141+
// CHECK-NEXT: ret float [[ADD]]
142+
//
143+
float test_cacoshf (float num[]) {
144+
float _Complex z = cacoshf(num[2]); // Don't emit TBAA metadata
145+
float tmp = crealf(z) + num[2];
146+
return tmp;
147+
}
148+
149+
//.
150+
// NONEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
151+
// NONEWSTRUCTPATHTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0}
152+
// NONEWSTRUCTPATHTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
153+
// NONEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"}
154+
// NONEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
155+
// NONEWSTRUCTPATHTBAA: [[META7]] = !{!"int", [[META4]], i64 0}
156+
// NONEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0}
157+
// NONEWSTRUCTPATHTBAA: [[META9]] = !{!"double", [[META4]], i64 0}
158+
//.
159+
// NEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4}
160+
// NEWSTRUCTPATHTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"}
161+
// NEWSTRUCTPATHTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"}
162+
// NEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"}
163+
// NEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4}
164+
// NEWSTRUCTPATHTBAA: [[META7]] = !{[[META4]], i64 4, !"int"}
165+
// NEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0, i64 8}
166+
// NEWSTRUCTPATHTBAA: [[META9]] = !{[[META4]], i64 8, !"double"}
167+
//.
168+
//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
169+
// NEWSTRUCTPATHTBAA: {{.*}}
170+
// NONEWSTRUCTPATHTBAA: {{.*}}

clang/test/CodeGen/math-libcalls-tbaa.cpp

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)