[GlobalOpt] Support "stored once" optimization for different types

GlobalOpt can optimize a global with undef initializer and a single
store to put the stored value into the initializer instead. Currently,
this requires the type of the global and the store to match.

This patch extends support to cases with different types (but same
size), in which case we create a new global to replace the old one.

Differential Revision: https://reviews.llvm.org/D117034
This commit is contained in:
Nikita Popov 2022-01-11 18:00:41 +01:00
parent c4db521cea
commit f3e87176e1
3 changed files with 58 additions and 9 deletions

View File

@ -1672,11 +1672,25 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
// This is restricted to address spaces that allow globals to have // This is restricted to address spaces that allow globals to have
// initializers. NVPTX, for example, does not support initializers for // initializers. NVPTX, for example, does not support initializers for
// shared memory (AS 3). // shared memory (AS 3).
if (SOVConstant && SOVConstant->getType() == GV->getValueType() && if (SOVConstant && isa<UndefValue>(GV->getInitializer()) &&
isa<UndefValue>(GV->getInitializer()) && DL.getTypeAllocSize(SOVConstant->getType()) ==
DL.getTypeAllocSize(GV->getValueType()) &&
CanHaveNonUndefGlobalInitializer) { CanHaveNonUndefGlobalInitializer) {
// Change the initial value here. if (SOVConstant->getType() == GV->getValueType()) {
GV->setInitializer(SOVConstant); // Change the initializer in place.
GV->setInitializer(SOVConstant);
} else {
// Create a new global with adjusted type.
auto *NGV = new GlobalVariable(
*GV->getParent(), SOVConstant->getType(), GV->isConstant(),
GV->getLinkage(), SOVConstant, "", GV, GV->getThreadLocalMode(),
GV->getAddressSpace());
NGV->takeName(GV);
NGV->copyAttributesFrom(GV);
GV->replaceAllUsesWith(ConstantExpr::getBitCast(NGV, GV->getType()));
GV->eraseFromParent();
GV = NGV;
}
// Clean up any obviously simplifiable users now. // Clean up any obviously simplifiable users now.
CleanupConstantGlobalUsers(GV, DL); CleanupConstantGlobalUsers(GV, DL);

View File

@ -0,0 +1,40 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
; RUN: opt -S -globalopt < %s | FileCheck %s
@g = internal global [4 x i8] undef
;.
; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal unnamed_addr constant i32 42
;.
define void @store() {
; CHECK-LABEL: @store(
; CHECK-NEXT: ret void
;
store i32 42, i32* bitcast ([4 x i8]* @g to i32*)
ret void
}
define i32 @load1() {
; CHECK-LABEL: @load1(
; CHECK-NEXT: ret i32 42
;
%v = load i32, i32* bitcast ([4 x i8]* @g to i32*)
ret i32 %v
}
define i16 @load2() {
; CHECK-LABEL: @load2(
; CHECK-NEXT: ret i16 42
;
%v = load i16, i16* bitcast ([4 x i8]* @g to i16*)
ret i16 %v
}
define [4 x i8] @load3() {
; CHECK-LABEL: @load3(
; CHECK-NEXT: [[V:%.*]] = load [4 x i8], [4 x i8]* bitcast (i32* @g to [4 x i8]*), align 1
; CHECK-NEXT: ret [4 x i8] [[V]]
;
%v = load [4 x i8], [4 x i8]* @g
ret [4 x i8] %v
}

View File

@ -8,13 +8,8 @@
@0 = internal global %T* null @0 = internal global %T* null
;.
; CHECK: @[[_BODY:[a-zA-Z0-9_$"\\.-]+]] = internal unnamed_addr global [[T:%.*]] undef
;.
define void @a() { define void @a() {
; CHECK-LABEL: @a( ; CHECK-LABEL: @a(
; CHECK-NEXT: store i32* null, i32** getelementptr inbounds ([[T:%.*]], %T* @.body, i64 0, i32 0), align 8
; CHECK-NEXT: [[TMP1:%.*]] = load atomic i64, i64* bitcast (%T* @.body to i64*) acquire, align 8
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;
%1 = tail call i8* @_Znwm(i64 8) %1 = tail call i8* @_Znwm(i64 8)