160160#include " llvm/ADT/DenseMap.h"
161161#include " llvm/ADT/DepthFirstIterator.h"
162162#include " llvm/ADT/SmallVector.h"
163+ #include " llvm/Analysis/AssumptionCache.h"
163164#include " llvm/Analysis/LoopInfo.h"
164165#include " llvm/Analysis/MemoryBuiltins.h"
165166#include " llvm/Analysis/TargetLibraryInfo.h"
198199using namespace llvm ;
199200using namespace llvm ::PatternMatch;
200201
202+ #define DEBUG_TYPE " separate-offset-gep"
203+
201204static cl::opt<bool > DisableSeparateConstOffsetFromGEP (
202205 " disable-separate-const-offset-from-gep" , cl::init(false ),
203206 cl::desc(" Do not separate the constant offset from a GEP instruction" ),
@@ -484,6 +487,9 @@ class SeparateConstOffsetFromGEP {
484487
485488 DenseMap<ExprKey, SmallVector<Instruction *, 2 >> DominatingAdds;
486489 DenseMap<ExprKey, SmallVector<Instruction *, 2 >> DominatingSubs;
490+
491+ bool decomposeXor (Function &F);
492+ Value *tryFoldXorToOrDisjoint (Instruction &I);
487493};
488494
489495} // end anonymous namespace
@@ -1162,6 +1168,162 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
11621168 return true ;
11631169}
11641170
1171+ bool SeparateConstOffsetFromGEP::decomposeXor (Function &F) {
1172+ bool FunctionChanged = false ;
1173+ SmallVector<std::pair<Instruction *, Value *>, 16 > ReplacementsToMake;
1174+
1175+ for (BasicBlock &BB : F) {
1176+ for (Instruction &I : BB) {
1177+ if (I.getOpcode () == Instruction::Xor) {
1178+ if (Value *Replacement = tryFoldXorToOrDisjoint (I)) {
1179+ ReplacementsToMake.push_back ({&I, Replacement});
1180+ FunctionChanged = true ;
1181+ }
1182+ }
1183+ }
1184+ }
1185+
1186+ if (!ReplacementsToMake.empty ()) {
1187+ LLVM_DEBUG (dbgs () << " Applying " << ReplacementsToMake.size ()
1188+ << " XOR->OR Disjoint replacements in " << F.getName ()
1189+ << " \n " );
1190+ for (auto &Pair : ReplacementsToMake) {
1191+ Pair.first ->replaceAllUsesWith (Pair.second );
1192+ }
1193+ for (auto &Pair : ReplacementsToMake) {
1194+ Pair.first ->eraseFromParent ();
1195+ }
1196+ }
1197+
1198+ return FunctionChanged;
1199+ }
1200+
1201+ static llvm::Instruction *findClosestSequentialXor (Value *A, Instruction &I) {
1202+ llvm::Instruction *ClosestUser = nullptr ;
1203+ for (llvm::User *User : A->users ()) {
1204+ if (auto *UserInst = llvm::dyn_cast<llvm::Instruction>(User)) {
1205+ if (UserInst->getOpcode () != Instruction::Xor || UserInst == &I)
1206+ continue ;
1207+ if (!ClosestUser) {
1208+ ClosestUser = UserInst;
1209+ } else {
1210+ // Compare instruction positions.
1211+ if (UserInst->comesBefore (ClosestUser)) {
1212+ ClosestUser = UserInst;
1213+ }
1214+ }
1215+ }
1216+ }
1217+ return ClosestUser;
1218+ }
1219+
1220+ // / Try to transform I = xor(A, C1) into or disjoint(Y, C2)
1221+ // / where Y = xor(A, C0) is another existing instruction dominating I,
1222+ // / C2 = C0 ^ C1, and A is known to be disjoint with C2.
1223+ // /
1224+ // / @param I The XOR instruction being visited.
1225+ // / @return The replacement Value* if successful, nullptr otherwise.
1226+ Value *SeparateConstOffsetFromGEP::tryFoldXorToOrDisjoint (Instruction &I) {
1227+ assert (I.getOpcode () == Instruction::Xor && " Instruction must be XOR" );
1228+
1229+ // Check if I has at least one GEP user.
1230+ bool HasGepUser = false ;
1231+ for (User *U : I.users ()) {
1232+ if (isa<GetElementPtrInst>(U)) {
1233+ HasGepUser = true ;
1234+ break ;
1235+ }
1236+ }
1237+ // If no user is a GEP instruction, abort the transformation.
1238+ if (!HasGepUser) {
1239+ LLVM_DEBUG (
1240+ dbgs () << " SeparateConstOffsetFromGEP: Skipping XOR->OR DISJOINT for "
1241+ << I << " because it has no GEP users.\n " );
1242+ return nullptr ;
1243+ }
1244+
1245+ Value *Op0 = I.getOperand (0 );
1246+ Value *Op1 = I.getOperand (1 );
1247+ ConstantInt *C1 = dyn_cast<ConstantInt>(Op1);
1248+ Value *A = Op0;
1249+
1250+ // Bail out of there is not constant operand.
1251+ if (!C1) {
1252+ C1 = dyn_cast<ConstantInt>(Op0);
1253+ if (!C1)
1254+ return nullptr ;
1255+ A = Op1;
1256+ }
1257+
1258+ if (isa<UndefValue>(A))
1259+ return nullptr ;
1260+
1261+ APInt C1_APInt = C1->getValue ();
1262+ unsigned BitWidth = C1_APInt.getBitWidth ();
1263+ Type *Ty = I.getType ();
1264+
1265+ // --- Step 2: Find Dominating Y = xor A, C0 ---
1266+ Instruction *FoundUserInst = nullptr ; // Instruction Y
1267+ APInt C0_APInt;
1268+
1269+ auto UserInst = findClosestSequentialXor (A, I);
1270+
1271+ BinaryOperator *UserBO = cast<BinaryOperator>(UserInst);
1272+ Value *UserOp0 = UserBO->getOperand (0 );
1273+ Value *UserOp1 = UserBO->getOperand (1 );
1274+ ConstantInt *UserC = nullptr ;
1275+ if (UserOp0 == A)
1276+ UserC = dyn_cast<ConstantInt>(UserOp1);
1277+ else if (UserOp1 == A)
1278+ UserC = dyn_cast<ConstantInt>(UserOp0);
1279+ if (UserC) {
1280+ if (DT->dominates (UserInst, &I)) {
1281+ FoundUserInst = UserInst;
1282+ C0_APInt = UserC->getValue ();
1283+ }
1284+ }
1285+ if (!FoundUserInst)
1286+ return nullptr ;
1287+
1288+ // Calculate C2.
1289+ APInt C2_APInt = C0_APInt ^ C1_APInt;
1290+
1291+ // Check Disjointness A & C2 == 0.
1292+ KnownBits KnownA (BitWidth);
1293+ AssumptionCache *AC = nullptr ;
1294+ computeKnownBits (A, KnownA, *DL, 0 , AC, &I, DT);
1295+
1296+ if ((KnownA.Zero & C2_APInt) != C2_APInt)
1297+ return nullptr ;
1298+
1299+ IRBuilder<> Builder (&I);
1300+ Builder.SetInsertPoint (&I); // Access Builder directly
1301+ Constant *C2_Const = ConstantInt::get (Ty, C2_APInt);
1302+ Twine Name = I.getName (); // Create Twine explicitly
1303+ Value *NewOr = BinaryOperator::CreateDisjointOr (FoundUserInst, C2_Const, Name,
1304+ I.getIterator ());
1305+ // Transformation Conditions Met.
1306+ LLVM_DEBUG (dbgs () << " SeparateConstOffsetFromGEP: Replacing " << I
1307+ << " (used by GEP) with " << *NewOr << " based on "
1308+ << *FoundUserInst << " \n " );
1309+
1310+ #if 0
1311+ // Preserve metadata
1312+ if (Instruction *NewOrInst = dyn_cast<Instruction>(NewOr)) {
1313+ NewOrInst->copyMetadata(I);
1314+ } else {
1315+ assert(false && "CreateNUWOr did not return an Instruction");
1316+ if (NewOr)
1317+ NewOr->deleteValue();
1318+ return nullptr;
1319+ }
1320+ #endif
1321+
1322+ // Return the replacement value. runOnFunction will handle replacement &
1323+ // deletion.
1324+ return NewOr;
1325+ }
1326+
11651327bool SeparateConstOffsetFromGEPLegacyPass::runOnFunction (Function &F) {
11661328 if (skipFunction (F))
11671329 return false ;
@@ -1181,6 +1343,10 @@ bool SeparateConstOffsetFromGEP::run(Function &F) {
11811343
11821344 DL = &F.getDataLayout ();
11831345 bool Changed = false ;
1346+
1347+ // Decompose xor in to "or disjoint" if possible.
1348+ Changed |= decomposeXor (F);
1349+
11841350 for (BasicBlock &B : F) {
11851351 if (!DT->isReachableFromEntry (&B))
11861352 continue ;
0 commit comments