Skip to content

Commit 32d2b45

Browse files
[LV][LAA] Vectorize math lib calls with mem write-only attribute
Teach LAA to consider safe specific math lib calls which are known to have set the memory write-only attribute. Those attributes are set to calls by inferNonMandatoryLibFuncAttrs, in BuildLibCalls.cpp, and the current ones are modf/modff and frexp/frexpf. This happens only when the calls are found through TLI to have vectorized counterparts.
1 parent 869079f commit 32d2b45

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

clang/test/CodeGen/aarch64-veclib-function-calls-linear-ptrs.c

+6-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ vectorize.
1717

1818
// CHECK-LABEL: define dso_local void @frexp_f64(
1919
// CHECK-SAME: ptr nocapture noundef readonly [[IN:%.*]], ptr nocapture noundef writeonly [[OUT1:%.*]], ptr nocapture noundef writeonly [[OUT2:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
20-
// CHECK: [[CALL:%.*]] = tail call double @frexp(double noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR2:[0-9]+]]
20+
// CHECK: [[CALL:%.*]] = tail call double @frexp(double noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR5:[0-9]+]]
2121
//
2222
void frexp_f64(double *in, double *out1, int *out2, int N) {
2323
for (int i = 0; i < N; ++i)
@@ -26,30 +26,27 @@ void frexp_f64(double *in, double *out1, int *out2, int N) {
2626

2727
// CHECK-LABEL: define dso_local void @frexp_f32(
2828
// CHECK-SAME: ptr nocapture noundef readonly [[IN:%.*]], ptr nocapture noundef writeonly [[OUT1:%.*]], ptr nocapture noundef writeonly [[OUT2:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
29-
// CHECK: [[CALL:%.*]] = tail call float @frexpf(float noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR2]]
29+
// CHECK: [[CALL:%.*]] = tail call float @frexpf(float noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR5]]
3030
//
3131
void frexp_f32(float *in, float *out1, int *out2, int N) {
3232
for (int i = 0; i < N; ++i)
3333
*out1 = frexpf(in[i], out2+i);
3434
}
3535

36-
37-
// TODO: LAA must allow vectorization.
38-
3936
// CHECK-LABEL: define dso_local void @modf_f64(
4037
// CHECK-SAME: ptr nocapture noundef readonly [[IN:%.*]], ptr nocapture noundef writeonly [[OUT1:%.*]], ptr nocapture noundef writeonly [[OUT2:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
41-
// CHECK: [[CALL:%.*]] = tail call double @modf(double noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR3:[0-9]+]]
38+
// CHECK: [[TMP11:%.*]] = tail call <vscale x 2 x double> @armpl_svmodf_f64_x(<vscale x 2 x double> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP10:%.*]], <vscale x 2 x i1> [[ACTIVE_LANE_MASK:%.*]])
39+
// CHECK: [[CALL:%.*]] = tail call double @modf(double noundef [[TMP14:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR6:[0-9]+]]
4240
//
4341
void modf_f64(double *in, double *out1, double *out2, int N) {
4442
for (int i = 0; i < N; ++i)
4543
out1[i] = modf(in[i], out2+i);
4644
}
4745

48-
// TODO: LAA must allow vectorization.
49-
5046
// CHECK-LABEL: define dso_local void @modf_f32(
5147
// CHECK-SAME: ptr nocapture noundef readonly [[IN:%.*]], ptr nocapture noundef writeonly [[OUT1:%.*]], ptr nocapture noundef writeonly [[OUT2:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
52-
// CHECK: [[CALL:%.*]] = tail call float @modff(float noundef [[TMP0:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR4:[0-9]+]]
48+
// CHECK: [[TMP11:%.*]] = tail call <vscale x 4 x float> @armpl_svmodf_f32_x(<vscale x 4 x float> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP10:%.*]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK:%.*]])
49+
// CHECK: [[CALL:%.*]] = tail call float @modff(float noundef [[TMP14:%.*]], ptr noundef [[ADD_PTR:%.*]]) #[[ATTR7:[0-9]+]]
5350
//
5451
void modf_f32(float *in, float *out1, float *out2, int N) {
5552
for (int i = 0; i < N; ++i)

llvm/lib/Analysis/LoopAccessAnalysis.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -2309,6 +2309,20 @@ bool LoopAccessInfo::canAnalyzeLoop() {
23092309
return true;
23102310
}
23112311

2312+
/// Returns whether \p I is a known math library call that has memory write-only
2313+
/// attribute set.
2314+
static bool isMathLibCallMemWriteOnly(const TargetLibraryInfo *TLI,
2315+
const Instruction &I) {
2316+
auto *Call = dyn_cast<CallInst>(&I);
2317+
if (!Call)
2318+
return false;
2319+
2320+
LibFunc Func;
2321+
TLI->getLibFunc(*Call, Func);
2322+
return Func == LibFunc::LibFunc_modf || Func == LibFunc::LibFunc_modff ||
2323+
Func == LibFunc::LibFunc_frexp || Func == LibFunc::LibFunc_frexpf;
2324+
}
2325+
23122326
void LoopAccessInfo::analyzeLoop(AAResults *AA, LoopInfo *LI,
23132327
const TargetLibraryInfo *TLI,
23142328
DominatorTree *DT) {
@@ -2405,6 +2419,11 @@ void LoopAccessInfo::analyzeLoop(AAResults *AA, LoopInfo *LI,
24052419

24062420
// Save 'store' instructions. Abort if other instructions write to memory.
24072421
if (I.mayWriteToMemory()) {
2422+
// We can safety handle math functions that have vectorized
2423+
// counterparts and have the memory write-only attribute set.
2424+
if (isMathLibCallMemWriteOnly(TLI, I))
2425+
continue;
2426+
24082427
auto *St = dyn_cast<StoreInst>(&I);
24092428
if (!St) {
24102429
recordAnalysis("CantVectorizeInstruction", St)

0 commit comments

Comments
 (0)