|
20 | 20 | #include "llvm/IR/Function.h" |
21 | 21 | #include "llvm/IR/InstIterator.h" |
22 | 22 | #include "llvm/IR/Instructions.h" |
| 23 | +#include "llvm/IR/IntrinsicInst.h" |
| 24 | +#include "llvm/IR/IntrinsicsAMDGPU.h" |
23 | 25 | #include "llvm/IR/Module.h" |
24 | 26 | #include "llvm/IR/Operator.h" |
25 | 27 | #include "llvm/IR/PassInstrumentation.h" |
@@ -115,9 +117,41 @@ InjectorIRStrategy::chooseOperation(Value *Src, RandomIRBuilder &IB) { |
115 | 117 | return *RS; |
116 | 118 | } |
117 | 119 |
|
| 120 | +static inline Instruction *getEffectiveTerminator(BasicBlock &BB) { |
| 121 | + if (Instruction *I = BB.getTerminatingMustTailCall()) { |
| 122 | + return I; |
| 123 | + } else { |
| 124 | + // Certain intrinsics, such as @llvm.amdgcn.cs.chain, must be immediately |
| 125 | + // followed by an unreachable instruction.. |
| 126 | + if (UnreachableInst *UI = dyn_cast<UnreachableInst>(BB.getTerminator())) { |
| 127 | + if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(UI->getPrevNode())) { |
| 128 | + return II; |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + return BB.getTerminator(); |
| 134 | +} |
| 135 | + |
| 136 | +static inline BasicBlock::iterator getEndIterator(BasicBlock &BB) { |
| 137 | + auto End = BB.end(); |
| 138 | + |
| 139 | + if (BB.empty()) { |
| 140 | + return End; |
| 141 | + } |
| 142 | + |
| 143 | + Instruction *EffectiveTerminator = getEffectiveTerminator(BB); |
| 144 | + if (EffectiveTerminator != BB.getTerminator()) { |
| 145 | + // Adjust range for special cases such as tail call. |
| 146 | + End = std::prev(BB.end()); |
| 147 | + } |
| 148 | + |
| 149 | + return End; |
| 150 | +} |
| 151 | + |
118 | 152 | static inline iterator_range<BasicBlock::iterator> |
119 | 153 | getInsertionRange(BasicBlock &BB) { |
120 | | - auto End = BB.getTerminatingMustTailCall() ? std::prev(BB.end()) : BB.end(); |
| 154 | + auto End = getEndIterator(BB); |
121 | 155 | return make_range(BB.getFirstInsertionPt(), End); |
122 | 156 | } |
123 | 157 |
|
@@ -409,6 +443,12 @@ static bool isUnsupportedFunction(Function *F) { |
409 | 443 | return true; |
410 | 444 | } |
411 | 445 |
|
| 446 | + // This intrinsic has specific requirements for its parameters and the caller |
| 447 | + // must adhere to certain calling conventions. |
| 448 | + if (F->isIntrinsic() && F->getIntrinsicID() == Intrinsic::amdgcn_cs_chain) { |
| 449 | + return true; |
| 450 | + } |
| 451 | + |
412 | 452 | return false; |
413 | 453 | } |
414 | 454 |
|
@@ -641,8 +681,9 @@ void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { |
641 | 681 | std::map<size_t, Instruction *> AliveInsts; |
642 | 682 | std::map<Instruction *, size_t> AliveInstsLookup; |
643 | 683 | size_t InsertIdx = 0; |
644 | | - for (auto &I : make_early_inc_range(make_range( |
645 | | - BB.getFirstInsertionPt(), BB.getTerminator()->getIterator()))) { |
| 684 | + for (auto &I : make_early_inc_range( |
| 685 | + make_range(BB.getFirstInsertionPt(), |
| 686 | + getEffectiveTerminator(BB)->getIterator()))) { |
646 | 687 | // First gather all instructions that can be shuffled. Don't take |
647 | 688 | // terminator. |
648 | 689 | AliveInsts.insert({InsertIdx, &I}); |
@@ -702,7 +743,7 @@ void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) { |
702 | 743 | } |
703 | 744 | } |
704 | 745 |
|
705 | | - Instruction *Terminator = BB.getTerminator(); |
| 746 | + Instruction *Terminator = getEffectiveTerminator(BB); |
706 | 747 | // Then put instructions back. |
707 | 748 | for (Instruction *I : Insts) { |
708 | 749 | I->insertBefore(Terminator->getIterator()); |
|
0 commit comments