This patch is a first draft of a new pass that adds a more flexible way
to eliminate compares based on more complex constraints collected from
dominating conditions.
In particular, it aims at simplifying conditions of the forms below
using a forward propagation approach, rather than instcomine-style
ad-hoc backwards walking of def-use chains.
if (x < y)
if (y < z)
if (x < z) <- simplify
or
if (x + 2 < y)
if (x + 1 < y) <- simplify assuming no wraps
The general approach is to collect conditions and blocks, sort them by
dominance and then iterate over the sorted list. Conditions are turned
into a linear inequality and add it to a system containing the linear
inequalities that hold on entry to the block. For blocks, we check each
compare against the system and see if it is implied by the constraints
in the system.
We also keep a stack of processed conditions and remove conditions from
the stack and the constraint system once they go out-of-scope (= do not
dominate the current block any longer).
Currently there still are the least the following areas for improvements
* Currently large unsigned constants cannot be added to the system
(coefficients must be represented as integers)
* The way constraints are managed currently is not very optimized.
Reviewed By: spatel
Differential Revision: https://reviews.llvm.org/D84547
135 lines
5.4 KiB
LLVM
135 lines
5.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -constraint-elimination -S %s | FileCheck %s
|
|
|
|
define void @test.not.uge.ult([10 x i8]* %start, i8* %low, i8* %high) {
|
|
; CHECK-LABEL: @test.not.uge.ult(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START:%.*]], i64 1, i64 3
|
|
; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8* [[ADD_PTR_I]], [[HIGH:%.*]]
|
|
; CHECK-NEXT: br i1 [[C_1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[START_0:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 10, i64 0
|
|
; CHECK-NEXT: [[C_0:%.*]] = icmp ult i8* [[START_0]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_0]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%add.ptr.i = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 1, i64 3
|
|
%c.1 = icmp uge i8* %add.ptr.i, %high
|
|
br i1 %c.1, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
ret void
|
|
|
|
if.end: ; preds = %entry
|
|
%start.0 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 10, i64 0
|
|
%c.0 = icmp ult i8* %start.0, %high
|
|
call void @use(i1 %c.0)
|
|
ret void
|
|
}
|
|
|
|
define void @test.not.uge.ule([10 x i8]* %start, i8* %low, i8* %high) {
|
|
; CHECK-LABEL: @test.not.uge.ule(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START:%.*]], i64 1, i64 3
|
|
; CHECK-NEXT: [[C:%.*]] = icmp uge i8* [[ADD_PTR_I]], [[HIGH:%.*]]
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[START_0:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 10, i64 0
|
|
; CHECK-NEXT: [[C_0:%.*]] = icmp ule i8* [[START_0]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_0]])
|
|
; CHECK-NEXT: [[START_1:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 2, i64 1
|
|
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8* [[START_1]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%add.ptr.i = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 1, i64 3
|
|
%c = icmp uge i8* %add.ptr.i, %high
|
|
br i1 %c, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
ret void
|
|
|
|
if.end: ; preds = %entry
|
|
%start.0 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 10, i64 0
|
|
%c.0 = icmp ule i8* %start.0, %high
|
|
call void @use(i1 %c.0)
|
|
%start.1 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 2, i64 1
|
|
%c.1 = icmp ule i8* %start.1, %high
|
|
call void @use(i1 %c.1)
|
|
ret void
|
|
}
|
|
|
|
define void @test.not.uge.ugt([10 x i8]* %start, i8* %low, i8* %high) {
|
|
; CHECK-LABEL: @test.not.uge.ugt(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START:%.*]], i64 1, i64 3
|
|
; CHECK-NEXT: [[C:%.*]] = icmp uge i8* [[ADD_PTR_I]], [[HIGH:%.*]]
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[START_0:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 3, i64 0
|
|
; CHECK-NEXT: [[C_0:%.*]] = icmp ugt i8* [[START_0]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_0]])
|
|
; CHECK-NEXT: [[START_1:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 3, i64 1
|
|
; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8* [[START_1]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_1]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%add.ptr.i = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 1, i64 3
|
|
%c = icmp uge i8* %add.ptr.i, %high
|
|
br i1 %c, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
ret void
|
|
|
|
if.end: ; preds = %entry
|
|
%start.0 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 3, i64 0
|
|
%c.0 = icmp ugt i8* %start.0, %high
|
|
call void @use(i1 %c.0)
|
|
|
|
%start.1 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 3, i64 1
|
|
%c.1 = icmp ugt i8* %start.1, %high
|
|
call void @use(i1 %c.1)
|
|
ret void
|
|
}
|
|
|
|
define void @test.not.uge.uge([10 x i8]* %start, i8* %low, i8* %high) {
|
|
; CHECK-LABEL: @test.not.uge.uge(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START:%.*]], i64 1, i64 3
|
|
; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8* [[ADD_PTR_I]], [[HIGH:%.*]]
|
|
; CHECK-NEXT: br i1 [[C_1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.end:
|
|
; CHECK-NEXT: [[START_0:%.*]] = getelementptr inbounds [10 x i8], [10 x i8]* [[START]], i64 3, i64 0
|
|
; CHECK-NEXT: [[C_0:%.*]] = icmp uge i8* [[START_0]], [[HIGH]]
|
|
; CHECK-NEXT: call void @use(i1 [[C_0]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%add.ptr.i = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 1, i64 3
|
|
%c.1 = icmp uge i8* %add.ptr.i, %high
|
|
br i1 %c.1, label %if.then, label %if.end
|
|
|
|
if.then: ; preds = %entry
|
|
ret void
|
|
|
|
if.end: ; preds = %entry
|
|
%start.0 = getelementptr inbounds [10 x i8], [10 x i8]* %start, i64 3, i64 0
|
|
%c.0 = icmp uge i8* %start.0, %high
|
|
call void @use(i1 %c.0)
|
|
|
|
ret void
|
|
}
|
|
|
|
declare void @use(i1)
|