Skip to content

Commit 7377410

Browse files
authored
[FuzzMutate] Properly handle intrinsics and avoid illegal code genertion (#145495)
This PR addresses issues related to the `amdgcn_cs_chain` intrinsic: 1. Ensures the intrinsic's special attribute and calling convention requirements are not violated by the mutator. 2. Enforces the necessary unreachable statement following this type of intrinsic, preventing the fuzzer from generating invalid code.
1 parent f18cfb9 commit 7377410

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

llvm/lib/FuzzMutate/IRMutator.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "llvm/IR/Function.h"
2121
#include "llvm/IR/InstIterator.h"
2222
#include "llvm/IR/Instructions.h"
23+
#include "llvm/IR/IntrinsicInst.h"
24+
#include "llvm/IR/IntrinsicsAMDGPU.h"
2325
#include "llvm/IR/Module.h"
2426
#include "llvm/IR/Operator.h"
2527
#include "llvm/IR/PassInstrumentation.h"
@@ -115,9 +117,41 @@ InjectorIRStrategy::chooseOperation(Value *Src, RandomIRBuilder &IB) {
115117
return *RS;
116118
}
117119

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+
118152
static inline iterator_range<BasicBlock::iterator>
119153
getInsertionRange(BasicBlock &BB) {
120-
auto End = BB.getTerminatingMustTailCall() ? std::prev(BB.end()) : BB.end();
154+
auto End = getEndIterator(BB);
121155
return make_range(BB.getFirstInsertionPt(), End);
122156
}
123157

@@ -409,6 +443,12 @@ static bool isUnsupportedFunction(Function *F) {
409443
return true;
410444
}
411445

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+
412452
return false;
413453
}
414454

@@ -641,8 +681,9 @@ void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
641681
std::map<size_t, Instruction *> AliveInsts;
642682
std::map<Instruction *, size_t> AliveInstsLookup;
643683
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()))) {
646687
// First gather all instructions that can be shuffled. Don't take
647688
// terminator.
648689
AliveInsts.insert({InsertIdx, &I});
@@ -702,7 +743,7 @@ void ShuffleBlockStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
702743
}
703744
}
704745

705-
Instruction *Terminator = BB.getTerminator();
746+
Instruction *Terminator = getEffectiveTerminator(BB);
706747
// Then put instructions back.
707748
for (Instruction *I : Insts) {
708749
I->insertBefore(Terminator->getIterator());

llvm/unittests/FuzzMutate/StrategiesTest.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,4 +745,22 @@ TEST(AllStrategies, SkipEHPad) {
745745
mutateAndVerifyModule<InjectorIRStrategy>(Source);
746746
mutateAndVerifyModule<InstModificationIRStrategy>(Source);
747747
}
748+
749+
TEST(AllStrategies, SpecialTerminator) {
750+
StringRef Source = "\n\
751+
declare amdgpu_cs_chain void @callee(<3 x i32> inreg, { i32, ptr addrspace(5), i32, i32 })\n\
752+
define amdgpu_cs_chain void @chain_to_chain(<3 x i32> inreg %sgpr, { i32, ptr addrspace(5), i32, i32 } %vgpr) {\n\
753+
call void(ptr, i64, <3 x i32>, { i32, ptr addrspace(5), i32, i32 }, i32, ...) @llvm.amdgcn.cs.chain(ptr @callee, i64 -1, <3 x i32> inreg %sgpr, { i32, ptr addrspace(5), i32, i32 } %vgpr, i32 0) \n\
754+
unreachable\n\
755+
}\n\
756+
";
757+
mutateAndVerifyModule<InjectorIRStrategy>(Source);
758+
mutateAndVerifyModule<InsertCFGStrategy>(Source);
759+
mutateAndVerifyModule<InsertFunctionStrategy>(Source);
760+
mutateAndVerifyModule<InsertPHIStrategy>(Source);
761+
mutateAndVerifyModule<InstModificationIRStrategy>(Source);
762+
mutateAndVerifyModule<ShuffleBlockStrategy>(Source);
763+
mutateAndVerifyModule<SinkInstructionStrategy>(Source);
764+
}
765+
748766
} // namespace

0 commit comments

Comments
 (0)