Skip to content

Commit 72be4ca

Browse files
committed
Fix bug when copying to global dest
The case in which copying from a global source to a global dest wasn't handled and caused opt to crash. This is now handled and a new test has been added to check Change-Id: Ieb0467797fcee888f6e95e68af4dac9c05d70a4d
1 parent c17ff0d commit 72be4ca

File tree

2 files changed

+86
-31
lines changed

2 files changed

+86
-31
lines changed

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,9 +2043,13 @@ static bool callInstIsMemcpy(CallInst *CI) {
20432043
}
20442044

20452045
static bool destArrayCanBeWidened(CallInst *CI) {
2046+
auto *GV = dyn_cast<GlobalVariable>(CI->getArgOperand(0));
20462047
auto *Alloca = dyn_cast<AllocaInst>(CI->getArgOperand(0));
20472048
auto *IsVolatile = dyn_cast<ConstantInt>(CI->getArgOperand(3));
20482049

2050+
if (!GV || !GV->hasInitializer())
2051+
return false;
2052+
20492053
if (!Alloca || !IsVolatile || IsVolatile->isOne())
20502054
return false;
20512055

@@ -2055,21 +2059,61 @@ static bool destArrayCanBeWidened(CallInst *CI) {
20552059
return true;
20562060
}
20572061

2062+
static GlobalVariable *widenGlobalVariable(GlobalVariable *OldVar, Function *F,
2063+
unsigned NumBytesToPad,
2064+
unsigned NumBytesToCopy) {
2065+
if (!OldVar->hasInitializer())
2066+
return nullptr;
2067+
2068+
ConstantDataArray *DataArray =
2069+
dyn_cast<ConstantDataArray>(OldVar->getInitializer());
2070+
if (!DataArray)
2071+
return nullptr;
2072+
2073+
// Update to be word aligned (memcpy(...,X,...))
2074+
// create replacement with padded null bytes.
2075+
StringRef Data = DataArray->getRawDataValues();
2076+
std::vector<uint8_t> StrData(Data.begin(), Data.end());
2077+
for (unsigned int p = 0; p < NumBytesToPad; p++)
2078+
StrData.push_back('\0');
2079+
auto Arr = ArrayRef(StrData.data(), NumBytesToCopy + NumBytesToPad);
2080+
// Create new padded version of global variable.
2081+
Constant *SourceReplace = ConstantDataArray::get(F->getContext(), Arr);
2082+
GlobalVariable *NewGV = new GlobalVariable(
2083+
*(F->getParent()), SourceReplace->getType(), true, OldVar->getLinkage(),
2084+
SourceReplace, SourceReplace->getName());
2085+
// Copy any other attributes from original global variable
2086+
// e.g. unamed_addr
2087+
NewGV->copyAttributesFrom(OldVar);
2088+
NewGV->takeName(OldVar);
2089+
return NewGV;
2090+
}
2091+
20582092
static void widenDestArray(CallInst *CI, const unsigned NumBytesToPad,
20592093
const unsigned NumBytesToCopy,
20602094
ConstantDataArray *SourceDataArray) {
2061-
unsigned ElementByteWidth = SourceDataArray->getElementByteSize();
2062-
unsigned int TotalBytes = NumBytesToCopy + NumBytesToPad;
2063-
unsigned NumElementsToCopy = divideCeil(TotalBytes, ElementByteWidth);
2064-
// Update destination array to be word aligned (memcpy(X,...,...))
2095+
2096+
// Dest array can be global or local
2097+
auto *DestGV = dyn_cast<GlobalVariable>(CI->getArgOperand(0));
20652098
auto *Alloca = dyn_cast<AllocaInst>(CI->getArgOperand(0));
2066-
IRBuilder<> BuildAlloca(Alloca);
2067-
AllocaInst *NewAlloca = BuildAlloca.CreateAlloca(ArrayType::get(
2068-
Alloca->getAllocatedType()->getArrayElementType(), NumElementsToCopy));
2069-
NewAlloca->takeName(Alloca);
2070-
NewAlloca->setAlignment(Alloca->getAlign());
2071-
Alloca->replaceAllUsesWith(NewAlloca);
2072-
Alloca->eraseFromParent();
2099+
if (DestGV) {
2100+
auto *F = CI->getCalledFunction();
2101+
auto *NewDestGV =
2102+
widenGlobalVariable(DestGV, F, NumBytesToPad, NumBytesToCopy);
2103+
DestGV->replaceAllUsesWith(NewDestGV);
2104+
} else if (Alloca) {
2105+
unsigned ElementByteWidth = SourceDataArray->getElementByteSize();
2106+
unsigned int TotalBytes = NumBytesToCopy + NumBytesToPad;
2107+
unsigned NumElementsToCopy = divideCeil(TotalBytes, ElementByteWidth);
2108+
// Update destination array to be word aligned (memcpy(X,...,...))
2109+
IRBuilder<> BuildAlloca(Alloca);
2110+
AllocaInst *NewAlloca = BuildAlloca.CreateAlloca(ArrayType::get(
2111+
Alloca->getAllocatedType()->getArrayElementType(), NumElementsToCopy));
2112+
NewAlloca->takeName(Alloca);
2113+
NewAlloca->setAlignment(Alloca->getAlign());
2114+
Alloca->replaceAllUsesWith(NewAlloca);
2115+
Alloca->eraseFromParent();
2116+
}
20732117
}
20742118

20752119
static bool tryWidenGlobalArrayAndDests(Function *F, GlobalVariable *SourceVar,
@@ -2081,25 +2125,10 @@ static bool tryWidenGlobalArrayAndDests(Function *F, GlobalVariable *SourceVar,
20812125
!SourceVar->hasLocalLinkage() || !SourceVar->hasGlobalUnnamedAddr())
20822126
return false;
20832127

2084-
// Update source to be word aligned (memcpy(...,X,...))
2085-
// create replacement with padded null bytes.
2086-
StringRef Data = SourceDataArray->getRawDataValues();
2087-
std::vector<uint8_t> StrData(Data.begin(), Data.end());
2088-
for (unsigned int p = 0; p < NumBytesToPad; p++)
2089-
StrData.push_back('\0');
2090-
auto Arr = ArrayRef(StrData.data(), NumBytesToCopy + NumBytesToPad);
2091-
2092-
// Create new padded version of global variable.
2093-
Constant *SourceReplace = ConstantDataArray::get(F->getContext(), Arr);
2094-
GlobalVariable *NewGV = new GlobalVariable(
2095-
*(F->getParent()), SourceReplace->getType(), true,
2096-
SourceVar->getLinkage(), SourceReplace, SourceReplace->getName());
2097-
2098-
// Copy any other attributes from original global variable
2099-
// e.g. unamed_addr
2100-
NewGV->copyAttributesFrom(SourceVar);
2101-
NewGV->takeName(SourceVar);
2102-
2128+
auto *NewSourceGV =
2129+
widenGlobalVariable(SourceVar, F, NumBytesToPad, NumBytesToCopy);
2130+
if (!NewSourceGV)
2131+
return false;
21032132
// Update arguments of remaining uses that
21042133
// are memcpys.
21052134
for (auto *User : SourceVar->users()) {
@@ -2112,7 +2141,7 @@ static bool tryWidenGlobalArrayAndDests(Function *F, GlobalVariable *SourceVar,
21122141
CI->setArgOperand(2, ConstantInt::get(BytesToCopyOp->getType(),
21132142
NumBytesToCopy + NumBytesToPad));
21142143
}
2115-
SourceVar->replaceAllUsesWith(NewGV);
2144+
SourceVar->replaceAllUsesWith(NewSourceGV);
21162145

21172146
NumGlobalArraysPadded++;
21182147
return true;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -mtriple=arm-none-eabi -passes=globalopt -S | FileCheck %s
3+
4+
; CHECK: [4 x i8]
5+
@.i8 = private unnamed_addr constant [3 x i8] [i8 1, i8 2, i8 3] , align 1
6+
; CHECK: [4 x i8]
7+
@other = private unnamed_addr global [3 x i8] [i8 1, i8 2, i8 3] , align 1
8+
9+
define void @memcpy_multiple() {
10+
; CHECK-LABEL: define void @memcpy_multiple() local_unnamed_addr {
11+
; CHECK-NEXT: [[ENTRY:.*:]]
12+
; CHECK-NEXT: [[SOMETHING:%.*]] = alloca [4 x i8], align 1
13+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) [[SOMETHING]], ptr noundef nonnull align 1 dereferenceable(3) @.i8, i32 4, i1 false)
14+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) @other, ptr noundef nonnull align 1 dereferenceable(3) @.i8, i32 4, i1 false)
15+
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @bar(ptr nonnull [[SOMETHING]])
16+
; CHECK-NEXT: ret void
17+
;
18+
entry:
19+
%something = alloca [3 x i8], align 1
20+
call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) %something, ptr noundef nonnull align 1 dereferenceable(3) @.i8, i32 3, i1 false)
21+
call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) @other, ptr noundef nonnull align 1 dereferenceable(3) @.i8, i32 3, i1 false)
22+
%call2 = call i32 @bar(ptr nonnull %something)
23+
ret void
24+
}
25+
26+
declare i32 @bar(...)

0 commit comments

Comments
 (0)