forked from OSchip/llvm-project
[InstCombine] Simplify calls with "returned" attribute
If a call argument has the "returned" attribute, we can simplify the call to the value of that argument. This was already partially handled by InstSimplify/InstCombine for the case where the argument is an integer constant, and the result is thus known via known bits. The non-constant (or non-int) argument cases weren't handled though. This previously landed as an InstSimplify transform, but was reverted due to assertion failures when compiling the Linux kernel. The reason is that simplifying a call to another call breaks assumptions in call graph updating during inlining. As the code is not easy to fix, and there is no particularly strong motivation for having this in InstSimplify, the transform is only performed in InstCombine instead. Differential Revision: https://reviews.llvm.org/D75815
This commit is contained in:
parent
9cf920e64d
commit
0372768776
|
@ -4566,6 +4566,10 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) {
|
|||
if (I) return eraseInstFromFunction(*I);
|
||||
}
|
||||
|
||||
if (!Call.use_empty() && !Call.isMustTailCall())
|
||||
if (Value *ReturnedArg = Call.getReturnedArgOperand())
|
||||
return replaceInstUsesWith(Call, ReturnedArg);
|
||||
|
||||
if (isAllocLikeFn(&Call, &TLI))
|
||||
return visitAllocSite(Call);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ define i32 @foo2(i32* align 32 %a) #0 {
|
|||
; CHECK-LABEL: @foo2(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[V:%.*]] = call i32* @func1(i32* [[A:%.*]])
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[V]], align 32
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 32
|
||||
; CHECK-NEXT: ret i32 [[TMP0]]
|
||||
;
|
||||
entry:
|
||||
|
|
|
@ -17,7 +17,7 @@ define i32 @returned_const_int_arg() {
|
|||
define i8* @returned_const_ptr_arg() {
|
||||
; CHECK-LABEL: @returned_const_ptr_arg(
|
||||
; CHECK-NEXT: [[X:%.*]] = call i8* @passthru_p8(i8* null)
|
||||
; CHECK-NEXT: ret i8* [[X]]
|
||||
; CHECK-NEXT: ret i8* null
|
||||
;
|
||||
%x = call i8* @passthru_p8(i8* null)
|
||||
ret i8* %x
|
||||
|
@ -26,7 +26,7 @@ define i8* @returned_const_ptr_arg() {
|
|||
define i32 @returned_var_arg(i32 %arg) {
|
||||
; CHECK-LABEL: @returned_var_arg(
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @passthru_i32(i32 [[ARG:%.*]])
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
; CHECK-NEXT: ret i32 [[ARG]]
|
||||
;
|
||||
%x = call i32 @passthru_i32(i32 %arg)
|
||||
ret i32 %x
|
||||
|
|
|
@ -16,7 +16,7 @@ define void @test() {
|
|||
;
|
||||
; EXPENSIVE-OFF-LABEL: @test(
|
||||
; EXPENSIVE-OFF-NEXT: [[CALL:%.*]] = call i32 @passthru(i32 0)
|
||||
; EXPENSIVE-OFF-NEXT: call void @sink(i32 [[CALL]])
|
||||
; EXPENSIVE-OFF-NEXT: call void @sink(i32 0)
|
||||
; EXPENSIVE-OFF-NEXT: ret void
|
||||
;
|
||||
%call = call i32 @passthru(i32 0)
|
||||
|
|
|
@ -82,7 +82,7 @@ define i32 @test_not_sprintf() {
|
|||
define i8* @test_strcat() {
|
||||
; CHECK-LABEL: @test_strcat(
|
||||
; CHECK-NEXT: [[STRCAT:%.*]] = call i8* @strcat(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0))
|
||||
; CHECK-NEXT: ret i8* [[STRCAT]]
|
||||
; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0)
|
||||
;
|
||||
%dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
|
||||
|
@ -126,7 +126,7 @@ define i64 @test_not_strlcat() {
|
|||
define i8* @test_strncat() {
|
||||
; CHECK-LABEL: @test_strncat(
|
||||
; CHECK-NEXT: [[STRNCAT:%.*]] = call i8* @strncat(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i64 0, i64 0), i64 22)
|
||||
; CHECK-NEXT: ret i8* [[STRNCAT]]
|
||||
; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i64 0, i64 0)
|
||||
;
|
||||
%dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
|
||||
|
|
|
@ -53,7 +53,7 @@ define i8* @test_simplify3() {
|
|||
define i8* @test_simplify4() {
|
||||
; CHECK-LABEL: @test_simplify4(
|
||||
; CHECK-NEXT: [[STRCPY:%.*]] = call i8* @strcpy(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0))
|
||||
; CHECK-NEXT: ret i8* [[STRCPY]]
|
||||
; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
|
||||
;
|
||||
%dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
|
||||
|
|
|
@ -39,7 +39,7 @@ define i8* @test_simplify2() {
|
|||
define i8* @test_simplify3() {
|
||||
; CHECK-LABEL: @test_simplify3(
|
||||
; CHECK-NEXT: [[STRNCPY:%.*]] = call i8* @strncpy(i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0), i8* nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @b, i32 0, i32 0), i32 12)
|
||||
; CHECK-NEXT: ret i8* [[STRNCPY]]
|
||||
; CHECK-NEXT: ret i8* getelementptr inbounds ([60 x i8], [60 x i8]* @a, i32 0, i32 0)
|
||||
;
|
||||
%dst = getelementptr inbounds [60 x i8], [60 x i8]* @a, i32 0, i32 0
|
||||
%src = getelementptr inbounds [60 x i8], [60 x i8]* @b, i32 0, i32 0
|
||||
|
|
|
@ -12,13 +12,8 @@ define i32 @main(i32 %argc, i8** %argv) #0 {
|
|||
; CHECK-SAME: (i32 [[ARGC:%.*]], i8** nocapture readnone [[ARGV:%.*]]) local_unnamed_addr #0
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[ARGC]], 2
|
||||
; CHECK-NEXT: br i1 [[TMP0]], label [[DONE:%.*]], label [[DO_WORK:%.*]]
|
||||
; CHECK: do_work:
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @compute(i8* undef, i32 [[ARGC]])
|
||||
; CHECK-NEXT: br label [[DONE]]
|
||||
; CHECK: done:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP1]], [[DO_WORK]] ]
|
||||
; CHECK-NEXT: ret i32 [[RETVAL]]
|
||||
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TMP0]], i32 0, i32 [[ARGC]]
|
||||
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
|
||||
;
|
||||
entry:
|
||||
%0 = getelementptr inbounds i8*, i8** %argv, i32 0
|
||||
|
|
|
@ -978,6 +978,10 @@ define <2 x double> @negated_mag_arg_vec(<2 x double> %x) {
|
|||
ret <2 x double> %r
|
||||
}
|
||||
|
||||
; We handle the "returned" attribute only in InstCombine, because the fact
|
||||
; that this simplification may replace one call with another may cause issues
|
||||
; for call graph passes.
|
||||
|
||||
declare i32 @passthru_i32(i32 returned)
|
||||
declare i8* @passthru_p8(i8* returned)
|
||||
|
||||
|
|
Loading…
Reference in New Issue