mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-23 05:29:23 +00:00
This can only occur (I think) through the back-edge of the loop. However, folding a GEP into itself means that the value of the previous iteration needs to be stored in the meantime, thus requiring an additional register variable to be live, but not actually achieving anything (the gep still needs to be executed once per loop iteration). The attached test case is derived from: typedef unsigned uint32; typedef unsigned char uint8; inline uint8 *f(uint32 value, uint8 *target) { while (value >= 0x80) { value >>= 7; ++target; } ++target; return target; } uint8 *g(uint32 b, uint8 *target) { target = f(b, f(42, target)); return target; } What happens is that the GEP stored in incptr2 is folded into itself through the loop's back-edge and the phi-node stored in loopptr, effectively incrementing the ptr by "2" in each iteration instead of "1". In this case, it is actually increasing the number of GEPs required as the GEP before the loop can't be folded away anymore. For comparison: With this patch: define i8* @test4(i32 %value, i8* %buffer) { entry: %cmp = icmp ugt i32 %value, 127 br i1 %cmp, label %loop.header, label %exit loop.header: ; preds = %entry br label %loop.body loop.body: ; preds = %loop.body, %loop.header %buffer.pn = phi i8* [ %buffer, %loop.header ], [ %loopptr, %loop.body ] %newval = phi i32 [ %value, %loop.header ], [ %shr, %loop.body ] %loopptr = getelementptr inbounds i8, i8* %buffer.pn, i64 1 %shr = lshr i32 %newval, 7 %cmp2 = icmp ugt i32 %newval, 16383 br i1 %cmp2, label %loop.body, label %loop.exit loop.exit: ; preds = %loop.body br label %exit exit: ; preds = %loop.exit, %entry %0 = phi i8* [ %loopptr, %loop.exit ], [ %buffer, %entry ] %incptr3 = getelementptr inbounds i8, i8* %0, i64 2 ret i8* %incptr3 } Without this patch: define i8* @test4(i32 %value, i8* %buffer) { entry: %incptr = getelementptr inbounds i8, i8* %buffer, i64 1 %cmp = icmp ugt i32 %value, 127 br i1 %cmp, label %loop.header, label %exit loop.header: ; preds = %entry br label %loop.body loop.body: ; preds = %loop.body, %loop.header %0 = phi i8* [ %buffer, %loop.header ], [ %loopptr, %loop.body ] %loopptr = phi i8* [ %incptr, %loop.header ], [ %incptr2, %loop.body ] %newval = phi i32 [ %value, %loop.header ], [ %shr, %loop.body ] %shr = lshr i32 %newval, 7 %incptr2 = getelementptr inbounds i8, i8* %0, i64 2 %cmp2 = icmp ugt i32 %newval, 16383 br i1 %cmp2, label %loop.body, label %loop.exit loop.exit: ; preds = %loop.body br label %exit exit: ; preds = %loop.exit, %entry %ptr2 = phi i8* [ %incptr2, %loop.exit ], [ %incptr, %entry ] %incptr3 = getelementptr inbounds i8, i8* %ptr2, i64 1 ret i8* %incptr3 } Review: http://reviews.llvm.org/D8245 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@232718 91177308-0d34-0410-b5e6-96231b3b80d8
137 lines
4.6 KiB
LLVM
137 lines
4.6 KiB
LLVM
; RUN: opt -instcombine -S < %s | FileCheck %s
|
|
|
|
%struct1 = type { %struct2*, i32, i32, i32 }
|
|
%struct2 = type { i32, i32 }
|
|
%struct3 = type { i32, %struct4, %struct4 }
|
|
%struct4 = type { %struct2, %struct2 }
|
|
|
|
define i32 @test1(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {
|
|
bb:
|
|
%tmp = getelementptr inbounds %struct1, %struct1* %dm, i64 0, i32 0
|
|
%tmp1 = load %struct2*, %struct2** %tmp, align 8
|
|
br i1 %tmp4, label %bb1, label %bb2
|
|
|
|
bb1:
|
|
%tmp10 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9
|
|
%tmp11 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 0
|
|
store i32 0, i32* %tmp11, align 4
|
|
br label %bb3
|
|
|
|
bb2:
|
|
%tmp20 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19
|
|
%tmp21 = getelementptr inbounds %struct2, %struct2* %tmp20, i64 0, i32 0
|
|
store i32 0, i32* %tmp21, align 4
|
|
br label %bb3
|
|
|
|
bb3:
|
|
%phi = phi %struct2* [ %tmp10, %bb1 ], [ %tmp20, %bb2 ]
|
|
%tmp24 = getelementptr inbounds %struct2, %struct2* %phi, i64 0, i32 1
|
|
%tmp25 = load i32, i32* %tmp24, align 4
|
|
ret i32 %tmp25
|
|
|
|
; CHECK-LABEL: @test1(
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 0
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19, i32 0
|
|
; CHECK: %[[PHI:[0-9A-Za-z]+]] = phi i64 [ %tmp9, %bb1 ], [ %tmp19, %bb2 ]
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %[[PHI]], i32 1
|
|
|
|
}
|
|
|
|
define i32 @test2(%struct1* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19) {
|
|
bb:
|
|
%tmp = getelementptr inbounds %struct1, %struct1* %dm, i64 0, i32 0
|
|
%tmp1 = load %struct2*, %struct2** %tmp, align 8
|
|
%tmp10 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9
|
|
%tmp11 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 0
|
|
store i32 0, i32* %tmp11, align 4
|
|
%tmp20 = getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19
|
|
%tmp21 = getelementptr inbounds %struct2, %struct2* %tmp20, i64 0, i32 0
|
|
store i32 0, i32* %tmp21, align 4
|
|
%tmp24 = getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 1
|
|
%tmp25 = load i32, i32* %tmp24, align 4
|
|
ret i32 %tmp25
|
|
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 0
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19, i32 0
|
|
; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 1
|
|
}
|
|
|
|
; Check that instcombine doesn't insert GEPs before landingpad.
|
|
|
|
define i32 @test3(%struct3* %dm, i1 %tmp4, i64 %tmp9, i64 %tmp19, i64 %tmp20, i64 %tmp21) {
|
|
bb:
|
|
%tmp = getelementptr inbounds %struct3, %struct3* %dm, i64 0
|
|
br i1 %tmp4, label %bb1, label %bb2
|
|
|
|
bb1:
|
|
%tmp1 = getelementptr inbounds %struct3, %struct3* %tmp, i64 %tmp19, i32 1
|
|
%tmp11 = getelementptr inbounds %struct4, %struct4* %tmp1, i64 0, i32 0, i32 0
|
|
store i32 0, i32* %tmp11, align 4
|
|
br label %bb3
|
|
|
|
bb2:
|
|
%tmp2 = getelementptr inbounds %struct3, %struct3* %tmp, i64 %tmp20, i32 1
|
|
%tmp12 = getelementptr inbounds %struct4, %struct4* %tmp2, i64 0, i32 0, i32 1
|
|
store i32 0, i32* %tmp12, align 4
|
|
br label %bb3
|
|
|
|
bb3:
|
|
%phi = phi %struct4* [ %tmp1, %bb1 ], [ %tmp2, %bb2 ]
|
|
%tmp22 = invoke i32 @foo1(i32 11) to label %bb4 unwind label %bb5
|
|
|
|
bb4:
|
|
ret i32 0
|
|
|
|
bb5:
|
|
%tmp27 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) catch i8* bitcast (i8** @_ZTIi to i8*)
|
|
%tmp34 = getelementptr inbounds %struct4, %struct4* %phi, i64 %tmp21, i32 1
|
|
%tmp35 = getelementptr inbounds %struct2, %struct2* %tmp34, i64 0, i32 1
|
|
%tmp25 = load i32, i32* %tmp35, align 4
|
|
ret i32 %tmp25
|
|
|
|
; CHECK-LABEL: @test3(
|
|
; CHECK: bb5:
|
|
; CHECK-NEXT: {{.*}}landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
|
}
|
|
|
|
@_ZTIi = external constant i8*
|
|
declare i32 @__gxx_personality_v0(...)
|
|
declare i32 @foo1(i32)
|
|
|
|
|
|
; Check that instcombine doesn't fold GEPs into themselves through a loop
|
|
; back-edge.
|
|
|
|
define i8* @test4(i32 %value, i8* %buffer) {
|
|
entry:
|
|
%incptr = getelementptr inbounds i8, i8* %buffer, i64 1
|
|
%cmp = icmp ugt i32 %value, 127
|
|
br i1 %cmp, label %loop.header, label %exit
|
|
|
|
loop.header:
|
|
br label %loop.body
|
|
|
|
loop.body:
|
|
%loopptr = phi i8* [ %incptr, %loop.header ], [ %incptr2, %loop.body ]
|
|
%newval = phi i32 [ %value, %loop.header ], [ %shr, %loop.body ]
|
|
%shr = lshr i32 %newval, 7
|
|
%incptr2 = getelementptr inbounds i8, i8* %loopptr, i64 1
|
|
%cmp2 = icmp ugt i32 %shr, 127
|
|
br i1 %cmp2, label %loop.body, label %loop.exit
|
|
|
|
loop.exit:
|
|
%exitptr = phi i8* [ %incptr2, %loop.body ]
|
|
br label %exit
|
|
|
|
exit:
|
|
%ptr2 = phi i8* [ %exitptr, %loop.exit ], [ %incptr, %entry ]
|
|
%incptr3 = getelementptr inbounds i8, i8* %ptr2, i64 1
|
|
ret i8* %incptr3
|
|
|
|
; CHECK-LABEL: @test4(
|
|
; CHECK: loop.body:
|
|
; CHECK: getelementptr{{.*}}i64 1
|
|
; CHECK: exit:
|
|
}
|