Skip to content

Commit 0f3aff3

Browse files
[MergeFunc] Fix crash caused by bitcasting ArrayType (llvm#133259)
createCast in MergeFunctions did not consider ArrayTypes, which results in the creation of a bitcast between ArrayTypes in the thunk function, leading to an assertion failure in the provided test case. The version of createCast in GlobalMergeFunctions does handle ArrayTypes, so this common code has been factored out into the IRBuilder. rdar://145555614 (cherry picked from commit 1302610)
1 parent 886d8cc commit 0f3aff3

File tree

4 files changed

+119
-29
lines changed

4 files changed

+119
-29
lines changed

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,13 @@ class IRBuilderBase {
22392239
// isSigned parameter.
22402240
Value *CreateIntCast(Value *, Type *, const char *) = delete;
22412241

2242+
/// Cast between aggregate types that must have identical structure but may
2243+
/// differ in their leaf types. The leaf values are recursively extracted,
2244+
/// casted, and then reinserted into a value of type DestTy. The leaf types
2245+
/// must be castable using a bitcast or ptrcast, because signedness is
2246+
/// not specified.
2247+
Value *CreateAggregateCast(Value *V, Type *DestTy);
2248+
22422249
//===--------------------------------------------------------------------===//
22432250
// Instruction creation methods: Compare Instructions
22442251
//===--------------------------------------------------------------------===//

llvm/lib/IR/IRBuilder.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,40 @@ void IRBuilderBase::SetInstDebugLocation(Instruction *I) const {
7676
}
7777
}
7878

79+
Value *IRBuilderBase::CreateAggregateCast(Value *V, Type *DestTy) {
80+
Type *SrcTy = V->getType();
81+
if (SrcTy == DestTy)
82+
return V;
83+
84+
if (SrcTy->isAggregateType()) {
85+
unsigned NumElements;
86+
if (SrcTy->isStructTy()) {
87+
assert(DestTy->isStructTy() && "Expected StructType");
88+
assert(SrcTy->getStructNumElements() == DestTy->getStructNumElements() &&
89+
"Expected StructTypes with equal number of elements");
90+
NumElements = SrcTy->getStructNumElements();
91+
} else {
92+
assert(SrcTy->isArrayTy() && DestTy->isArrayTy() && "Expected ArrayType");
93+
assert(SrcTy->getArrayNumElements() == DestTy->getArrayNumElements() &&
94+
"Expected ArrayTypes with equal number of elements");
95+
NumElements = SrcTy->getArrayNumElements();
96+
}
97+
98+
Value *Result = PoisonValue::get(DestTy);
99+
for (unsigned I = 0; I < NumElements; ++I) {
100+
Type *ElementTy = SrcTy->isStructTy() ? DestTy->getStructElementType(I)
101+
: DestTy->getArrayElementType();
102+
Value *Element =
103+
CreateAggregateCast(CreateExtractValue(V, ArrayRef(I)), ElementTy);
104+
105+
Result = CreateInsertValue(Result, Element, ArrayRef(I));
106+
}
107+
return Result;
108+
}
109+
110+
return CreateBitOrPointerCast(V, DestTy);
111+
}
112+
79113
CallInst *
80114
IRBuilderBase::createCallHelper(Function *Callee, ArrayRef<Value *> Ops,
81115
const Twine &Name, Instruction *FMFSource,

llvm/lib/Transforms/IPO/MergeFunctions.cpp

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -483,33 +483,6 @@ void MergeFunctions::replaceDirectCallers(Function *Old, Function *New) {
483483
}
484484
}
485485

486-
// Helper for writeThunk,
487-
// Selects proper bitcast operation,
488-
// but a bit simpler then CastInst::getCastOpcode.
489-
static Value *createCast(IRBuilder<> &Builder, Value *V, Type *DestTy) {
490-
Type *SrcTy = V->getType();
491-
if (SrcTy->isStructTy()) {
492-
assert(DestTy->isStructTy());
493-
assert(SrcTy->getStructNumElements() == DestTy->getStructNumElements());
494-
Value *Result = PoisonValue::get(DestTy);
495-
for (unsigned int I = 0, E = SrcTy->getStructNumElements(); I < E; ++I) {
496-
Value *Element =
497-
createCast(Builder, Builder.CreateExtractValue(V, ArrayRef(I)),
498-
DestTy->getStructElementType(I));
499-
500-
Result = Builder.CreateInsertValue(Result, Element, ArrayRef(I));
501-
}
502-
return Result;
503-
}
504-
assert(!DestTy->isStructTy());
505-
if (SrcTy->isIntegerTy() && DestTy->isPointerTy())
506-
return Builder.CreateIntToPtr(V, DestTy);
507-
else if (SrcTy->isPointerTy() && DestTy->isIntegerTy())
508-
return Builder.CreatePtrToInt(V, DestTy);
509-
else
510-
return Builder.CreateBitCast(V, DestTy);
511-
}
512-
513486
// Erase the instructions in PDIUnrelatedWL as they are unrelated to the
514487
// parameter debug info, from the entry block.
515488
void MergeFunctions::eraseInstsUnrelatedToPDI(
@@ -761,7 +734,7 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
761734
unsigned i = 0;
762735
FunctionType *FFTy = F->getFunctionType();
763736
for (Argument &AI : H->args()) {
764-
Args.push_back(createCast(Builder, &AI, FFTy->getParamType(i)));
737+
Args.push_back(Builder.CreateAggregateCast(&AI, FFTy->getParamType(i)));
765738
++i;
766739
}
767740

@@ -776,7 +749,7 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
776749
if (H->getReturnType()->isVoidTy()) {
777750
RI = Builder.CreateRetVoid();
778751
} else {
779-
RI = Builder.CreateRet(createCast(Builder, CI, H->getReturnType()));
752+
RI = Builder.CreateRet(Builder.CreateAggregateCast(CI, H->getReturnType()));
780753
}
781754

782755
if (MergeFunctionsPDI) {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
2+
3+
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
4+
5+
%A = type { double }
6+
; the intermediary struct causes A_arr and B_arr to be different types
7+
%A_struct = type { %A }
8+
%A_arr = type { [1 x %A_struct] }
9+
10+
%B = type { double }
11+
%B_struct = type { %B }
12+
%B_arr = type { [1 x %B_struct] }
13+
14+
; conversion between C_arr and D_arr is possible, but requires ptrcast
15+
%C = type { i64 }
16+
%C_struct = type { %C }
17+
%C_arr = type { [1 x %C_struct] }
18+
19+
%D = type { ptr }
20+
%D_struct = type { %D }
21+
%D_arr = type { [1 x %D_struct] }
22+
23+
declare void @noop()
24+
25+
define %A_arr @a() {
26+
; CHECK-LABEL: define %A_arr @a() {
27+
; CHECK-NEXT: call void @noop()
28+
; CHECK-NEXT: ret %A_arr zeroinitializer
29+
;
30+
call void @noop()
31+
ret %A_arr zeroinitializer
32+
}
33+
34+
define %C_arr @c() {
35+
; CHECK-LABEL: define %C_arr @c() {
36+
; CHECK-NEXT: call void @noop()
37+
; CHECK-NEXT: ret %C_arr zeroinitializer
38+
;
39+
call void @noop()
40+
ret %C_arr zeroinitializer
41+
}
42+
43+
define %B_arr @b() {
44+
; CHECK-LABEL: define %B_arr @b() {
45+
; CHECK-NEXT: [[TMP1:%.*]] = tail call %A_arr @a
46+
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue %A_arr [[TMP1]], 0
47+
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue [1 x %A_struct] [[TMP2]], 0
48+
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue %A_struct [[TMP3]], 0
49+
; CHECK-NEXT: [[TMP5:%.*]] = extractvalue %A [[TMP4]], 0
50+
; CHECK-NEXT: [[TMP6:%.*]] = insertvalue %B poison, double [[TMP5]], 0
51+
; CHECK-NEXT: [[TMP7:%.*]] = insertvalue %B_struct poison, %B [[TMP6]], 0
52+
; CHECK-NEXT: [[TMP8:%.*]] = insertvalue [1 x %B_struct] poison, %B_struct [[TMP7]], 0
53+
; CHECK-NEXT: [[TMP9:%.*]] = insertvalue %B_arr poison, [1 x %B_struct] [[TMP8]], 0
54+
; CHECK-NEXT: ret %B_arr [[TMP9]]
55+
;
56+
call void @noop()
57+
ret %B_arr zeroinitializer
58+
}
59+
60+
define %D_arr @d() {
61+
; CHECK-LABEL: define %D_arr @d() {
62+
; CHECK-NEXT: [[TMP1:%.*]] = tail call %C_arr @c
63+
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue %C_arr [[TMP1]], 0
64+
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue [1 x %C_struct] [[TMP2]], 0
65+
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue %C_struct [[TMP3]], 0
66+
; CHECK-NEXT: [[TMP5:%.*]] = extractvalue %C [[TMP4]], 0
67+
; CHECK-NEXT: [[TMP10:%.*]] = inttoptr i64 [[TMP5]] to ptr
68+
; CHECK-NEXT: [[TMP6:%.*]] = insertvalue %D poison, ptr [[TMP10]], 0
69+
; CHECK-NEXT: [[TMP7:%.*]] = insertvalue %D_struct poison, %D [[TMP6]], 0
70+
; CHECK-NEXT: [[TMP8:%.*]] = insertvalue [1 x %D_struct] poison, %D_struct [[TMP7]], 0
71+
; CHECK-NEXT: [[TMP9:%.*]] = insertvalue %D_arr poison, [1 x %D_struct] [[TMP8]], 0
72+
; CHECK-NEXT: ret %D_arr [[TMP9]]
73+
;
74+
call void @noop()
75+
ret %D_arr zeroinitializer
76+
}

0 commit comments

Comments
 (0)