|
32 | 32 | #include "llvm/IR/IntrinsicInst.h"
|
33 | 33 | #include "llvm/IR/MDBuilder.h"
|
34 | 34 | #include "llvm/IR/PatternMatch.h"
|
| 35 | +#include "llvm/IR/Statepoint.h" |
35 | 36 | #include "llvm/IR/ValueHandle.h"
|
36 | 37 | #include "llvm/IR/ValueMap.h"
|
37 | 38 | #include "llvm/Pass.h"
|
@@ -72,6 +73,10 @@ static cl::opt<bool> DisableBranchOpts(
|
72 | 73 | "disable-cgp-branch-opts", cl::Hidden, cl::init(false),
|
73 | 74 | cl::desc("Disable branch optimizations in CodeGenPrepare"));
|
74 | 75 |
|
| 76 | +static cl::opt<bool> |
| 77 | + DisableGCOpts("disable-cgp-gc-opts", cl::Hidden, cl::init(false), |
| 78 | + cl::desc("Disable GC optimizations in CodeGenPrepare")); |
| 79 | + |
75 | 80 | static cl::opt<bool> DisableSelectToBranch(
|
76 | 81 | "disable-cgp-select2branch", cl::Hidden, cl::init(false),
|
77 | 82 | cl::desc("Disable select to branch conversion."));
|
@@ -183,6 +188,7 @@ class TypePromotionTransaction;
|
183 | 188 | const SmallVectorImpl<Instruction *> &Exts,
|
184 | 189 | unsigned CreatedInst);
|
185 | 190 | bool splitBranchCondition(Function &F);
|
| 191 | + bool simplifyOffsetableRelocate(Instruction &I); |
186 | 192 | };
|
187 | 193 | }
|
188 | 194 |
|
@@ -248,7 +254,7 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
|
248 | 254 | BasicBlock *BB = I++;
|
249 | 255 | bool ModifiedDTOnIteration = false;
|
250 | 256 | MadeChange |= OptimizeBlock(*BB, ModifiedDTOnIteration);
|
251 |
| - |
| 257 | + |
252 | 258 | // Restart BB iteration if the dominator tree of the Function was changed
|
253 | 259 | ModifiedDT |= ModifiedDTOnIteration;
|
254 | 260 | if (ModifiedDTOnIteration)
|
@@ -298,6 +304,16 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
|
298 | 304 | EverMadeChange |= MadeChange;
|
299 | 305 | }
|
300 | 306 |
|
| 307 | + if (!DisableGCOpts) { |
| 308 | + SmallVector<Instruction *, 2> Statepoints; |
| 309 | + for (BasicBlock &BB : F) |
| 310 | + for (Instruction &I : BB) |
| 311 | + if (isStatepoint(I)) |
| 312 | + Statepoints.push_back(&I); |
| 313 | + for (auto &I : Statepoints) |
| 314 | + EverMadeChange |= simplifyOffsetableRelocate(*I); |
| 315 | + } |
| 316 | + |
301 | 317 | if (ModifiedDT && DT)
|
302 | 318 | DT->recalculate(F);
|
303 | 319 |
|
@@ -521,6 +537,144 @@ void CodeGenPrepare::EliminateMostlyEmptyBlock(BasicBlock *BB) {
|
521 | 537 | DEBUG(dbgs() << "AFTER:\n" << *DestBB << "\n\n\n");
|
522 | 538 | }
|
523 | 539 |
|
| 540 | +// Computes a map of base pointer relocation instructions to corresponding |
| 541 | +// derived pointer relocation instructions given a vector of all relocate calls |
| 542 | +static void computeBaseDerivedRelocateMap( |
| 543 | + const SmallVectorImpl<User *> &AllRelocateCalls, |
| 544 | + DenseMap<IntrinsicInst *, SmallVector<IntrinsicInst *, 2>> & |
| 545 | + RelocateInstMap) { |
| 546 | + // Collect information in two maps: one primarily for locating the base object |
| 547 | + // while filling the second map; the second map is the final structure holding |
| 548 | + // a mapping between Base and corresponding Derived relocate calls |
| 549 | + DenseMap<std::pair<unsigned, unsigned>, IntrinsicInst *> RelocateIdxMap; |
| 550 | + for (auto &U : AllRelocateCalls) { |
| 551 | + GCRelocateOperands ThisRelocate(U); |
| 552 | + IntrinsicInst *I = cast<IntrinsicInst>(U); |
| 553 | + auto K = std::make_pair(ThisRelocate.basePtrIndex(), |
| 554 | + ThisRelocate.derivedPtrIndex()); |
| 555 | + RelocateIdxMap.insert(std::make_pair(K, I)); |
| 556 | + } |
| 557 | + for (auto &Item : RelocateIdxMap) { |
| 558 | + std::pair<unsigned, unsigned> Key = Item.first; |
| 559 | + if (Key.first == Key.second) |
| 560 | + // Base relocation: nothing to insert |
| 561 | + continue; |
| 562 | + |
| 563 | + IntrinsicInst *I = Item.second; |
| 564 | + auto BaseKey = std::make_pair(Key.first, Key.first); |
| 565 | + IntrinsicInst *Base = RelocateIdxMap[BaseKey]; |
| 566 | + if (!Base) |
| 567 | + // TODO: We might want to insert a new base object relocate and gep off |
| 568 | + // that, if there are enough derived object relocates. |
| 569 | + continue; |
| 570 | + RelocateInstMap[Base].push_back(I); |
| 571 | + } |
| 572 | +} |
| 573 | + |
| 574 | +// Accepts a GEP and extracts the operands into a vector provided they're all |
| 575 | +// small integer constants |
| 576 | +static bool getGEPSmallConstantIntOffsetV(GetElementPtrInst *GEP, |
| 577 | + SmallVectorImpl<Value *> &OffsetV) { |
| 578 | + for (unsigned i = 1; i < GEP->getNumOperands(); i++) { |
| 579 | + // Only accept small constant integer operands |
| 580 | + auto Op = dyn_cast<ConstantInt>(GEP->getOperand(i)); |
| 581 | + if (!Op || Op->getZExtValue() > 20) |
| 582 | + return false; |
| 583 | + } |
| 584 | + |
| 585 | + for (unsigned i = 1; i < GEP->getNumOperands(); i++) |
| 586 | + OffsetV.push_back(GEP->getOperand(i)); |
| 587 | + return true; |
| 588 | +} |
| 589 | + |
| 590 | +// Takes a RelocatedBase (base pointer relocation instruction) and Targets to |
| 591 | +// replace, computes a replacement, and affects it. |
| 592 | +static bool |
| 593 | +simplifyRelocatesOffABase(IntrinsicInst *RelocatedBase, |
| 594 | + const SmallVectorImpl<IntrinsicInst *> &Targets) { |
| 595 | + bool MadeChange = false; |
| 596 | + for (auto &ToReplace : Targets) { |
| 597 | + GCRelocateOperands MasterRelocate(RelocatedBase); |
| 598 | + GCRelocateOperands ThisRelocate(ToReplace); |
| 599 | + |
| 600 | + assert(ThisRelocate.basePtrIndex() == MasterRelocate.basePtrIndex() && |
| 601 | + "Not relocating a derived object of the original base object"); |
| 602 | + if (ThisRelocate.basePtrIndex() == ThisRelocate.derivedPtrIndex()) { |
| 603 | + // A duplicate relocate call. TODO: coalesce duplicates. |
| 604 | + continue; |
| 605 | + } |
| 606 | + |
| 607 | + Value *Base = ThisRelocate.basePtr(); |
| 608 | + auto Derived = dyn_cast<GetElementPtrInst>(ThisRelocate.derivedPtr()); |
| 609 | + if (!Derived || Derived->getPointerOperand() != Base) |
| 610 | + continue; |
| 611 | + |
| 612 | + SmallVector<Value *, 2> OffsetV; |
| 613 | + if (!getGEPSmallConstantIntOffsetV(Derived, OffsetV)) |
| 614 | + continue; |
| 615 | + |
| 616 | + // Create a Builder and replace the target callsite with a gep |
| 617 | + IRBuilder<> Builder(ToReplace); |
| 618 | + Builder.SetCurrentDebugLocation(ToReplace->getDebugLoc()); |
| 619 | + Value *Replacement = |
| 620 | + Builder.CreateGEP(RelocatedBase, makeArrayRef(OffsetV)); |
| 621 | + Instruction *ReplacementInst = cast<Instruction>(Replacement); |
| 622 | + ReplacementInst->removeFromParent(); |
| 623 | + ReplacementInst->insertAfter(RelocatedBase); |
| 624 | + Replacement->takeName(ToReplace); |
| 625 | + ToReplace->replaceAllUsesWith(Replacement); |
| 626 | + ToReplace->eraseFromParent(); |
| 627 | + |
| 628 | + MadeChange = true; |
| 629 | + } |
| 630 | + return MadeChange; |
| 631 | +} |
| 632 | + |
| 633 | +// Turns this: |
| 634 | +// |
| 635 | +// %base = ... |
| 636 | +// %ptr = gep %base + 15 |
| 637 | +// %tok = statepoint (%fun, i32 0, i32 0, i32 0, %base, %ptr) |
| 638 | +// %base' = relocate(%tok, i32 4, i32 4) |
| 639 | +// %ptr' = relocate(%tok, i32 4, i32 5) |
| 640 | +// %val = load %ptr' |
| 641 | +// |
| 642 | +// into this: |
| 643 | +// |
| 644 | +// %base = ... |
| 645 | +// %ptr = gep %base + 15 |
| 646 | +// %tok = statepoint (%fun, i32 0, i32 0, i32 0, %base, %ptr) |
| 647 | +// %base' = gc.relocate(%tok, i32 4, i32 4) |
| 648 | +// %ptr' = gep %base' + 15 |
| 649 | +// %val = load %ptr' |
| 650 | +bool CodeGenPrepare::simplifyOffsetableRelocate(Instruction &I) { |
| 651 | + bool MadeChange = false; |
| 652 | + SmallVector<User *, 2> AllRelocateCalls; |
| 653 | + |
| 654 | + for (auto *U : I.users()) |
| 655 | + if (isGCRelocate(dyn_cast<Instruction>(U))) |
| 656 | + // Collect all the relocate calls associated with a statepoint |
| 657 | + AllRelocateCalls.push_back(U); |
| 658 | + |
| 659 | + // We need atleast one base pointer relocation + one derived pointer |
| 660 | + // relocation to mangle |
| 661 | + if (AllRelocateCalls.size() < 2) |
| 662 | + return false; |
| 663 | + |
| 664 | + // RelocateInstMap is a mapping from the base relocate instruction to the |
| 665 | + // corresponding derived relocate instructions |
| 666 | + DenseMap<IntrinsicInst *, SmallVector<IntrinsicInst *, 2>> RelocateInstMap; |
| 667 | + computeBaseDerivedRelocateMap(AllRelocateCalls, RelocateInstMap); |
| 668 | + if (RelocateInstMap.empty()) |
| 669 | + return false; |
| 670 | + |
| 671 | + for (auto &Item : RelocateInstMap) |
| 672 | + // Item.first is the RelocatedBase to offset against |
| 673 | + // Item.second is the vector of Targets to replace |
| 674 | + MadeChange = simplifyRelocatesOffABase(Item.first, Item.second); |
| 675 | + return MadeChange; |
| 676 | +} |
| 677 | + |
524 | 678 | /// SinkCast - Sink the specified cast instruction into its user blocks
|
525 | 679 | static bool SinkCast(CastInst *CI) {
|
526 | 680 | BasicBlock *DefBB = CI->getParent();
|
|
0 commit comments