aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
diff options
context:
space:
mode:
authorYingwei Zheng <dtcxzyw2333@gmail.com>2025-04-12 15:11:54 +0800
committerGitHub <noreply@github.com>2025-04-12 15:11:54 +0800
commit76e07d8ba5286daf349ef19588c8c011162bec09 (patch)
tree56c048f2e0f032670e8f2190af1bb13145998e2f /llvm/lib/Transforms/Utils/BuildLibCalls.cpp
parent339f58de16ac7a31869d189bec6cad7696958546 (diff)
downloadllvm-76e07d8ba5286daf349ef19588c8c011162bec09.zip
llvm-76e07d8ba5286daf349ef19588c8c011162bec09.tar.gz
llvm-76e07d8ba5286daf349ef19588c8c011162bec09.tar.bz2
[LibCall] Infer nocallback for libcalls (#135173)
This patch adds `nocallback` attributes for string/math libcalls. It allows FuncAttributor to infer `norecurse` more precisely and encourages more aggressive global optimization.
Diffstat (limited to 'llvm/lib/Transforms/Utils/BuildLibCalls.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/BuildLibCalls.cpp39
1 files changed, 38 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 24eefc9..a5f6047 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -47,6 +47,7 @@ STATISTIC(
NumWriteArgumentMemOrErrnoMemOnly,
"Number of functions inferred as memory(argmem: write, errnomem: write)");
STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind");
+STATISTIC(NumNoCallback, "Number of functions inferred as nocallback");
STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture");
STATISTIC(NumWriteOnlyArg, "Number of arguments inferred as writeonly");
STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly");
@@ -148,6 +149,14 @@ static bool setDoesNotThrow(Function &F) {
return true;
}
+static bool setDoesNotCallback(Function &F) {
+ if (F.hasFnAttribute(Attribute::NoCallback))
+ return false;
+ F.addFnAttr(Attribute::NoCallback);
+ ++NumNoCallback;
+ return true;
+}
+
static bool setRetDoesNotAlias(Function &F) {
if (F.hasRetAttribute(Attribute::NoAlias))
return false;
@@ -322,6 +331,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_wcslen:
Changed |= setOnlyReadsMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
@@ -331,6 +341,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
break;
case LibFunc_strtol:
@@ -341,6 +352,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_strtold:
case LibFunc_strtoull:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 1);
Changed |= setOnlyReadsMemory(F, 0);
@@ -349,6 +361,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_strncat:
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setReturnedArg(F, 0);
Changed |= setDoesNotCapture(F, 1);
@@ -364,6 +377,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_stpncpy:
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 1);
Changed |= setOnlyWritesMemory(F, 0);
@@ -373,6 +387,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_strxfrm:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
Changed |= setDoesNotCapture(F, 1);
@@ -383,6 +398,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_strncmp: // 0,1
case LibFunc_strcspn: // 0,1
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setOnlyReadsMemory(F);
@@ -396,6 +412,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
// global memory.
Changed |= setOnlyReadsMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
Changed |= setDoesNotCapture(F, 1);
@@ -405,12 +422,14 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 1);
break;
case LibFunc_strtok:
case LibFunc_strtok_r:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 1);
Changed |= setOnlyReadsMemory(F, 1);
@@ -509,6 +528,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
Changed |= setDoesNotCapture(F, 1);
@@ -516,6 +536,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_memchr:
case LibFunc_memrchr:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setWillReturn(F);
@@ -524,6 +545,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_modff:
case LibFunc_modfl:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyWritesMemory(F);
@@ -531,6 +553,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_memcpy:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotAlias(F, 0);
@@ -542,6 +565,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_memmove:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setReturnedArg(F, 0);
@@ -555,6 +579,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
[[fallthrough]];
case LibFunc_memcpy_chk:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setDoesNotAlias(F, 0);
Changed |= setOnlyWritesMemory(F, 0);
@@ -657,6 +682,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_bcopy:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
@@ -666,6 +692,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_bcmp:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setWillReturn(F);
@@ -674,6 +701,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_bzero:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
@@ -710,6 +738,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_atof:
case LibFunc_atoll:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setOnlyReadsMemory(F);
Changed |= setWillReturn(F);
Changed |= setDoesNotCapture(F, 0);
@@ -787,6 +816,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_frexpf:
case LibFunc_frexpl:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setWillReturn(F);
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyWritesMemory(F);
@@ -1025,6 +1055,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_ntohl:
case LibFunc_ntohs:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setDoesNotAccessMemory(F);
break;
case LibFunc_lstat:
@@ -1041,7 +1072,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyReadsMemory(F, 0);
break;
case LibFunc_qsort:
- // May throw; places call through function pointer.
+ // May throw/callback; places call through function pointer.
// Cannot give undef pointer/size
Changed |= setRetAndArgsNoUndef(F);
Changed |= setDoesNotCapture(F, 3);
@@ -1058,6 +1089,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
break;
case LibFunc_dunder_strtok_r:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setDoesNotCapture(F, 1);
Changed |= setOnlyReadsMemory(F, 1);
break;
@@ -1149,6 +1181,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyAccessesArgMemory(F);
Changed |= setOnlyWritesMemory(F, 0);
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
break;
case LibFunc_abort:
Changed |= setIsCold(F);
@@ -1156,6 +1189,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setDoesNotThrow(F);
break;
case LibFunc_terminate:
+ // May callback; terminate_handler may be called
Changed |= setIsCold(F);
Changed |= setNoReturn(F);
break;
@@ -1284,6 +1318,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_tanhl:
case LibFunc_tanl:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setDoesNotFreeMemory(F);
Changed |= setWillReturn(F);
Changed |= setOnlyWritesErrnoMemory(F);
@@ -1327,6 +1362,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_isascii:
case LibFunc_isdigit:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setDoesNotFreeMemory(F);
Changed |= setWillReturn(F);
break;
@@ -1340,6 +1376,7 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
case LibFunc_remquof:
case LibFunc_remquol:
Changed |= setDoesNotThrow(F);
+ Changed |= setDoesNotCallback(F);
Changed |= setDoesNotFreeMemory(F);
Changed |= setOnlyWritesMemory(F, 2);
Changed |= setDoesNotCapture(F, 2);