|
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