mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-08 03:30:22 +00:00
improve switch formation to handle small range
comparisons formed by comparisons. For example, this: void foo(unsigned x) { if (x == 0 || x == 1 || x == 3 || x == 4 || x == 6) bar(); } compiles into: _foo: ## @foo ## BB#0: ## %entry cmpl $6, %edi ja LBB0_2 ## BB#1: ## %entry movl %edi, %eax movl $91, %ecx btq %rax, %rcx jb LBB0_3 instead of: _foo: ## @foo ## BB#0: ## %entry cmpl $2, %edi jb LBB0_4 ## BB#1: ## %switch.early.test cmpl $6, %edi ja LBB0_3 ## BB#2: ## %switch.early.test movl %edi, %eax movl $88, %ecx btq %rax, %rcx jb LBB0_4 This catches a bunch of cases in GCC, which look like this: %804 = load i32* @which_alternative, align 4, !tbaa !0 %805 = icmp ult i32 %804, 2 %806 = icmp eq i32 %804, 3 %or.cond121 = or i1 %805, %806 %807 = icmp eq i32 %804, 4 %or.cond124 = or i1 %or.cond121, %807 br i1 %or.cond124, label %.thread, label %808 turning this into a range comparison. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122045 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1139d5090a
commit
e27db74a60
@ -54,7 +54,7 @@ public:
|
|||||||
/// @brief Initialize a range of values explicitly. This will assert out if
|
/// @brief Initialize a range of values explicitly. This will assert out if
|
||||||
/// Lower==Upper and Lower != Min or Max value for its type. It will also
|
/// Lower==Upper and Lower != Min or Max value for its type. It will also
|
||||||
/// assert out if the two APInt's are not the same bit width.
|
/// assert out if the two APInt's are not the same bit width.
|
||||||
ConstantRange(const APInt& Lower, const APInt& Upper);
|
ConstantRange(const APInt &Lower, const APInt &Upper);
|
||||||
|
|
||||||
/// makeICmpRegion - Produce the smallest range that contains all values that
|
/// makeICmpRegion - Produce the smallest range that contains all values that
|
||||||
/// might satisfy the comparison specified by Pred when compared to any value
|
/// might satisfy the comparison specified by Pred when compared to any value
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/Support/CFG.h"
|
||||||
|
#include "llvm/Support/ConstantRange.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -305,11 +306,33 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
|
|||||||
|
|
||||||
// If this is an icmp against a constant, handle this as one of the cases.
|
// If this is an icmp against a constant, handle this as one of the cases.
|
||||||
if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
|
if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
|
||||||
if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE))
|
if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
|
||||||
if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
|
if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ:ICmpInst::ICMP_NE)) {
|
||||||
Vals.push_back(C);
|
Vals.push_back(C);
|
||||||
return I->getOperand(0);
|
return I->getOperand(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have "x ult 3" comparison, for example, then we can add 0,1,2 to
|
||||||
|
// the set.
|
||||||
|
ConstantRange Span =
|
||||||
|
ConstantRange::makeICmpRegion(ICI->getPredicate(),
|
||||||
|
ConstantRange(C->getValue()));
|
||||||
|
|
||||||
|
// If this is an and/!= check then we want to optimize "x ugt 2" into
|
||||||
|
// x != 0 && x != 1.
|
||||||
|
if (!isEQ)
|
||||||
|
Span = Span.inverse();
|
||||||
|
|
||||||
|
// If there are a ton of values, we don't want to make a ginormous switch.
|
||||||
|
if (Span.getSetSize().getZExtValue() > 8 || Span.isEmptySet() ||
|
||||||
|
// We don't handle wrapped sets yet.
|
||||||
|
Span.isWrappedSet())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (APInt Tmp = Span.getLower(); Tmp != Span.getUpper(); ++Tmp)
|
||||||
|
Vals.push_back(ConstantInt::get(V->getContext(), Tmp));
|
||||||
|
return I->getOperand(0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,4 +351,73 @@ malformed:
|
|||||||
ret void
|
ret void
|
||||||
; CHECK: @test12
|
; CHECK: @test12
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; test13 - handle switch formation with ult.
|
||||||
|
define void @test13(i32 %x) nounwind ssp noredzone {
|
||||||
|
entry:
|
||||||
|
%cmp = icmp ult i32 %x, 2
|
||||||
|
br i1 %cmp, label %if.then, label %lor.lhs.false3
|
||||||
|
|
||||||
|
lor.lhs.false3: ; preds = %lor.lhs.false
|
||||||
|
%cmp5 = icmp eq i32 %x, 3
|
||||||
|
br i1 %cmp5, label %if.then, label %lor.lhs.false6
|
||||||
|
|
||||||
|
lor.lhs.false6: ; preds = %lor.lhs.false3
|
||||||
|
%cmp8 = icmp eq i32 %x, 4
|
||||||
|
br i1 %cmp8, label %if.then, label %lor.lhs.false9
|
||||||
|
|
||||||
|
lor.lhs.false9: ; preds = %lor.lhs.false6
|
||||||
|
%cmp11 = icmp eq i32 %x, 6
|
||||||
|
br i1 %cmp11, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
|
||||||
|
call void @foo1() noredzone
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %if.then, %lor.lhs.false9
|
||||||
|
ret void
|
||||||
|
; CHECK: @test13
|
||||||
|
; CHECK: switch i32 %x, label %if.end [
|
||||||
|
; CHECK: i32 6, label %if.then
|
||||||
|
; CHECK: i32 4, label %if.then
|
||||||
|
; CHECK: i32 3, label %if.then
|
||||||
|
; CHECK: i32 1, label %if.then
|
||||||
|
; CHECK: i32 0, label %if.then
|
||||||
|
; CHECK: ]
|
||||||
|
}
|
||||||
|
|
||||||
|
; test14 - handle switch formation with ult.
|
||||||
|
define void @test14(i32 %x) nounwind ssp noredzone {
|
||||||
|
entry:
|
||||||
|
%cmp = icmp ugt i32 %x, 2
|
||||||
|
br i1 %cmp, label %lor.lhs.false3, label %if.then
|
||||||
|
|
||||||
|
lor.lhs.false3: ; preds = %lor.lhs.false
|
||||||
|
%cmp5 = icmp ne i32 %x, 3
|
||||||
|
br i1 %cmp5, label %lor.lhs.false6, label %if.then
|
||||||
|
|
||||||
|
lor.lhs.false6: ; preds = %lor.lhs.false3
|
||||||
|
%cmp8 = icmp ne i32 %x, 4
|
||||||
|
br i1 %cmp8, label %lor.lhs.false9, label %if.then
|
||||||
|
|
||||||
|
lor.lhs.false9: ; preds = %lor.lhs.false6
|
||||||
|
%cmp11 = icmp ne i32 %x, 6
|
||||||
|
br i1 %cmp11, label %if.end, label %if.then
|
||||||
|
|
||||||
|
if.then: ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
|
||||||
|
call void @foo1() noredzone
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %if.then, %lor.lhs.false9
|
||||||
|
ret void
|
||||||
|
; CHECK: @test14
|
||||||
|
; CHECK: switch i32 %x, label %if.end [
|
||||||
|
; CHECK: i32 6, label %if.then
|
||||||
|
; CHECK: i32 4, label %if.then
|
||||||
|
; CHECK: i32 3, label %if.then
|
||||||
|
; CHECK: i32 1, label %if.then
|
||||||
|
; CHECK: i32 0, label %if.then
|
||||||
|
; CHECK: ]
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user