Skip to content

Commit

Permalink
[ConstantFolding] Do not consider padded-in-memory types as uniform (#…
Browse files Browse the repository at this point in the history
…81854)

Teaching ConstantFoldLoadFromUniformValue that types that are padded in
memory can't be considered as uniform.

Using the big hammer to prevent optimizations when loading from a
constant for which DataLayout::typeSizeEqualsStoreSize would return
false.

Main problem solved would be something like this:
  store i17 -1, ptr %p, align 4
  %v = load i8, ptr %p, align 1
If for example the i17 occupies 32 bits in memory, then LLVM IR doesn't
really tell where the padding goes. And even if we assume that the 15
most significant bits are padding, then they should be considered as
undefined (even if LLVM backend typically would pad with zeroes).
Anyway, for a big-endian target the load would read those most
significant bits, which aren't guaranteed to be one's. So it would be
wrong to constant fold the load as returning -1.

If LLVM IR had been more explicit about the placement of padding, then
we could allow the constant fold of the load in the example, but only
for little-endian.

Fixes: #81793
  • Loading branch information
bjope committed Feb 15, 2024
1 parent 8416586 commit 7677453
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 12 deletions.
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/ConstantFolding.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ Constant *ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
/// 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);
Constant *ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty,
const DataLayout &DL);

/// canConstantFoldCallTo - Return true if its even possible to fold a call to
/// the specified function.
Expand Down
17 changes: 11 additions & 6 deletions llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
"Invalid constantexpr bitcast!");

// Catch the obvious splat cases.
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy))
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy, DL))
return Res;

if (auto *VTy = dyn_cast<VectorType>(C->getType())) {
Expand Down Expand Up @@ -342,7 +342,7 @@ bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV,
}

Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
const DataLayout &DL) {
const DataLayout &DL) {
do {
Type *SrcTy = C->getType();
if (SrcTy == DestTy)
Expand All @@ -355,7 +355,7 @@ Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,

// Catch the obvious splat cases (since all-zeros can coerce non-integral
// pointers legally).
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy))
if (Constant *Res = ConstantFoldLoadFromUniformValue(C, DestTy, DL))
return Res;

// If the type sizes are the same and a cast is legal, just directly
Expand Down Expand Up @@ -709,7 +709,7 @@ Constant *llvm::ConstantFoldLoadFromConst(Constant *C, Type *Ty,
return PoisonValue::get(Ty);

// Try an offset-independent fold of a uniform value.
if (Constant *Result = ConstantFoldLoadFromUniformValue(C, Ty))
if (Constant *Result = ConstantFoldLoadFromUniformValue(C, Ty, DL))
return Result;

// Try hard to fold loads from bitcasted strange and non-type-safe things.
Expand Down Expand Up @@ -745,7 +745,7 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,

// If this load comes from anywhere in a uniform constant global, the value
// is always the same, regardless of the loaded offset.
return ConstantFoldLoadFromUniformValue(GV->getInitializer(), Ty);
return ConstantFoldLoadFromUniformValue(GV->getInitializer(), Ty, DL);
}

Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
Expand All @@ -754,11 +754,16 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
return ConstantFoldLoadFromConstPtr(C, Ty, Offset, DL);
}

Constant *llvm::ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty) {
Constant *llvm::ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty,
const DataLayout &DL) {
if (isa<PoisonValue>(C))
return PoisonValue::get(Ty);
if (isa<UndefValue>(C))
return UndefValue::get(Ty);
// If padding is needed when storing C to memory, then it isn't considered as
// uniform.
if (!DL.typeSizeEqualsStoreSize(C->getType()))
return nullptr;
if (C->isNullValue() && !Ty->isX86_MMXTy() && !Ty->isX86_AMXTy())
return Constant::getNullValue(Ty);
if (C->isAllOnesValue() &&
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6960,8 +6960,8 @@ Value *llvm::simplifyLoadInst(LoadInst *LI, Value *PtrOp,

// If GlobalVariable's initializer is uniform, then return the constant
// regardless of its offset.
if (Constant *C =
ConstantFoldLoadFromUniformValue(GV->getInitializer(), LI->getType()))
if (Constant *C = ConstantFoldLoadFromUniformValue(GV->getInitializer(),
LI->getType(), Q.DL))
return C;

// Try to convert operand into a constant by stripping offsets while looking
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/IPO/Attributor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ AA::getInitialValueForObj(Attributor &A, const AbstractAttribute &QueryingAA,
return ConstantFoldLoadFromConst(Initializer, &Ty, Offset, DL);
}

return ConstantFoldLoadFromUniformValue(Initializer, &Ty);
return ConstantFoldLoadFromUniformValue(Initializer, &Ty, DL);
}

bool AA::isValidInScope(const Value &V, const Function *Scope) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/IPO/GlobalOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
// A load from a uniform value is always the same, regardless of any
// applied offset.
Type *Ty = LI->getType();
if (Constant *Res = ConstantFoldLoadFromUniformValue(Init, Ty)) {
if (Constant *Res = ConstantFoldLoadFromUniformValue(Init, Ty, DL)) {
LI->replaceAllUsesWith(Res);
EraseFromParent(LI);
continue;
Expand Down
35 changes: 34 additions & 1 deletion llvm/test/Transforms/InstSimplify/ConstProp/loads.ll
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,45 @@ define ptr addrspace(2) @load_non_integral_ptr_from_i8_data() {

define i8 @load_i8_from_i1() {
; CHECK-LABEL: @load_i8_from_i1(
; CHECK-NEXT: ret i8 -1
; CHECK-NEXT: [[V:%.*]] = load i8, ptr @g_i1, align 1
; CHECK-NEXT: ret i8 [[V]]
;
%v = load i8, ptr @g_i1
ret i8 %v
}

@global9 = internal constant i9 -1

; Reproducer for https://github.com/llvm/llvm-project/issues/81793
define i8 @load_i8_from_i9() {
; CHECK-LABEL: @load_i8_from_i9(
; CHECK-NEXT: [[V:%.*]] = load i8, ptr @global9, align 1
; CHECK-NEXT: ret i8 [[V]]
;
%v = load i8, ptr @global9
ret i8 %v
}

define i9 @load_i9_from_i9() {
; CHECK-LABEL: @load_i9_from_i9(
; CHECK-NEXT: ret i9 -1
;
%v = load i9, ptr @global9
ret i9 %v
}

; Reproducer for https://github.com/llvm/llvm-project/issues/81793
define i16 @load_i16_from_i17_store(ptr %p) {
; CHECK-LABEL: @load_i16_from_i17_store(
; CHECK-NEXT: store i17 -1, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[V:%.*]] = load i16, ptr @global9, align 2
; CHECK-NEXT: ret i16 [[V]]
;
store i17 -1, ptr %p
%v = load i16, ptr @global9
ret i16 %v
}

@global128 = internal constant i128 1125899906842625
define i128 @load-128bit(){
; CHECK-LABEL: @load-128bit(
Expand Down

0 comments on commit 7677453

Please sign in to comment.