mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-27 02:31:09 +00:00
InstSimplify: Make shift, select and GEP simplifications vector-aware.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200016 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c55979b28d
commit
c166623dcd
@ -1288,6 +1288,33 @@ Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, const DataLayout *TD,
|
|||||||
return ::SimplifyFRemInst(Op0, Op1, Query (TD, TLI, DT), RecursionLimit);
|
return ::SimplifyFRemInst(Op0, Op1, Query (TD, TLI, DT), RecursionLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// isUndefShift - Returns true if a shift by \c Amount always yields undef.
|
||||||
|
static bool isUndefShift(Value *Amount) {
|
||||||
|
Constant *C = dyn_cast<Constant>(Amount);
|
||||||
|
if (!C)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// X shift by undef -> undef because it may shift by the bitwidth.
|
||||||
|
if (isa<UndefValue>(C))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Shifting by the bitwidth or more is undefined.
|
||||||
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(C))
|
||||||
|
if (CI->getValue().getLimitedValue() >=
|
||||||
|
CI->getType()->getScalarSizeInBits())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If all lanes of a vector shift are undefined the whole shift is.
|
||||||
|
if (isa<ConstantVector>(C) || isa<ConstantDataVector>(C)) {
|
||||||
|
for (unsigned I = 0, E = C->getType()->getVectorNumElements(); I != E; ++I)
|
||||||
|
if (!isUndefShift(C->getAggregateElement(I)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can
|
/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can
|
||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
|
static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
|
||||||
@ -1307,14 +1334,8 @@ static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
|
|||||||
if (match(Op1, m_Zero()))
|
if (match(Op1, m_Zero()))
|
||||||
return Op0;
|
return Op0;
|
||||||
|
|
||||||
// X shift by undef -> undef because it may shift by the bitwidth.
|
// Fold undefined shifts.
|
||||||
if (match(Op1, m_Undef()))
|
if (isUndefShift(Op1))
|
||||||
return Op1;
|
|
||||||
|
|
||||||
// Shifting by the bitwidth or more is undefined.
|
|
||||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1))
|
|
||||||
if (CI->getValue().getLimitedValue() >=
|
|
||||||
Op0->getType()->getScalarSizeInBits())
|
|
||||||
return UndefValue::get(Op0->getType());
|
return UndefValue::get(Op0->getType());
|
||||||
|
|
||||||
// If the operation is with the result of a select instruction, check whether
|
// If the operation is with the result of a select instruction, check whether
|
||||||
@ -2699,8 +2720,12 @@ static Value *SimplifySelectInst(Value *CondVal, Value *TrueVal,
|
|||||||
unsigned MaxRecurse) {
|
unsigned MaxRecurse) {
|
||||||
// select true, X, Y -> X
|
// select true, X, Y -> X
|
||||||
// select false, X, Y -> Y
|
// select false, X, Y -> Y
|
||||||
if (ConstantInt *CB = dyn_cast<ConstantInt>(CondVal))
|
if (Constant *CB = dyn_cast<Constant>(CondVal)) {
|
||||||
return CB->getZExtValue() ? TrueVal : FalseVal;
|
if (CB->isAllOnesValue())
|
||||||
|
return TrueVal;
|
||||||
|
if (CB->isNullValue())
|
||||||
|
return FalseVal;
|
||||||
|
}
|
||||||
|
|
||||||
// select C, X, X -> X
|
// select C, X, X -> X
|
||||||
if (TrueVal == FalseVal)
|
if (TrueVal == FalseVal)
|
||||||
@ -2731,10 +2756,7 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
|||||||
/// fold the result. If not, this returns null.
|
/// fold the result. If not, this returns null.
|
||||||
static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
||||||
// The type of the GEP pointer operand.
|
// The type of the GEP pointer operand.
|
||||||
PointerType *PtrTy = dyn_cast<PointerType>(Ops[0]->getType());
|
PointerType *PtrTy = cast<PointerType>(Ops[0]->getType()->getScalarType());
|
||||||
// The GEP pointer operand is not a pointer, it's a vector of pointers.
|
|
||||||
if (!PtrTy)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// getelementptr P -> P.
|
// getelementptr P -> P.
|
||||||
if (Ops.size() == 1)
|
if (Ops.size() == 1)
|
||||||
@ -2744,13 +2766,14 @@ static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
|
|||||||
// Compute the (pointer) type returned by the GEP instruction.
|
// Compute the (pointer) type returned by the GEP instruction.
|
||||||
Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, Ops.slice(1));
|
Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, Ops.slice(1));
|
||||||
Type *GEPTy = PointerType::get(LastType, PtrTy->getAddressSpace());
|
Type *GEPTy = PointerType::get(LastType, PtrTy->getAddressSpace());
|
||||||
|
if (VectorType *VT = dyn_cast<VectorType>(Ops[0]->getType()))
|
||||||
|
GEPTy = VectorType::get(GEPTy, VT->getNumElements());
|
||||||
return UndefValue::get(GEPTy);
|
return UndefValue::get(GEPTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ops.size() == 2) {
|
if (Ops.size() == 2) {
|
||||||
// getelementptr P, 0 -> P.
|
// getelementptr P, 0 -> P.
|
||||||
if (ConstantInt *C = dyn_cast<ConstantInt>(Ops[1]))
|
if (match(Ops[1], m_Zero()))
|
||||||
if (C->isZero())
|
|
||||||
return Ops[0];
|
return Ops[0];
|
||||||
// getelementptr P, N -> P if P points to a type of zero size.
|
// getelementptr P, N -> P if P points to a type of zero size.
|
||||||
if (Q.TD) {
|
if (Q.TD) {
|
||||||
|
@ -739,3 +739,21 @@ define i1 @non_inbounds_gep_compare2(i64* %a) {
|
|||||||
ret i1 %cmp
|
ret i1 %cmp
|
||||||
; CHECK-NEXT: ret i1 true
|
; CHECK-NEXT: ret i1 true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define <4 x i8> @vectorselectfold(<4 x i8> %a, <4 x i8> %b) {
|
||||||
|
%false = icmp ne <4 x i8> zeroinitializer, zeroinitializer
|
||||||
|
%sel = select <4 x i1> %false, <4 x i8> %a, <4 x i8> %b
|
||||||
|
ret <4 x i8> %sel
|
||||||
|
|
||||||
|
; CHECK-LABEL: @vectorselectfold
|
||||||
|
; CHECK-NEXT: ret <4 x i8> %b
|
||||||
|
}
|
||||||
|
|
||||||
|
define <4 x i8> @vectorselectfold2(<4 x i8> %a, <4 x i8> %b) {
|
||||||
|
%true = icmp eq <4 x i8> zeroinitializer, zeroinitializer
|
||||||
|
%sel = select <4 x i1> %true, <4 x i8> %a, <4 x i8> %b
|
||||||
|
ret <4 x i8> %sel
|
||||||
|
|
||||||
|
; CHECK-LABEL: @vectorselectfold
|
||||||
|
; CHECK-NEXT: ret <4 x i8> %a
|
||||||
|
}
|
||||||
|
@ -153,3 +153,10 @@ define i64 @test18(i64 %a) {
|
|||||||
%r = call i64 (i64)* undef(i64 %a)
|
%r = call i64 (i64)* undef(i64 %a)
|
||||||
ret i64 %r
|
ret i64 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test19
|
||||||
|
; CHECK: ret <4 x i8> undef
|
||||||
|
define <4 x i8> @test19(<4 x i8> %a) {
|
||||||
|
%b = shl <4 x i8> %a, <i8 8, i8 9, i8 undef, i8 -1>
|
||||||
|
ret <4 x i8> %b
|
||||||
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
;RUN: opt -instsimplify -disable-output < %s
|
; RUN: opt -S -instsimplify < %s | FileCheck %s
|
||||||
|
|
||||||
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
|
||||||
declare void @helper(<2 x i8*>)
|
declare void @helper(<2 x i8*>)
|
||||||
define void @test(<2 x i8*> %a) {
|
define void @test(<2 x i8*> %a) {
|
||||||
%A = getelementptr <2 x i8*> %a, <2 x i32> <i32 0, i32 0>
|
%A = getelementptr <2 x i8*> %a, <2 x i32> <i32 0, i32 0>
|
||||||
@ -6,3 +9,47 @@ define void @test(<2 x i8*> %a) {
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define <4 x i8*> @test1(<4 x i8*> %a) {
|
||||||
|
%gep = getelementptr <4 x i8*> %a, <4 x i32> zeroinitializer
|
||||||
|
ret <4 x i8*> %gep
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test1
|
||||||
|
; CHECK-NEXT: ret <4 x i8*> %a
|
||||||
|
}
|
||||||
|
|
||||||
|
define <4 x i8*> @test2(<4 x i8*> %a) {
|
||||||
|
%gep = getelementptr <4 x i8*> %a
|
||||||
|
ret <4 x i8*> %gep
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test2
|
||||||
|
; CHECK-NEXT: ret <4 x i8*> %a
|
||||||
|
}
|
||||||
|
|
||||||
|
%struct = type { double, float }
|
||||||
|
|
||||||
|
define <4 x float*> @test3() {
|
||||||
|
%gep = getelementptr <4 x %struct*> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
|
||||||
|
ret <4 x float*> %gep
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test3
|
||||||
|
; CHECK-NEXT: ret <4 x float*> undef
|
||||||
|
}
|
||||||
|
|
||||||
|
%struct.empty = type { }
|
||||||
|
|
||||||
|
define <4 x %struct.empty*> @test4(<4 x %struct.empty*> %a) {
|
||||||
|
%gep = getelementptr <4 x %struct.empty*> %a, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
|
||||||
|
ret <4 x %struct.empty*> %gep
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test4
|
||||||
|
; CHECK-NEXT: ret <4 x %struct.empty*> %a
|
||||||
|
}
|
||||||
|
|
||||||
|
define <4 x i8*> @test5() {
|
||||||
|
%c = inttoptr <4 x i64> <i64 1, i64 2, i64 3, i64 4> to <4 x i8*>
|
||||||
|
%gep = getelementptr <4 x i8*> %c, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
|
||||||
|
ret <4 x i8*> %gep
|
||||||
|
|
||||||
|
; CHECK-LABEL: @test5
|
||||||
|
; CHECK-NEXT: ret <4 x i8*> getelementptr (<4 x i8*> <i8* inttoptr (i64 1 to i8*), i8* inttoptr (i64 2 to i8*), i8* inttoptr (i64 3 to i8*), i8* inttoptr (i64 4 to i8*)>, <4 x i32> <i32 1, i32 1, i32 1, i32 1>)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user