[llvm] 167ea67 - [IR] Ignore bitcasts of function pointers which are only used as callees in callbase instruction
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 6 02:24:01 PDT 2021
Author: madhur13490
Date: 2021-04-06T09:23:46Z
New Revision: 167ea67d76c297eb5dd3fa5f4ffc3c85e1842faa
URL: https://github.com/llvm/llvm-project/commit/167ea67d76c297eb5dd3fa5f4ffc3c85e1842faa
DIFF: https://github.com/llvm/llvm-project/commit/167ea67d76c297eb5dd3fa5f4ffc3c85e1842faa.diff
LOG: [IR] Ignore bitcasts of function pointers which are only used as callees in callbase instruction
This patch enhances hasAddressTaken() to ignore bitcasts as a
callee in callbase instruction. Such bitcast usage doesn't really take
the address in a useful meaningful way.
Reviewed By: rampitec
Differential Revision: https://reviews.llvm.org/D98884
Added:
llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll
llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll
llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll
llvm/test/Analysis/CallGraph/ignore-bitcast-callees2.ll
llvm/test/Transforms/GlobalOpt/assumelike-bitcast-fastcc.ll
llvm/test/Transforms/GlobalOpt/bitcast-call-argument-fastcc.ll
llvm/test/Transforms/GlobalOpt/bitcast-callees-fastcc.ll
llvm/test/Transforms/GlobalOpt/blockaddr-bitcast-fastcc.ll
Modified:
llvm/lib/IR/Function.cpp
llvm/lib/Transforms/IPO/GlobalOpt.cpp
llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll
llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll
llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
llvm/test/Transforms/SCCP/arg-count-mismatch.ll
llvm/test/Transforms/SCCP/arg-type-mismatch.ll
Removed:
################################################################################
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 1001607403d2..f759771cbdfd 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -1637,6 +1637,14 @@ bool Function::hasAddressTaken(const User **PutOffender,
continue;
}
+ if (isa<BitCastOperator>(FU) && isa<ConstantExpr>(FU) &&
+ llvm::all_of(FU->uses(), [](const Use &U) {
+ if (const CallBase *CB = dyn_cast<CallBase>(U.getUser()))
+ return CB->isCallee(&U);
+ return false;
+ }))
+ continue;
+
const auto *Call = dyn_cast<CallBase>(FU);
if (!Call) {
if (IgnoreAssumeLikeCalls) {
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index f275f371c77a..356bb17d5077 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -2131,13 +2131,26 @@ processGlobal(GlobalValue &GV,
return processInternalGlobal(GVar, GS, GetTLI, LookupDomTree) || Changed;
}
+static void SetCallBaseFastCallingConv(Use &U) {
+ CallBase *CB = dyn_cast<CallBase>(U.getUser());
+ if (!CB || !CB->isCallee(&U))
+ return;
+ CB->setCallingConv(CallingConv::Fast);
+}
+
/// Walk all of the direct calls of the specified function, changing them to
/// FastCC.
static void ChangeCalleesToFastCall(Function *F) {
- for (User *U : F->users()) {
- if (isa<BlockAddress>(U))
+ for (Use &U : F->uses()) {
+ User *FU = U.getUser();
+ if (isa<BlockAddress>(FU))
+ continue;
+ if (isa<BitCastOperator>(FU) && isa<ConstantExpr>(FU)) {
+ for (Use &BU : FU->uses())
+ SetCallBaseFastCallingConv(BU);
continue;
- cast<CallBase>(U)->setCallingConv(CallingConv::Fast);
+ }
+ SetCallBaseFastCallingConv(U);
}
}
@@ -2149,13 +2162,25 @@ static AttributeList StripAttr(LLVMContext &C, AttributeList Attrs,
return Attrs;
}
+static void SetCallBaseAttributes(Use &U, Function *F, Attribute::AttrKind A) {
+ CallBase *CB = dyn_cast<CallBase>(U.getUser());
+ if (!CB || !CB->isCallee(&U))
+ return;
+ CB->setAttributes(StripAttr(F->getContext(), CB->getAttributes(), A));
+}
+
static void RemoveAttribute(Function *F, Attribute::AttrKind A) {
F->setAttributes(StripAttr(F->getContext(), F->getAttributes(), A));
- for (User *U : F->users()) {
- if (isa<BlockAddress>(U))
+ for (Use &U : F->uses()) {
+ User *FU = U.getUser();
+ if (isa<BlockAddress>(FU))
+ continue;
+ if (isa<BitCastOperator>(FU) && isa<ConstantExpr>(FU)) {
+ for (Use &BU : FU->uses())
+ SetCallBaseAttributes(BU, F, A);
continue;
- CallBase *CB = cast<CallBase>(U);
- CB->setAttributes(StripAttr(F->getContext(), CB->getAttributes(), A));
+ }
+ SetCallBaseAttributes(U, F, A);
}
}
diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll
new file mode 100644
index 000000000000..7e8002051eea
--- /dev/null
+++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument-callee.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
+
+; CHECK: Call graph node <<null function>><<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<None> calls function 'foo'
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'bar'<<{{.*}}>> #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'test'<<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<{{.*}}> calls function 'bar'
+; CHECK-NEXT: CS<{{.*}}> calls external node
+
+define internal i32 @foo() {
+entry:
+ ret i32 5
+}
+
+define internal i32 @bar(float()* %arg) {
+ ret i32 5
+}
+
+define internal i32 @test() {
+ %v1 = call i32 @bar(float()* bitcast (i32()* @foo to float()*))
+ %v2 = call float bitcast (i32()* @foo to float()*)()
+ %v3 = fptoui float %v2 to i32
+ %v4 = add i32 %v1, %v3
+ ret i32 %v4
+}
+
diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll
new file mode 100644
index 000000000000..8a47dec6410a
--- /dev/null
+++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-call-argument.ll
@@ -0,0 +1,27 @@
+; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
+
+; CHECK: Call graph node <<null function>><<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<None> calls function 'foo'
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'bar'<<{{.*}}>> #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'test'<<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<{{.*}}> calls function 'bar'
+
+define internal i32 @foo() {
+entry:
+ ret i32 5
+}
+
+define internal i32 @bar(float()* %arg) {
+ ret i32 5
+}
+
+define internal i32 @test() {
+ %v1 = call i32 @bar(float()* bitcast (i32()* @foo to float()*))
+ %v2 = add i32 %v1, 6
+ ret i32 %v2
+}
+
diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll
new file mode 100644
index 000000000000..1d62586645a7
--- /dev/null
+++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees.ll
@@ -0,0 +1,23 @@
+; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
+; CHECK: Call graph node <<null function>><<{{.*}}>> #uses=0
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=0
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'test_bitcast_callees'<<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<{{.*}}> calls external node
+; CHECK-NEXT: CS<{{.*}}> calls external node
+
+define internal i32 @foo() {
+entry:
+ ret i32 5
+}
+
+define internal float @test_bitcast_callees() {
+ %v1 = call float bitcast (i32()* @foo to float()*)()
+ %v2 = fadd float %v1, 1.0
+ %v3 = call i8 bitcast (i32()* @foo to i8()*)()
+ %v4 = uitofp i8 %v3 to float
+ %v5 = fadd float %v2, %v4
+ ret float %v5
+}
+
diff --git a/llvm/test/Analysis/CallGraph/ignore-bitcast-callees2.ll b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees2.ll
new file mode 100644
index 000000000000..91899be1afb3
--- /dev/null
+++ b/llvm/test/Analysis/CallGraph/ignore-bitcast-callees2.ll
@@ -0,0 +1,26 @@
+; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
+; CHECK: Call graph node <<null function>><<{{.*}}>> #uses=0
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'foo'<<{{.*}}>> #uses=0
+; CHECK-EMPTY:
+; CHECK-NEXT: Call graph node for function: 'test_bitcast_callees2'<<{{.*}}>> #uses=0
+; CHECK-NEXT: CS<{{.*}}> calls external node
+; CHECK-NEXT: CS<{{.*}}> calls external node
+; CHECK-NEXT: CS<{{.*}}> calls external node
+
+define internal i32 @foo() {
+entry:
+ ret i32 5
+}
+
+define internal float @test_bitcast_callees2() {
+ %v1 = call float bitcast (i32()* @foo to float()*)()
+ %v2 = fadd float %v1, 1.0
+ %v3 = call float bitcast (i32()* @foo to float()*)()
+ %v4 = fadd float %v3, %v2
+ %v5 = call i8 bitcast (i32()* @foo to i8()*)()
+ %v6 = uitofp i8 %v5 to float
+ %v7 = fadd float %v4, %v6
+ ret float %v7
+}
+
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll
index 0965b9868856..3c53872760c9 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll
@@ -36,10 +36,15 @@
; FIXME we should recognize this as UB and make it an unreachable.
define dso_local i16 @foo(i16 %a) {
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@foo
-; NOT_CGSCC_NPM-SAME: (i16 [[A:%.*]]) {
-; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i16 @bar()
-; NOT_CGSCC_NPM-NEXT: ret i16 [[CALL]]
+; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
+; IS__TUNIT____-SAME: (i16 [[A:%.*]]) {
+; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i16 @bar()
+; IS__TUNIT____-NEXT: ret i16 [[CALL]]
+;
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@foo
+; IS__CGSCC_OPM-SAME: (i16 [[A:%.*]]) {
+; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16)*)(i16 [[A]])
+; IS__CGSCC_OPM-NEXT: ret i16 [[CALL]]
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo
@@ -56,9 +61,8 @@ define internal i16 @bar(i16 %p1, i16 %p2) {
; IS__TUNIT____-SAME: () #[[ATTR0:[0-9]+]] {
; IS__TUNIT____-NEXT: ret i16 0
;
-; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar
-; IS__CGSCC_OPM-SAME: () #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_OPM-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) {
; IS__CGSCC_OPM-NEXT: ret i16 0
;
; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
@@ -86,11 +90,16 @@ define internal i16 @bar2(i16 %p1, i16 %p2) {
; IS__TUNIT____-NEXT: [[A:%.*]] = add i16 [[P1]], [[P2]]
; IS__TUNIT____-NEXT: ret i16 [[A]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@bar2
-; IS__CGSCC____-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) #[[ATTR0:[0-9]+]] {
-; IS__CGSCC____-NEXT: [[A:%.*]] = add i16 [[P1]], [[P2]]
-; IS__CGSCC____-NEXT: ret i16 [[A]]
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar2
+; IS__CGSCC_OPM-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) {
+; IS__CGSCC_OPM-NEXT: [[A:%.*]] = add i16 [[P1]], [[P2]]
+; IS__CGSCC_OPM-NEXT: ret i16 [[A]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@bar2
+; IS__CGSCC_NPM-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) #[[ATTR0]] {
+; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i16 [[P1]], [[P2]]
+; IS__CGSCC_NPM-NEXT: ret i16 [[A]]
;
%a = add i16 %p1, %p2
ret i16 %a
@@ -103,11 +112,17 @@ define internal i16 @bar2(i16 %p1, i16 %p2) {
; been provided),
define dso_local i16 @vararg_tests(i16 %a) {
-; CHECK-LABEL: define {{[^@]+}}@vararg_tests
-; CHECK-SAME: (i16 [[A:%.*]]) {
-; CHECK-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 noundef 7)
-; CHECK-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
-; CHECK-NEXT: ret i16 [[ADD]]
+; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@vararg_tests
+; NOT_CGSCC_OPM-SAME: (i16 [[A:%.*]]) {
+; NOT_CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 noundef 7)
+; NOT_CGSCC_OPM-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
+; NOT_CGSCC_OPM-NEXT: ret i16 [[ADD]]
+;
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@vararg_tests
+; IS__CGSCC_OPM-SAME: (i16 [[A:%.*]]) {
+; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
+; IS__CGSCC_OPM-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
+; IS__CGSCC_OPM-NEXT: ret i16 [[ADD]]
;
%call1 = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 %a)
%call2 = call i16 bitcast (i16 (i16, i16, ...) * @vararg_no_prop to i16 (i16) *) (i16 7)
@@ -118,7 +133,7 @@ define dso_local i16 @vararg_tests(i16 %a) {
define internal i16 @vararg_prop(i16 %p1, ...) {
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@vararg_prop
-; IS__CGSCC____-SAME: (i16 returned [[P1:%.*]], ...) #[[ATTR0]] {
+; IS__CGSCC____-SAME: (i16 returned [[P1:%.*]], ...) #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-NEXT: ret i16 7
;
ret i16 %p1
@@ -130,10 +145,14 @@ define internal i16 @vararg_no_prop(i16 %p1, i16 %p2, ...) {
; IS__TUNIT____-SAME: (i16 returned [[P1:%.*]], i16 [[P2:%.*]], ...) #[[ATTR0]] {
; IS__TUNIT____-NEXT: ret i16 7
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@vararg_no_prop
-; IS__CGSCC____-SAME: (i16 returned [[P1:%.*]], i16 [[P2:%.*]], ...) #[[ATTR0]] {
-; IS__CGSCC____-NEXT: ret i16 7
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@vararg_no_prop
+; IS__CGSCC_OPM-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]], ...) {
+; IS__CGSCC_OPM-NEXT: ret i16 [[P1]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@vararg_no_prop
+; IS__CGSCC_NPM-SAME: (i16 returned [[P1:%.*]], i16 [[P2:%.*]], ...) #[[ATTR0]] {
+; IS__CGSCC_NPM-NEXT: ret i16 7
;
ret i16 %p1
}
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll
index 3bbd2534c439..6d701ee84c0b 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll
@@ -23,10 +23,14 @@ define internal i16 @bar(i16 %p1, i16 %p2) {
; IS__TUNIT____-SAME: (i16 [[P1:%.*]], i16 returned [[P2:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__TUNIT____-NEXT: ret i16 [[P2]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@bar
-; IS__CGSCC____-SAME: (i16 [[P1:%.*]], i16 returned [[P2:%.*]]) #[[ATTR0:[0-9]+]] {
-; IS__CGSCC____-NEXT: ret i16 [[P2]]
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar
+; IS__CGSCC_OPM-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) {
+; IS__CGSCC_OPM-NEXT: ret i16 [[P2]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@bar
+; IS__CGSCC_NPM-SAME: (i16 [[P1:%.*]], i16 returned [[P2:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT: ret i16 [[P2]]
;
ret i16 %p2
}
@@ -35,5 +39,5 @@ define internal i16 @bar(i16 %p1, i16 %p2) {
;.
; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
;.
-; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
+; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
;.
diff --git a/llvm/test/Transforms/GlobalOpt/assumelike-bitcast-fastcc.ll b/llvm/test/Transforms/GlobalOpt/assumelike-bitcast-fastcc.ll
new file mode 100644
index 000000000000..4b60a6da4927
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/assumelike-bitcast-fastcc.ll
@@ -0,0 +1,27 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+; Check that fastccc is not set on
+; function "bar" because its address is taken
+; when no optional parameters are passed to
+; hasAddressTaken() as it returns "true"
+; If the optional parameter corresponding to
+; ignore llvmassumelike is passed to
+; hasAddressTaken() then this test would fail.
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+
+; CHECK-NOT: define internal fastcc void @bar() {
+; CHECK: define internal void @bar() {
+define internal void @bar() {
+entry:
+ ret void
+}
+
+; CHECK: define void @foo() local_unnamed_addr {
+define void @foo() {
+entry:
+ %c = bitcast void()* @bar to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %c)
+ ret void
+}
+
diff --git a/llvm/test/Transforms/GlobalOpt/bitcast-call-argument-fastcc.ll b/llvm/test/Transforms/GlobalOpt/bitcast-call-argument-fastcc.ll
new file mode 100644
index 000000000000..4679594d17b7
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/bitcast-call-argument-fastcc.ll
@@ -0,0 +1,29 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+; Check that globalopt doesn't set fastcc on
+; functions and their call sites if its hasAddressTaken()
+; is true. "foo" function's hasAddressTaken() is
+; true so globalopt should not set fastcc on it
+; and its call sites. However, for "bar" fastcc must be set.
+
+; CHECK-NOT: define internal fastcc i32 @foo() {
+; CHECK: define internal i32 @foo() {
+define internal i32 @foo() {
+entry:
+ ret i32 5
+}
+
+; CHECK: define internal fastcc i32 @bar(float ()* %arg) unnamed_addr {
+define internal i32 @bar(float()* %arg) {
+ ret i32 5
+}
+
+; CHECK-NOT: define fastcc i32 @test()
+; CHECK: define i32 @test()
+define i32 @test() {
+ ; CHECK: call fastcc i32 @bar(float ()* bitcast (i32 ()* @foo to float ()*))
+ %v1 = call i32 @bar(float ()* bitcast (i32 ()* @foo to float ()*))
+ %v2 = add i32 %v1, 6
+ ret i32 %v2
+}
+
diff --git a/llvm/test/Transforms/GlobalOpt/bitcast-callees-fastcc.ll b/llvm/test/Transforms/GlobalOpt/bitcast-callees-fastcc.ll
new file mode 100644
index 000000000000..79b2eae5d2c6
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/bitcast-callees-fastcc.ll
@@ -0,0 +1,18 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+; CHECK-LABEL: define internal fastcc i32 @foo() unnamed_addr
+define internal i32 @foo() {
+ ret i32 8
+}
+
+; CHECK-LABEL: define void @test_bitcast_callees2() local_unnamed_addr {
+define void @test_bitcast_callees2() {
+ ; CHECK: %1 = call fastcc float bitcast (i32 ()* @foo to float ()*)()
+ call float bitcast (i32()* @foo to float()*)()
+ ; CHECK-NEXT: %2 = call fastcc float bitcast (i32 ()* @foo to float ()*)()
+ call float bitcast (i32()* @foo to float()*)()
+ ; CHECK-NEXT: %3 = call fastcc i8 bitcast (i32 ()* @foo to i8 ()*)()
+ call i8 bitcast (i32()* @foo to i8()*)()
+ ret void
+}
+
diff --git a/llvm/test/Transforms/GlobalOpt/blockaddr-bitcast-fastcc.ll b/llvm/test/Transforms/GlobalOpt/blockaddr-bitcast-fastcc.ll
new file mode 100644
index 000000000000..f5cbf5336306
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/blockaddr-bitcast-fastcc.ll
@@ -0,0 +1,24 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+; Check if fastcc is set on function "g"
+; as its address is not taken and other
+; conditions are met to tag "g" as fastcc.
+
+ at x = internal global i8* zeroinitializer
+
+; CHECK: define internal fastcc void @g() unnamed_addr {
+define internal void @g() {
+entry:
+ br label %here
+
+here:
+ ret void
+}
+
+define void @f() {
+ store i8* blockaddress(@g, %here), i8** @x, align 8
+; CHECK: call fastcc i32 bitcast (void ()* @g to i32 ()*)()
+ call i32 bitcast (void ()* @g to i32 ()*)()
+ ret void
+}
+
diff --git a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
index 09f3d16da526..17022b7cc84d 100644
--- a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
+++ b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
@@ -2,14 +2,13 @@
; CHECK: Call graph node <<null function>><<{{.*}}>> #uses=0
; CHECK: CS<None> calls function 'dead_fork_call'
-; CHECK: CS<None> calls function '.omp_outlined..0'
; CHECK: CS<None> calls function '__kmpc_fork_call'
; CHECK: CS<None> calls function 'live_fork_call'
; CHECK: CS<None> calls function '.omp_outlined..1'
; CHECK: CS<None> calls function 'd'
;
-; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>> #uses=1
-;
+; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>> #uses=0
+;
; CHECK: Call graph node for function: '.omp_outlined..1'<<{{.*}}>> #uses=3
; CHECK: CS<{{.*}}> calls function 'd'
;
diff --git a/llvm/test/Transforms/SCCP/arg-count-mismatch.ll b/llvm/test/Transforms/SCCP/arg-count-mismatch.ll
index ba5f1a6d83f7..a82de0cf0f5e 100644
--- a/llvm/test/Transforms/SCCP/arg-count-mismatch.ll
+++ b/llvm/test/Transforms/SCCP/arg-count-mismatch.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt < %s -ipsccp -S -o - | FileCheck %s
; The original C source looked like this:
@@ -31,8 +31,9 @@
; argument count between the caller and callee.
define dso_local void @foo(i16 %a) {
-; CHECK-LABEL: @foo(
-; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16)*)(i16 [[A:%.*]])
+; CHECK-LABEL: define {{[^@]+}}@foo
+; CHECK-SAME: (i16 [[A:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16)*)(i16 [[A]])
; CHECK-NEXT: ret void
;
%call = call i16 bitcast (i16 (i16, i16) * @bar to i16 (i16) *)(i16 %a)
@@ -40,8 +41,9 @@ define dso_local void @foo(i16 %a) {
}
define internal i16 @bar(i16 %p1, i16 %p2) {
-; CHECK-LABEL: @bar(
-; CHECK-NEXT: ret i16 0
+; CHECK-LABEL: define {{[^@]+}}@bar
+; CHECK-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) {
+; CHECK-NEXT: unreachable
;
ret i16 0
}
@@ -52,15 +54,17 @@ define internal i16 @bar(i16 %p1, i16 %p2) {
; been provided),
define internal i16 @vararg_prop(i16 %p1, ...) {
-; CHECK-LABEL: @vararg_prop(
+; CHECK-LABEL: define {{[^@]+}}@vararg_prop
+; CHECK-SAME: (i16 [[P1:%.*]], ...) {
; CHECK-NEXT: ret i16 undef
;
ret i16 %p1
}
define dso_local i16 @vararg_tests(i16 %a) {
-; CHECK-LABEL: @vararg_tests(
-; CHECK-NEXT: [[CALL1:%.*]] = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 [[A:%.*]])
+; CHECK-LABEL: define {{[^@]+}}@vararg_tests
+; CHECK-SAME: (i16 [[A:%.*]]) {
+; CHECK-NEXT: [[CALL1:%.*]] = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 [[A]])
; CHECK-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
; CHECK-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
; CHECK-NEXT: ret i16 [[ADD]]
@@ -72,8 +76,9 @@ define dso_local i16 @vararg_tests(i16 %a) {
}
define internal i16 @vararg_no_prop(i16 %p1, i16 %p2, ...) {
-; CHECK-LABEL: @vararg_no_prop(
-; CHECK-NEXT: ret i16 [[P1:%.*]]
+; CHECK-LABEL: define {{[^@]+}}@vararg_no_prop
+; CHECK-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]], ...) {
+; CHECK-NEXT: unreachable
;
ret i16 %p1
}
diff --git a/llvm/test/Transforms/SCCP/arg-type-mismatch.ll b/llvm/test/Transforms/SCCP/arg-type-mismatch.ll
index 9a9da52174c2..17dd105ad882 100644
--- a/llvm/test/Transforms/SCCP/arg-type-mismatch.ll
+++ b/llvm/test/Transforms/SCCP/arg-type-mismatch.ll
@@ -1,12 +1,13 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt < %s -ipsccp -S -o - | FileCheck %s
; This test is just to verify that we do not crash/assert due to mismatch in
; argument type between the caller and callee.
define dso_local void @foo(i16 %a) {
-; CHECK-LABEL: @foo(
-; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16, i32)*)(i16 [[A:%.*]], i32 7)
+; CHECK-LABEL: define {{[^@]+}}@foo
+; CHECK-SAME: (i16 [[A:%.*]]) {
+; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16, i32)*)(i16 [[A]], i32 7)
; CHECK-NEXT: ret void
;
%call = call i16 bitcast (i16 (i16, i16) * @bar to i16 (i16, i32) *)(i16 %a, i32 7)
@@ -14,8 +15,9 @@ define dso_local void @foo(i16 %a) {
}
define internal i16 @bar(i16 %p1, i16 %p2) {
-; CHECK-LABEL: @bar(
-; CHECK-NEXT: ret i16 [[P2:%.*]]
+; CHECK-LABEL: define {{[^@]+}}@bar
+; CHECK-SAME: (i16 [[P1:%.*]], i16 [[P2:%.*]]) {
+; CHECK-NEXT: unreachable
;
ret i16 %p2
}
More information about the llvm-commits
mailing list