@@ -37,7 +37,18 @@ using namespace hlsl;
3737
3838namespace {
3939
40- Value *MergeGEP (GEPOperator *SrcGEP, GEPOperator *GEP) {
40+ // Attempt to merge the two GEPs into a single GEP.
41+ //
42+ // If `AsCast` is non-null the merged GEP will be wrapped
43+ // in an addrspacecast before replacing users. This allows
44+ // merging GEPs of the form
45+ //
46+ // gep(addrspacecast(gep(p0, gep_args0) to p1*), gep_args1)
47+ // into
48+ // addrspacecast(gep(p0, gep_args0+gep_args1) to p1*)
49+ //
50+ Value *MergeGEP (GEPOperator *SrcGEP, GEPOperator *GEP,
51+ AddrSpaceCastOperator *AsCast) {
4152 IRBuilder<> Builder (GEP->getContext ());
4253 StringRef Name = " " ;
4354 if (Instruction *I = dyn_cast<Instruction>(GEP)) {
@@ -75,7 +86,7 @@ Value *MergeGEP(GEPOperator *SrcGEP, GEPOperator *GEP) {
7586 }
7687
7788 // Update the GEP in place if possible.
78- if (SrcGEP->getNumOperands () == 2 ) {
89+ if (SrcGEP->getNumOperands () == 2 && !AsCast ) {
7990 GEP->setOperand (0 , SrcGEP->getOperand (0 ));
8091 GEP->setOperand (1 , Sum);
8192 return GEP;
@@ -94,12 +105,64 @@ Value *MergeGEP(GEPOperator *SrcGEP, GEPOperator *GEP) {
94105 DXASSERT (!Indices.empty (), " must merge" );
95106 Value *newGEP =
96107 Builder.CreateInBoundsGEP (nullptr , SrcGEP->getOperand (0 ), Indices, Name);
108+
109+ // Wrap the new gep in an addrspacecast if needed.
110+ if (AsCast)
111+ newGEP = Builder.CreateAddrSpaceCast (
112+ newGEP, PointerType::get (GEP->getType ()->getPointerElementType (),
113+ AsCast->getDestAddressSpace ()));
97114 GEP->replaceAllUsesWith (newGEP);
98115 if (Instruction *I = dyn_cast<Instruction>(GEP))
99116 I->eraseFromParent ();
100117 return newGEP;
101118}
102119
120+ // Examine the gep and try to merge it when the input pointer is
121+ // itself a gep. We handle two forms here:
122+ //
123+ // gep(gep(p))
124+ // gep(addrspacecast(gep(p)))
125+ //
126+ // If the gep was merged successfully then return the updated value, otherwise
127+ // return nullptr.
128+ //
129+ // When the gep is sucessfully merged we will delete the gep and also try to
130+ // delete the nested gep and addrspacecast.
131+ static Value *TryMegeWithNestedGEP (GEPOperator *GEP) {
132+ // Sentinal value to return when we fail to merge.
133+ Value *FailedToMerge = nullptr ;
134+
135+ Value *Ptr = GEP->getPointerOperand ();
136+ GEPOperator *prevGEP = dyn_cast<GEPOperator>(Ptr);
137+ AddrSpaceCastOperator *AsCast = nullptr ;
138+
139+ // If there is no directly nested gep try looking through an addrspacecast to
140+ // find one.
141+ if (!prevGEP) {
142+ AsCast = dyn_cast<AddrSpaceCastOperator>(Ptr);
143+ if (AsCast)
144+ prevGEP = dyn_cast<GEPOperator>(AsCast->getPointerOperand ());
145+ }
146+
147+ // Not a nested gep expression.
148+ if (!prevGEP)
149+ return FailedToMerge;
150+
151+ // Try merging the two geps.
152+ Value *newGEP = MergeGEP (prevGEP, GEP, AsCast);
153+ if (!newGEP)
154+ return FailedToMerge;
155+
156+ // Delete the nested gep and addrspacecast if no more users.
157+ if (AsCast && AsCast->user_empty () && isa<AddrSpaceCastInst>(AsCast))
158+ cast<AddrSpaceCastInst>(AsCast)->eraseFromParent ();
159+
160+ if (prevGEP->user_empty () && isa<GetElementPtrInst>(prevGEP))
161+ cast<GetElementPtrInst>(prevGEP)->eraseFromParent ();
162+
163+ return newGEP;
164+ }
165+
103166} // namespace
104167
105168namespace hlsl {
@@ -130,23 +193,14 @@ bool MergeGepUse(Value *V) {
130193 // merge any GEP users of the untranslated bitcast
131194 addUsersToWorklist (V);
132195 }
196+ } else if (isa<AddrSpaceCastOperator>(V)) {
197+ addUsersToWorklist (V);
133198 } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
134- if (GEPOperator *prevGEP =
135- dyn_cast<GEPOperator>(GEP->getPointerOperand ())) {
136- // merge the 2 GEPs, returns nullptr if couldn't merge
137- if (Value *newGEP = MergeGEP (prevGEP, GEP)) {
138- changed = true ;
139- worklist.push_back (newGEP);
140- // delete prevGEP if no more users
141- if (prevGEP->user_empty () && isa<GetElementPtrInst>(prevGEP)) {
142- cast<GetElementPtrInst>(prevGEP)->eraseFromParent ();
143- }
144- } else {
145- addUsersToWorklist (GEP);
146- }
199+ if (Value *newGEP = TryMegeWithNestedGEP (GEP)) {
200+ changed = true ;
201+ worklist.push_back (newGEP);
147202 } else {
148- // nothing to merge yet, add GEP users
149- addUsersToWorklist (V);
203+ addUsersToWorklist (GEP);
150204 }
151205 }
152206 }
0 commit comments