diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index d6b4a4f5030f..73d1e0aa622b 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -334,14 +334,26 @@ bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const { } bool CallBase::hasFnAttrOnCalledFunction(Attribute::AttrKind Kind) const { - if (const Function *F = getCalledFunction()) + Value *V = getCalledOperand(); + if (auto *CE = dyn_cast(V)) + if (CE->getOpcode() == BitCast) + V = CE->getOperand(0); + + if (auto *F = dyn_cast(V)) return F->getAttributes().hasFnAttribute(Kind); + return false; } bool CallBase::hasFnAttrOnCalledFunction(StringRef Kind) const { - if (const Function *F = getCalledFunction()) + Value *V = getCalledOperand(); + if (auto *CE = dyn_cast(V)) + if (CE->getOpcode() == BitCast) + V = CE->getOperand(0); + + if (auto *F = dyn_cast(V)) return F->getAttributes().hasFnAttribute(Kind); + return false; } diff --git a/llvm/test/Analysis/MemorySSA/call-bitcast.ll b/llvm/test/Analysis/MemorySSA/call-bitcast.ll new file mode 100644 index 000000000000..c4bfdbee77ad --- /dev/null +++ b/llvm/test/Analysis/MemorySSA/call-bitcast.ll @@ -0,0 +1,14 @@ +; RUN: opt -aa-pipeline=basic-aa -passes='print,verify' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensures that MemorySSA leverages the ground truth of the function being called when wrapped in a bitcast. + +declare i1 @opaque_true(i1) nounwind readonly + +define i1 @foo(i32* %ptr, i1 %cond) { + %cond_wide = zext i1 %cond to i32 +; CHECK: MemoryUse(liveOnEntry) MayAlias +; CHECK-NEXT: call i32 bitcast + %cond_hidden_wide = call i32 bitcast (i1 (i1)* @opaque_true to i32 (i32)*)(i32 %cond_wide) + %cond_hidden = trunc i32 %cond_hidden_wide to i1 + ret i1 %cond_hidden +} diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll index 3bdfbbb36eb1..22d7ce63a658 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll @@ -70,10 +70,16 @@ define internal i16 @bar(i16 %p1, i16 %p2) { } define dso_local i16 @foo2(i16 %a) { -; CHECK-LABEL: define {{[^@]+}}@foo2 -; CHECK-SAME: (i16 [[A:%.*]]) { -; CHECK-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar2 to i16 (i16)*)(i16 [[A]]) -; CHECK-NEXT: ret i16 [[CALL]] +; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@foo2 +; NOT_CGSCC_NPM-SAME: (i16 [[A:%.*]]) { +; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar2 to i16 (i16)*)(i16 [[A]]) +; NOT_CGSCC_NPM-NEXT: ret i16 [[CALL]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo2 +; IS__CGSCC_NPM-SAME: (i16 [[A:%.*]]) [[ATTR1:#.*]] { +; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar2 to i16 (i16)*)(i16 [[A]]) +; IS__CGSCC_NPM-NEXT: ret i16 [[CALL]] ; %call = call i16 bitcast (i16 (i16, i16) * @bar2 to i16 (i16) *)(i16 %a) ret i16 %call @@ -103,11 +109,18 @@ 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_NPM-LABEL: define {{[^@]+}}@vararg_tests +; NOT_CGSCC_NPM-SAME: (i16 [[A:%.*]]) { +; NOT_CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 noundef 7) +; NOT_CGSCC_NPM-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]] +; NOT_CGSCC_NPM-NEXT: ret i16 [[ADD]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@vararg_tests +; IS__CGSCC_NPM-SAME: (i16 [[A:%.*]]) [[ATTR1]] { +; IS__CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 noundef 7) +; IS__CGSCC_NPM-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]] +; IS__CGSCC_NPM-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) diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll index bdbfd20c0518..61b78d95c93a 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll @@ -8,10 +8,16 @@ ; argument type between the caller and callee. define dso_local i16 @foo(i16 %a) { -; 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 i16 [[CALL]] +; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@foo +; NOT_CGSCC_NPM-SAME: (i16 [[A:%.*]]) { +; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16, i32)*)(i16 [[A]], i32 7) +; NOT_CGSCC_NPM-NEXT: ret i16 [[CALL]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo +; IS__CGSCC_NPM-SAME: (i16 [[A:%.*]]) [[ATTR0:#.*]] { +; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i16 bitcast (i16 (i16, i16)* @bar to i16 (i16, i32)*)(i16 [[A]], i32 7) +; IS__CGSCC_NPM-NEXT: ret i16 [[CALL]] ; %call = call i16 bitcast (i16 (i16, i16) * @bar to i16 (i16, i32) *)(i16 %a, i32 7) ret i16 %call @@ -25,7 +31,7 @@ define internal i16 @bar(i16 %p1, 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:#.*]] { +; IS__CGSCC____-SAME: (i16 [[P1:%.*]], i16 returned [[P2:%.*]]) [[ATTR1:#.*]] { ; IS__CGSCC____-NEXT: ret i16 [[P2]] ; ret i16 %p2 diff --git a/llvm/test/Transforms/Attributor/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll index 50c093af962d..5a2f968eadad 100644 --- a/llvm/test/Transforms/Attributor/liveness.ll +++ b/llvm/test/Transforms/Attributor/liveness.ll @@ -2425,33 +2425,59 @@ indirectgoto: ; preds = %lab0, %entry @e = global %struct.a* null define i32 @main() { -; CHECK-LABEL: define {{[^@]+}}@main() { -; CHECK-NEXT: entry: -; CHECK-NEXT: [[F:%.*]] = alloca i32, align 4 -; CHECK-NEXT: br label [[FOR_COND_0:%.*]] -; CHECK: for.cond.0: -; CHECK-NEXT: [[G_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY_0:%.*]] ] -; CHECK-NEXT: [[CMP_0:%.*]] = icmp ult i32 [[G_0]], 100 -; CHECK-NEXT: br i1 [[CMP_0]], label [[FOR_BODY_0]], label [[FOR_END_0:%.*]] -; CHECK: for.body.0: -; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[G_0]], 1 -; CHECK-NEXT: br label [[FOR_COND_0]] -; CHECK: for.end.0: -; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 noundef 8) -; CHECK-NEXT: store i8* [[CALL]], i8** bitcast (%struct.a** @e to i8**), align 8 -; CHECK-NEXT: [[B:%.*]] = bitcast i8* [[CALL]] to %struct.a** -; CHECK-NEXT: store %struct.a* null, %struct.a** [[B]], align 8 -; CHECK-NEXT: br label [[FOR_COND_1:%.*]] -; CHECK: for.cond.1: -; CHECK-NEXT: [[G_1:%.*]] = phi i32 [ 0, [[FOR_END_0]] ], [ [[INC6:%.*]], [[FOR_BODY_1:%.*]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[G_1]], 100 -; CHECK-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_1]], label [[FOR_END_1:%.*]] -; CHECK: for.body.1: -; CHECK-NEXT: [[CALL4:%.*]] = call i32 (i32*, ...) bitcast (i32 (i32)* @h to i32 (i32*, ...)*)(i32* nonnull [[F]]) -; CHECK-NEXT: [[INC6]] = add nuw nsw i32 [[G_1]], 1 -; CHECK-NEXT: br label [[FOR_COND_1]] -; CHECK: for.end.1: -; CHECK-NEXT: ret i32 0 +; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@main() { +; NOT_CGSCC_NPM-NEXT: entry: +; NOT_CGSCC_NPM-NEXT: [[F:%.*]] = alloca i32, align 4 +; NOT_CGSCC_NPM-NEXT: br label [[FOR_COND_0:%.*]] +; NOT_CGSCC_NPM: for.cond.0: +; NOT_CGSCC_NPM-NEXT: [[G_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY_0:%.*]] ] +; NOT_CGSCC_NPM-NEXT: [[CMP_0:%.*]] = icmp ult i32 [[G_0]], 100 +; NOT_CGSCC_NPM-NEXT: br i1 [[CMP_0]], label [[FOR_BODY_0]], label [[FOR_END_0:%.*]] +; NOT_CGSCC_NPM: for.body.0: +; NOT_CGSCC_NPM-NEXT: [[INC]] = add nuw nsw i32 [[G_0]], 1 +; NOT_CGSCC_NPM-NEXT: br label [[FOR_COND_0]] +; NOT_CGSCC_NPM: for.end.0: +; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 noundef 8) +; NOT_CGSCC_NPM-NEXT: store i8* [[CALL]], i8** bitcast (%struct.a** @e to i8**), align 8 +; NOT_CGSCC_NPM-NEXT: [[B:%.*]] = bitcast i8* [[CALL]] to %struct.a** +; NOT_CGSCC_NPM-NEXT: store %struct.a* null, %struct.a** [[B]], align 8 +; NOT_CGSCC_NPM-NEXT: br label [[FOR_COND_1:%.*]] +; NOT_CGSCC_NPM: for.cond.1: +; NOT_CGSCC_NPM-NEXT: [[G_1:%.*]] = phi i32 [ 0, [[FOR_END_0]] ], [ [[INC6:%.*]], [[FOR_BODY_1:%.*]] ] +; NOT_CGSCC_NPM-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[G_1]], 100 +; NOT_CGSCC_NPM-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_1]], label [[FOR_END_1:%.*]] +; NOT_CGSCC_NPM: for.body.1: +; NOT_CGSCC_NPM-NEXT: [[CALL4:%.*]] = call i32 (i32*, ...) bitcast (i32 (i32)* @h to i32 (i32*, ...)*)(i32* nonnull [[F]]) +; NOT_CGSCC_NPM-NEXT: [[INC6]] = add nuw nsw i32 [[G_1]], 1 +; NOT_CGSCC_NPM-NEXT: br label [[FOR_COND_1]] +; NOT_CGSCC_NPM: for.end.1: +; NOT_CGSCC_NPM-NEXT: ret i32 0 +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@main() { +; IS__CGSCC____-NEXT: entry: +; IS__CGSCC____-NEXT: br label [[FOR_COND_0:%.*]] +; IS__CGSCC____: for.cond.0: +; IS__CGSCC____-NEXT: [[G_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY_0:%.*]] ] +; IS__CGSCC____-NEXT: [[CMP_0:%.*]] = icmp ult i32 [[G_0]], 100 +; IS__CGSCC____-NEXT: br i1 [[CMP_0]], label [[FOR_BODY_0]], label [[FOR_END_0:%.*]] +; IS__CGSCC____: for.body.0: +; IS__CGSCC____-NEXT: [[INC]] = add nuw nsw i32 [[G_0]], 1 +; IS__CGSCC____-NEXT: br label [[FOR_COND_0]] +; IS__CGSCC____: for.end.0: +; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 noundef 8) +; IS__CGSCC____-NEXT: store i8* [[CALL]], i8** bitcast (%struct.a** @e to i8**), align 8 +; IS__CGSCC____-NEXT: [[B:%.*]] = bitcast i8* [[CALL]] to %struct.a** +; IS__CGSCC____-NEXT: store %struct.a* null, %struct.a** [[B]], align 8 +; IS__CGSCC____-NEXT: br label [[FOR_COND_1:%.*]] +; IS__CGSCC____: for.cond.1: +; IS__CGSCC____-NEXT: [[G_1:%.*]] = phi i32 [ 0, [[FOR_END_0]] ], [ [[INC6:%.*]], [[FOR_BODY_1:%.*]] ] +; IS__CGSCC____-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[G_1]], 100 +; IS__CGSCC____-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_1]], label [[FOR_END_1:%.*]] +; IS__CGSCC____: for.body.1: +; IS__CGSCC____-NEXT: [[INC6]] = add nuw nsw i32 [[G_1]], 1 +; IS__CGSCC____-NEXT: br label [[FOR_COND_1]] +; IS__CGSCC____: for.end.1: +; IS__CGSCC____-NEXT: ret i32 0 ; entry: %f = alloca i32