forked from OSchip/llvm-project
[ConstantFolding] Unify handling of load from uniform value
There are a number of places that specially handle loads from a uniform value where all the bits are the same (zero, one, undef, poison), because we a) don't care about the load offset in that case and b) it bypasses casts that might not be legal generally but do work with uniform values. We had multiple implementations of this, with a different set of supported values each time, as well as incomplete type checks in some cases. In particular, this fixes the assertion reported in https://reviews.llvm.org/D114889#3198921, as well as a similar assertion that could be triggered via constant folding. Differential Revision: https://reviews.llvm.org/D115924
This commit is contained in:
parent
d3abb04e14
commit
9fd4f80e33
|
@ -134,8 +134,8 @@ void g6() {
|
|||
f6m(1, 2, 3, 4, 5, s);
|
||||
}
|
||||
// CHECK: define{{.*}} void @g6
|
||||
// CHECK: call void @f6(i32 1, [4 x i32] [i32 6, i32 7, i32 0, i32 0])
|
||||
// CHECK: call void @f6m(i32 1, i32 2, i32 3, i32 4, i32 5, [4 x i32] [i32 6, i32 7, i32 0, i32 0])
|
||||
// CHECK: call void @f6(i32 1, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
|
||||
// CHECK: call void @f6m(i32 1, i32 2, i32 3, i32 4, i32 5, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
|
||||
// CHECK: declare void @f6(i32, [4 x i32])
|
||||
// CHECK: declare void @f6m(i32, i32, i32, i32, i32, [4 x i32])
|
||||
}
|
||||
|
|
|
@ -148,6 +148,12 @@ Constant *ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, APInt Offset,
|
|||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
|
||||
const DataLayout &DL);
|
||||
|
||||
/// If C is a uniform value where all bits are the same (either all zero, all
|
||||
/// ones, all undef or all poison), return the corresponding uniform value in
|
||||
/// the new type. If the value is not uniform or the result cannot be
|
||||
/// represented, return null.
|
||||
Constant *ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty);
|
||||
|
||||
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
||||
/// getelementptr constantexpr, return the constant value being addressed by the
|
||||
/// constant expression, or null if something is funny and we can't decide.
|
||||
|
|
|
@ -106,11 +106,8 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
|
|||
"Invalid constantexpr bitcast!");
|
||||
|
||||
// Catch the obvious splat cases.
|
||||
if (C->isNullValue() && !DestTy->isX86_MMXTy() && !DestTy->isX86_AMXTy())
|
||||
return Constant::getNullValue(DestTy);
|
||||
if (C->isAllOnesValue() && !DestTy->isX86_MMXTy() && !DestTy->isX86_AMXTy() &&
|
||||
!DestTy->isPtrOrPtrVectorTy()) // Don't get ones for ptr types!
|
||||
return Constant::getAllOnesValue(DestTy);
|
||||
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy))
|
||||
return Res;
|
||||
|
||||
if (auto *VTy = dyn_cast<VectorType>(C->getType())) {
|
||||
// Handle a vector->scalar integer/fp cast.
|
||||
|
@ -362,16 +359,8 @@ Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
|
|||
|
||||
// Catch the obvious splat cases (since all-zeros can coerce non-integral
|
||||
// pointers legally).
|
||||
if (C->isNullValue() && !DestTy->isX86_MMXTy() && !DestTy->isX86_AMXTy())
|
||||
return Constant::getNullValue(DestTy);
|
||||
if (C->isAllOnesValue() &&
|
||||
(DestTy->isIntegerTy() || DestTy->isFloatingPointTy() ||
|
||||
DestTy->isVectorTy()) &&
|
||||
!DestTy->isX86_AMXTy() && !DestTy->isX86_MMXTy() &&
|
||||
!DestTy->isPtrOrPtrVectorTy())
|
||||
// Get ones when the input is trivial, but
|
||||
// only for supported types inside getAllOnesValue.
|
||||
return Constant::getAllOnesValue(DestTy);
|
||||
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy))
|
||||
return Res;
|
||||
|
||||
// If the type sizes are the same and a cast is legal, just directly
|
||||
// cast the constant.
|
||||
|
@ -704,16 +693,13 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
|
|||
Offset, DL))
|
||||
return Result;
|
||||
|
||||
// If this load comes from anywhere in a constant global, and if the global
|
||||
// is all undef or zero, we know what it loads.
|
||||
if (auto *GV = dyn_cast<GlobalVariable>(getUnderlyingObject(C))) {
|
||||
if (GV->isConstant() && GV->hasDefinitiveInitializer()) {
|
||||
if (GV->getInitializer()->isNullValue())
|
||||
return Constant::getNullValue(Ty);
|
||||
if (isa<UndefValue>(GV->getInitializer()))
|
||||
return UndefValue::get(Ty);
|
||||
}
|
||||
}
|
||||
// If this load comes from anywhere in a uniform constant global, the value
|
||||
// is always the same, regardless of the loaded offset.
|
||||
if (auto *GV = dyn_cast<GlobalVariable>(getUnderlyingObject(C)))
|
||||
if (GV->isConstant() && GV->hasDefinitiveInitializer())
|
||||
if (Constant *Res =
|
||||
ConstantFoldLoadFromUniformValue(GV->getInitializer(), Ty))
|
||||
return Res;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -724,6 +710,19 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
|
|||
return ConstantFoldLoadFromConstPtr(C, Ty, Offset, DL);
|
||||
}
|
||||
|
||||
Constant *llvm::ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty) {
|
||||
if (isa<PoisonValue>(C))
|
||||
return PoisonValue::get(Ty);
|
||||
if (isa<UndefValue>(C))
|
||||
return UndefValue::get(Ty);
|
||||
if (C->isNullValue() && !Ty->isX86_MMXTy() && !Ty->isX86_AMXTy())
|
||||
return Constant::getNullValue(Ty);
|
||||
if (C->isAllOnesValue() &&
|
||||
(Ty->isIntOrIntVectorTy() || Ty->isFPOrFPVectorTy()))
|
||||
return Constant::getAllOnesValue(Ty);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// One of Op0/Op1 is a constant expression.
|
||||
|
|
|
@ -305,8 +305,9 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
|
|||
else if (auto *LI = dyn_cast<LoadInst>(U)) {
|
||||
// A load from zeroinitializer is always zeroinitializer, regardless of
|
||||
// any applied offset.
|
||||
if (Init->isNullValue()) {
|
||||
LI->replaceAllUsesWith(Constant::getNullValue(LI->getType()));
|
||||
if (Constant *Res =
|
||||
ConstantFoldLoadFromUniformValue(Init, LI->getType())) {
|
||||
LI->replaceAllUsesWith(Res);
|
||||
EraseFromParent(LI);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -globalopt < %s | FileCheck %s
|
||||
|
||||
@m64 = internal global <1 x i64> zeroinitializer
|
||||
|
||||
define i32 @load_mmx() {
|
||||
; CHECK-LABEL: @load_mmx(
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%temp = load x86_mmx, x86_mmx* bitcast (<1 x i64>* @m64 to x86_mmx*)
|
||||
ret i32 0
|
||||
}
|
|
@ -280,3 +280,16 @@ define { i64, i64 } @test_load_struct() {
|
|||
%v = load { i64, i64 }, { i64, i64 }* @g3
|
||||
ret { i64, i64 } %v
|
||||
}
|
||||
|
||||
@m64 = internal constant [2 x i64] zeroinitializer
|
||||
@idx = external global i32
|
||||
|
||||
; This should not try to create an x86_mmx null value.
|
||||
define x86_mmx @load_mmx() {
|
||||
; CHECK-LABEL: @load_mmx(
|
||||
; CHECK-NEXT: [[TEMP:%.*]] = load x86_mmx, x86_mmx* bitcast (i64* getelementptr ([2 x i64], [2 x i64]* @m64, i64 0, i64 ptrtoint (i32* @idx to i64)) to x86_mmx*), align 8
|
||||
; CHECK-NEXT: ret x86_mmx [[TEMP]]
|
||||
;
|
||||
%temp = load x86_mmx, x86_mmx* bitcast (i64* getelementptr ([2 x i64], [2 x i64]* @m64, i64 0, i64 ptrtoint (i32* @idx to i64)) to x86_mmx*)
|
||||
ret x86_mmx %temp
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue