-; RUN: opt < %s -argpromotion -S > %t
-; RUN: cat %t | grep "define.*@callee(.*i32\*"
+; RUN: opt < %s -argpromotion -S | FileCheck %s
; PR2498
; This test tries to convince argpromotion about promoting the load from %A + 2,
; because there is a load of %A in the entry block
define internal i32 @callee(i1 %C, i32* %A) {
+; CHECK-LABEL: define internal i32 @callee(
+; CHECK: i1 %C, i32* %A)
entry:
- ; Unconditonally load the element at %A
- %A.0 = load i32, i32* %A
- br i1 %C, label %T, label %F
+ ; Unconditonally load the element at %A
+ %A.0 = load i32, i32* %A
+ br i1 %C, label %T, label %F
+
T:
- ret i32 %A.0
+ ret i32 %A.0
+
F:
- ; Load the element at offset two from %A. This should not be promoted!
- %A.2 = getelementptr i32, i32* %A, i32 2
- %R = load i32, i32* %A.2
- ret i32 %R
+ ; Load the element at offset two from %A. This should not be promoted!
+ %A.2 = getelementptr i32, i32* %A, i32 2
+ %R = load i32, i32* %A.2
+ ret i32 %R
}
define i32 @foo() {
+; CHECK-LABEL: define i32 @foo
%X = call i32 @callee(i1 false, i32* null) ; <i32> [#uses=1]
+; CHECK: call i32 @callee(i1 false, i32* null)
ret i32 %X
}
-; RUN: opt < %s -argpromotion -instcombine -S | not grep load
-target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+; RUN: opt < %s -argpromotion -S | FileCheck %s
-%QuadTy = type { i32, i32, i32, i32 }
-@G = constant %QuadTy {
- i32 0,
- i32 0,
- i32 17,
- i32 25 } ; <%QuadTy*> [#uses=1]
+%T = type { i32, i32, i32, i32 }
+@G = constant %T { i32 0, i32 0, i32 17, i32 25 }
-define internal i32 @test(%QuadTy* %P) {
- %A = getelementptr %QuadTy, %QuadTy* %P, i64 0, i32 3 ; <i32*> [#uses=1]
- %B = getelementptr %QuadTy, %QuadTy* %P, i64 0, i32 2 ; <i32*> [#uses=1]
- %a = load i32, i32* %A ; <i32> [#uses=1]
- %b = load i32, i32* %B ; <i32> [#uses=1]
- %V = add i32 %a, %b ; <i32> [#uses=1]
- ret i32 %V
+define internal i32 @test(%T* %p) {
+; CHECK-LABEL: define internal i32 @test(
+; CHECK: i32 %{{.*}}, i32 %{{.*}})
+entry:
+ %a.gep = getelementptr %T, %T* %p, i64 0, i32 3
+ %b.gep = getelementptr %T, %T* %p, i64 0, i32 2
+ %a = load i32, i32* %a.gep
+ %b = load i32, i32* %b.gep
+; CHECK-NOT: load
+ %v = add i32 %a, %b
+ ret i32 %v
+; CHECK: ret i32
}
define i32 @caller() {
- %V = call i32 @test( %QuadTy* @G ) ; <i32> [#uses=1]
- ret i32 %V
+; CHECK-LABEL: define i32 @caller(
+entry:
+ %v = call i32 @test(%T* @G)
+; CHECK: %[[B_GEP:.*]] = getelementptr %T, %T* @G, i64 0, i32 2
+; CHECK: %[[B:.*]] = load i32, i32* %[[B_GEP]]
+; CHECK: %[[A_GEP:.*]] = getelementptr %T, %T* @G, i64 0, i32 3
+; CHECK: %[[A:.*]] = load i32, i32* %[[A_GEP]]
+; CHECK: call i32 @test(i32 %[[B]], i32 %[[A]])
+ ret i32 %v
}
-
-; RUN: opt < %s -argpromotion -S | grep zeroext
+; RUN: opt < %s -argpromotion -S | FileCheck %s
- %struct.ss = type { i32, i64 }
+%struct.ss = type { i32, i64 }
-define internal void @f(%struct.ss* byval %b, i32* byval %X, i32 %i) nounwind {
+; Don't drop 'byval' on %X here.
+define internal void @f(%struct.ss* byval %b, i32* byval %X, i32 %i) nounwind {
+; CHECK-LABEL: define internal void @f(
+; CHECK: i32 %[[B0:.*]], i64 %[[B1:.*]], i32* byval %X, i32 %i)
entry:
- %tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
- %tmp1 = load i32, i32* %tmp, align 4
- %tmp2 = add i32 %tmp1, 1
- store i32 %tmp2, i32* %tmp, align 4
+; CHECK: %[[B:.*]] = alloca %struct.ss
+; CHECK: %[[B_GEP0:.*]] = getelementptr %struct.ss, %struct.ss* %[[B]], i32 0, i32 0
+; CHECK: store i32 %[[B0]], i32* %[[B_GEP0]]
+; CHECK: %[[B_GEP1:.*]] = getelementptr %struct.ss, %struct.ss* %[[B]], i32 0, i32 1
+; CHECK: store i64 %[[B1]], i64* %[[B_GEP1]]
- store i32 0, i32* %X
- ret void
+ %tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
+; CHECK: %[[TMP:.*]] = getelementptr %struct.ss, %struct.ss* %[[B]], i32 0, i32 0
+ %tmp1 = load i32, i32* %tmp, align 4
+; CHECK: %[[TMP1:.*]] = load i32, i32* %[[TMP]]
+ %tmp2 = add i32 %tmp1, 1
+; CHECK: %[[TMP2:.*]] = add i32 %[[TMP1]], 1
+ store i32 %tmp2, i32* %tmp, align 4
+; CHECK: store i32 %[[TMP2]], i32* %[[TMP]]
+
+ store i32 0, i32* %X
+; CHECK: store i32 0, i32* %X
+ ret void
}
+; Also make sure we don't drop the call zeroext attribute.
define i32 @test(i32* %X) {
+; CHECK-LABEL: define i32 @test(
entry:
- %S = alloca %struct.ss ; <%struct.ss*> [#uses=4]
- %tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0 ; <i32*> [#uses=1]
- store i32 1, i32* %tmp1, align 8
- %tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1 ; <i64*> [#uses=1]
- store i64 2, i64* %tmp4, align 4
- call void @f( %struct.ss* byval %S, i32* byval %X, i32 zeroext 0)
- ret i32 0
+ %S = alloca %struct.ss
+; CHECK: %[[S:.*]] = alloca %struct.ss
+ %tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0
+ store i32 1, i32* %tmp1, align 8
+; CHECK: store i32 1
+ %tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
+ store i64 2, i64* %tmp4, align 4
+; CHECK: store i64 2
+
+ call void @f( %struct.ss* byval %S, i32* byval %X, i32 zeroext 0)
+; CHECK: %[[S_GEP0:.*]] = getelementptr %struct.ss, %struct.ss* %[[S]], i32 0, i32 0
+; CHECK: %[[S0:.*]] = load i32, i32* %[[S_GEP0]]
+; CHECK: %[[S_GEP1:.*]] = getelementptr %struct.ss, %struct.ss* %[[S]], i32 0, i32 1
+; CHECK: %[[S1:.*]] = load i64, i64* %[[S_GEP1]]
+; CHECK: call void @f(i32 %[[S0]], i64 %[[S1]], i32* byval %X, i32 zeroext 0)
+
+ ret i32 0
}
-; RUN: opt < %s -argpromotion -instcombine -S | not grep load
-target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
+; RUN: opt < %s -argpromotion -S | FileCheck %s
-@G1 = constant i32 0 ; <i32*> [#uses=1]
-@G2 = constant i32* @G1 ; <i32**> [#uses=1]
+@G1 = constant i32 0
+@G2 = constant i32* @G1
-define internal i32 @test(i32** %X) {
- %Y = load i32*, i32** %X ; <i32*> [#uses=1]
- %X.upgrd.1 = load i32, i32* %Y ; <i32> [#uses=1]
- ret i32 %X.upgrd.1
+define internal i32 @test(i32** %x) {
+; CHECK-LABEL: define internal i32 @test(
+; CHECK: i32 %{{.*}})
+entry:
+ %y = load i32*, i32** %x
+ %z = load i32, i32* %y
+; CHECK-NOT: load
+ ret i32 %z
+; CHECK: ret i32
}
-define i32 @caller(i32** %P) {
- %X = call i32 @test( i32** @G2 ) ; <i32> [#uses=1]
- ret i32 %X
+define i32 @caller() {
+; CHECK-LABEL: define i32 @caller()
+entry:
+ %x = call i32 @test(i32** @G2)
+; CHECK: %[[Y:.*]] = load i32*, i32** @G2
+; CHECK: %[[Z:.*]] = load i32, i32* %[[Y]]
+; CHECK: call i32 @test(i32 %[[Z]])
+ ret i32 %x
}
; RUN: opt < %s -argpromotion -S | \
; RUN: not grep "load i32* null"
+; Don't promote around control flow.
define internal i32 @callee(i1 %C, i32* %P) {
- br i1 %C, label %T, label %F
+; CHECK-LABEL: define internal i32 @callee(
+; CHECK: i1 %C, i32* %P)
+entry:
+ br i1 %C, label %T, label %F
-T: ; preds = %0
- ret i32 17
+T:
+ ret i32 17
-F: ; preds = %0
- %X = load i32, i32* %P ; <i32> [#uses=1]
- ret i32 %X
+F:
+ %X = load i32, i32* %P
+ ret i32 %X
}
define i32 @foo() {
- %X = call i32 @callee( i1 true, i32* null ) ; <i32> [#uses=1]
- ret i32 %X
+; CHECK-LABEL: define i32 @foo(
+entry:
+; CHECK-NOT: load i32, i32* null
+ %X = call i32 @callee(i1 true, i32* null)
+; CHECK: call i32 @callee(i1 true, i32* null)
+ ret i32 %X
}