mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
7c7b72a066
This patch adds limited support in ValueTracking for inferring known bits of a value from conditional expressions which must be true to reach the instruction we're trying to optimize. At this time, the feature is off by default. Once landed, I'm hoping for feedback from others on both profitability and compile time impact. Forms of conditional value propagation have been tried in LLVM before and have failed due to compile time problems. In an attempt to side step that, this patch only considers conditions where the edge leaving the branch dominates the context instruction. It does not attempt full dataflow. Even with that restriction, it handles many interesting cases: * Early exits from functions * Early exits from loops (for context instructions in the loop and after the check) * Conditions which control entry into loops, including multi-version loops (such as those produced during vectorization, IRCE, loop unswitch, etc..) Possible applications include optimizing using information provided by constructs such as: preconditions, assumptions, null checks, & range checks. This patch implements two approaches to the problem that need further benchmarking. Approach 1 is to directly walk the dominator tree looking for interesting conditions. Approach 2 is to inspect other uses of the value being queried for interesting comparisons. From initial benchmarking, it appears that Approach 2 is faster than Approach 1, but this needs to be further validated. Differential Revision: http://reviews.llvm.org/D7708 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231879 91177308-0d34-0410-b5e6-96231b3b80d8
153 lines
3.2 KiB
LLVM
153 lines
3.2 KiB
LLVM
; RUN: opt -instcombine -value-tracking-dom-conditions=1 -S < %s | FileCheck %s
|
|
|
|
target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32:32-p3:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
|
|
|
|
define i1 @test_cmp_ult(i64 %A) {
|
|
; CHECK-LABEL: @test_cmp_ult
|
|
entry:
|
|
%cmp = icmp ult i64 %A, 64
|
|
br i1 %cmp, label %taken, label %untaken
|
|
|
|
taken:
|
|
; CHECK-LABEL: taken:
|
|
; CHECK-NEXT: ret i1 false
|
|
%cmp2 = icmp ugt i64 %A, 64
|
|
ret i1 %cmp2
|
|
untaken:
|
|
ret i1 true
|
|
}
|
|
|
|
define i1 @test_cmp_ule(i64 %A) {
|
|
; CHECK-LABEL: @test_cmp_ule
|
|
entry:
|
|
%cmp = icmp ule i64 %A, 64
|
|
br i1 %cmp, label %taken, label %untaken
|
|
|
|
taken:
|
|
; CHECK-LABEL: taken:
|
|
; CHECK-NEXT: ret i1 false
|
|
%cmp2 = icmp ugt i64 %A, 128
|
|
ret i1 %cmp2
|
|
untaken:
|
|
ret i1 true
|
|
}
|
|
|
|
define i1 @test_cmp_sgt(i32 %A) {
|
|
; CHECK-LABEL: @test_cmp_sgt
|
|
entry:
|
|
%cmp = icmp sgt i32 %A, 10
|
|
br i1 %cmp, label %taken, label %untaken
|
|
|
|
taken:
|
|
; CHECK-LABEL: taken:
|
|
; CHECK-NEXT: ret i1 true
|
|
%cmp2 = icmp sgt i32 %A, -1
|
|
ret i1 %cmp2
|
|
untaken:
|
|
ret i1 true
|
|
}
|
|
|
|
define i64 @test_add_zero_bits(i64 %A) {
|
|
; CHECK-LABEL: @test_add_zero_bits
|
|
entry:
|
|
%cmp = icmp eq i64 %A, 2
|
|
br i1 %cmp, label %taken, label %untaken
|
|
|
|
taken:
|
|
; CHECK-LABEL: taken:
|
|
; CHECK-NEXT: ret i64 3
|
|
%add = add i64 %A, 1
|
|
ret i64 %add
|
|
untaken:
|
|
ret i64 %A
|
|
}
|
|
|
|
define i64 @test_add_nsw(i64 %A) {
|
|
; CHECK-LABEL: @test_add_nsw
|
|
entry:
|
|
%cmp = icmp ult i64 %A, 20
|
|
br i1 %cmp, label %taken, label %untaken
|
|
|
|
taken:
|
|
; CHECK-LABEL: taken:
|
|
; CHECK-NEXT: %add = add nuw nsw i64 %A, 1
|
|
; CHECK-NEXT: ret i64 %add
|
|
%add = add i64 %A, 1
|
|
ret i64 %add
|
|
untaken:
|
|
ret i64 %A
|
|
}
|
|
|
|
; After sinking the instructions into the if block, check that we
|
|
; can simplify some of them using dominating conditions.
|
|
define i32 @test_add_zero_bits_sink(i32 %x) nounwind ssp {
|
|
; CHECK-LABEL: @test_add_zero_bits_sink(
|
|
; CHECK-NOT: sdiv i32
|
|
entry:
|
|
%a = add nsw i32 %x, 16
|
|
%b = sdiv i32 %a, %x
|
|
%cmp = icmp ult i32 %x, 7
|
|
br i1 %cmp, label %bb1, label %bb2
|
|
|
|
bb1:
|
|
; CHECK-LABEL: bb1:
|
|
; CHECK-NEXT: or i32 %x, 16
|
|
; CHECK-NEXT: udiv i32
|
|
ret i32 %b
|
|
|
|
bb2:
|
|
ret i32 %x
|
|
}
|
|
|
|
; A condition in the same block gives no information
|
|
define i32 @test_neg1(i32 %x) nounwind ssp {
|
|
; CHECK-LABEL: @test_neg1
|
|
; CHECK: add
|
|
; CHECK: sdiv
|
|
; CHECK: icmp
|
|
; CHECK: select
|
|
entry:
|
|
%a = add nsw i32 %x, 16
|
|
%b = sdiv i32 %a, %x
|
|
%cmp = icmp ult i32 %x, 7
|
|
%ret = select i1 %cmp, i32 %a, i32 %b
|
|
ret i32 %ret
|
|
}
|
|
|
|
; A non-dominating edge gives no information
|
|
define i32 @test_neg2(i32 %x) {
|
|
; CHECK-LABEL: @test_neg2
|
|
entry:
|
|
%cmp = icmp ult i32 %x, 7
|
|
br i1 %cmp, label %bb1, label %merge
|
|
|
|
bb1:
|
|
br label %merge
|
|
|
|
merge:
|
|
; CHECK-LABEL: merge:
|
|
; CHECK: icmp
|
|
; CHECK: select
|
|
%cmp2 = icmp ult i32 %x, 7
|
|
%ret = select i1 %cmp2, i32 %x, i32 0
|
|
ret i32 %ret
|
|
}
|
|
|
|
; A unconditional branch expressed as a condition one gives no
|
|
; information (and shouldn't trip any asserts.)
|
|
define i32 @test_neg3(i32 %x) {
|
|
; CHECK-LABEL: @test_neg3
|
|
entry:
|
|
%cmp = icmp ult i32 %x, 7
|
|
br i1 %cmp, label %merge, label %merge
|
|
merge:
|
|
; CHECK-LABEL: merge:
|
|
; CHECK: icmp
|
|
; CHECK: select
|
|
%cmp2 = icmp ult i32 %x, 7
|
|
%ret = select i1 %cmp2, i32 %x, i32 0
|
|
ret i32 %ret
|
|
}
|
|
|
|
declare i32 @bar()
|