[llvm] a933f60 - Revert "[FuzzMutate] RandomIRBuilder has more source and sink type now."
Peter Rong via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 16 09:08:43 PDT 2023
Author: Peter Rong
Date: 2023-04-16T09:08:26-07:00
New Revision: a933f6003ecf79521fcfd28d7e31475e21d3121b
URL: https://github.com/llvm/llvm-project/commit/a933f6003ecf79521fcfd28d7e31475e21d3121b
DIFF: https://github.com/llvm/llvm-project/commit/a933f6003ecf79521fcfd28d7e31475e21d3121b.diff
LOG: Revert "[FuzzMutate] RandomIRBuilder has more source and sink type now."
This reverts commit e0117a3efacf9620408393f162a7795b5e0965d2.
Added:
Modified:
llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
llvm/lib/FuzzMutate/RandomIRBuilder.cpp
llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
index de66c080809d8..a7048f6def896 100644
--- a/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
+++ b/llvm/include/llvm/FuzzMutate/RandomIRBuilder.h
@@ -18,16 +18,11 @@
#include <random>
namespace llvm {
-class AllocaInst;
class BasicBlock;
-class Function;
-class GlobalVariable;
class Instruction;
class LLVMContext;
class Type;
class Value;
-class Module;
-
namespace fuzzerop {
class SourcePred;
}
@@ -43,23 +38,6 @@ struct RandomIRBuilder {
// TODO: Try to make this a bit less of a random mishmash of functions.
- /// Create a stack memory at the head of the function, store \c Init to the
- /// memory if provided.
- AllocaInst *createStackMemory(Function *F, Type *Ty, Value *Init = nullptr);
- /// Find or create a global variable. It will be initialized by random
- /// constants that satisfies \c Pred. It will also report whether this global
- /// variable found or created.
- std::pair<GlobalVariable *, bool>
- findOrCreateGlobalVariable(Module *M, ArrayRef<Value *> Srcs,
- fuzzerop::SourcePred Pred);
- enum SourceType {
- SrcFromInstInCurBlock,
- FunctionArgument,
- InstInDominator,
- SrcFromGlobalVariable,
- NewConstOrStack,
- EndOfValueSource,
- };
/// Find a "source" for some operation, which will be used in one of the
/// operation's operands. This either selects an instruction in \c Insts or
/// returns some new arbitrary Value.
@@ -76,22 +54,11 @@ struct RandomIRBuilder {
Value *newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
ArrayRef<Value *> Srcs, fuzzerop::SourcePred Pred,
bool allowConstant = true);
-
- enum SinkType {
- /// TODO: Also consider pointers in function argument.
- SinkToInstInCurBlock,
- PointersInDominator,
- InstInDominatee,
- NewStore,
- SinkToGlobalVariable,
- EndOfValueSink,
- };
/// Find a viable user for \c V in \c Insts, which should all be contained in
/// \c BB. This may also create some new instruction in \c BB and use that.
- Instruction *connectToSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
- Value *V);
+ void connectToSink(BasicBlock &BB, ArrayRef<Instruction *> Insts, Value *V);
/// Create a user for \c V in \c BB.
- Instruction *newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts, Value *V);
+ void newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts, Value *V);
Value *findPointer(BasicBlock &BB, ArrayRef<Instruction *> Insts,
ArrayRef<Value *> Srcs, fuzzerop::SourcePred Pred);
Type *chooseType(LLVMContext &Context, ArrayRef<Value *> Srcs,
diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
index 3817bc054ec6c..bb9f91d0bb375 100644
--- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
+++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp
@@ -13,89 +13,12 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Module.h"
using namespace llvm;
using namespace fuzzerop;
-/// Return a vector of Blocks that dominates this block, excluding current
-/// block.
-static std::vector<BasicBlock *> getDominators(BasicBlock *BB) {
- std::vector<BasicBlock *> ret;
- DominatorTree DT(*BB->getParent());
- DomTreeNode *Node = DT[BB]->getIDom();
- while (Node && Node->getBlock()) {
- ret.push_back(Node->getBlock());
- // Get parent block.
- Node = Node->getIDom();
- }
- return ret;
-}
-
-/// Return a vector of Blocks that is dominated by this block, excluding current
-/// block
-static std::vector<BasicBlock *> getDominatees(BasicBlock *BB) {
- DominatorTree DT(*BB->getParent());
- std::vector<BasicBlock *> ret;
- for (DomTreeNode *Child : DT[BB]->children())
- ret.push_back(Child->getBlock());
- uint64_t Idx = 0;
- while (Idx < ret.size()) {
- DomTreeNode *Node = DT[ret[Idx]];
- Idx++;
- for (DomTreeNode *Child : Node->children())
- ret.push_back(Child->getBlock());
- }
- return ret;
-}
-
-AllocaInst *RandomIRBuilder::createStackMemory(Function *F, Type *Ty,
- Value *Init) {
- /// TODO: For all Allocas, maybe allocate an array.
- BasicBlock *EntryBB = &F->getEntryBlock();
- DataLayout DL(F->getParent());
- AllocaInst *Alloca = new AllocaInst(Ty, DL.getAllocaAddrSpace(), "A",
- &*EntryBB->getFirstInsertionPt());
- if (Init)
- new StoreInst(Init, Alloca, Alloca->getNextNode());
- return Alloca;
-}
-
-std::pair<GlobalVariable *, bool>
-RandomIRBuilder::findOrCreateGlobalVariable(Module *M, ArrayRef<Value *> Srcs,
- fuzzerop::SourcePred Pred) {
- auto MatchesPred = [&Srcs, &Pred](GlobalVariable *GV) {
- // Can't directly compare GV's type, as it would be a pointer to the actual
- // type.
- return Pred.matches(Srcs, UndefValue::get(GV->getValueType()));
- };
- bool DidCreate = false;
- SmallVector<GlobalVariable *, 4> GlobalVars;
- for (GlobalVariable &GV : M->globals()) {
- GlobalVars.push_back(&GV);
- }
- auto RS = makeSampler(Rand, make_filter_range(GlobalVars, MatchesPred));
- RS.sample(nullptr, 1);
- GlobalVariable *GV = RS.getSelection();
- if (!GV) {
- DidCreate = true;
- using LinkageTypes = GlobalVariable::LinkageTypes;
- auto TRS = makeSampler<Constant *>(Rand);
- TRS.sample(Pred.generate(Srcs, KnownTypes));
- Constant *Init = TRS.getSelection();
- Type *Ty = Init->getType();
- GV = new GlobalVariable(*M, Ty, false, LinkageTypes::ExternalLinkage, Init,
- "G", nullptr,
- GlobalValue::ThreadLocalMode::NotThreadLocal,
- M->getDataLayout().getDefaultGlobalsAddressSpace());
- }
- return {GV, DidCreate};
-}
-
Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
ArrayRef<Instruction *> Insts) {
return findOrCreateSource(BB, Insts, {}, anyType());
@@ -106,83 +29,15 @@ Value *RandomIRBuilder::findOrCreateSource(BasicBlock &BB,
ArrayRef<Value *> Srcs,
SourcePred Pred,
bool allowConstant) {
- auto MatchesPred = [&Srcs, &Pred](Value *V) { return Pred.matches(Srcs, V); };
- SmallVector<uint64_t, 8> SrcTys;
- for (uint64_t i = 0; i < EndOfValueSource; i++)
- SrcTys.push_back(i);
- std::shuffle(SrcTys.begin(), SrcTys.end(), Rand);
- for (uint64_t SrcTy : SrcTys) {
- switch (SrcTy) {
- case SrcFromInstInCurBlock: {
- auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred));
- if (!RS.isEmpty()) {
- return RS.getSelection();
- }
- break;
- }
- case FunctionArgument: {
- Function *F = BB.getParent();
- SmallVector<Argument *, 8> Args;
- for (uint64_t i = 0; i < F->arg_size(); i++) {
- Args.push_back(F->getArg(i));
- }
- auto RS = makeSampler(Rand, make_filter_range(Args, MatchesPred));
- if (!RS.isEmpty()) {
- return RS.getSelection();
- }
- break;
- }
- case InstInDominator: {
- auto Dominators = getDominators(&BB);
- std::shuffle(Dominators.begin(), Dominators.end(), Rand);
- for (BasicBlock *Dom : Dominators) {
- SmallVector<Instruction *, 16> Instructions;
- for (Instruction &I : *Dom) {
- Instructions.push_back(&I);
- }
- auto RS =
- makeSampler(Rand, make_filter_range(Instructions, MatchesPred));
- // Also consider choosing no source, meaning we want a new one.
- if (!RS.isEmpty()) {
- return RS.getSelection();
- }
- }
- break;
- }
- case SrcFromGlobalVariable: {
- Module *M = BB.getParent()->getParent();
- auto [GV, DidCreate] = findOrCreateGlobalVariable(M, Srcs, Pred);
- Type *Ty = GV->getValueType();
- LoadInst *LoadGV = nullptr;
- if (BB.getTerminator()) {
- LoadGV = new LoadInst(Ty, GV, "LGV", &*BB.getFirstInsertionPt());
- } else {
- LoadGV = new LoadInst(Ty, GV, "LGV", &BB);
- }
- // Because we might be generating new values, we have to check if it
- // matches again.
- if (DidCreate) {
- if (Pred.matches(Srcs, LoadGV)) {
- return LoadGV;
- }
- LoadGV->eraseFromParent();
- // If no one is using this GlobalVariable, delete it too.
- if (GV->use_empty()) {
- GV->eraseFromParent();
- }
- }
- break;
- }
- case NewConstOrStack: {
- return newSource(BB, Insts, Srcs, Pred, allowConstant);
- }
- default:
- case EndOfValueSource: {
- llvm_unreachable("EndOfValueSource executed");
- }
- }
- }
- llvm_unreachable("Can't find a source");
+ auto MatchesPred = [&Srcs, &Pred](Instruction *Inst) {
+ return Pred.matches(Srcs, Inst);
+ };
+ auto RS = makeSampler(Rand, make_filter_range(Insts, MatchesPred));
+ // Also consider choosing no source, meaning we want a new one.
+ RS.sample(nullptr, /*Weight=*/1);
+ if (Instruction *Src = RS.getSelection())
+ return Src;
+ return newSource(BB, Insts, Srcs, Pred, allowConstant);
}
Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
@@ -221,7 +76,12 @@ Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
if (!allowConstant && isa<Constant>(newSrc)) {
Type *Ty = newSrc->getType();
Function *F = BB.getParent();
- AllocaInst *Alloca = createStackMemory(F, Ty, newSrc);
+ BasicBlock *EntryBB = &F->getEntryBlock();
+ /// TODO: For all Allocas, maybe allocate an array.
+ DataLayout DL(BB.getParent()->getParent());
+ AllocaInst *Alloca = new AllocaInst(Ty, DL.getProgramAddressSpace(), "A",
+ EntryBB->getTerminator());
+ new StoreInst(newSrc, Alloca, EntryBB->getTerminator());
if (BB.getTerminator()) {
newSrc = new LoadInst(Ty, Alloca, /*ArrLen,*/ "L", BB.getTerminator());
} else {
@@ -259,106 +119,48 @@ static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
if (OperandNo >= 1)
return false;
break;
- case Instruction::Call:
- case Instruction::Invoke:
- case Instruction::CallBr: {
- const CallBase *II = cast<CallBase>(I);
- const Function *Callee = II->getCalledFunction();
- return !Callee->hasParamAttribute(OperandNo, Attribute::ImmArg);
- }
default:
break;
}
return true;
}
-Instruction *RandomIRBuilder::connectToSink(BasicBlock &BB,
- ArrayRef<Instruction *> Insts,
- Value *V) {
- SmallVector<uint64_t, 8> SinkTys;
- for (uint64_t i = 0; i < EndOfValueSink; i++)
- SinkTys.push_back(i);
- std::shuffle(SinkTys.begin(), SinkTys.end(), Rand);
- auto findSinkAndConnect =
- [this, V](ArrayRef<Instruction *> Instructions) -> Instruction * {
- auto RS = makeSampler<Use *>(Rand);
- for (auto &I : Instructions) {
- for (Use &U : I->operands())
- if (isCompatibleReplacement(I, U, V))
- RS.sample(&U, 1);
- }
- if (!RS.isEmpty()) {
- Use *Sink = RS.getSelection();
- User *U = Sink->getUser();
- unsigned OpNo = Sink->getOperandNo();
- U->setOperand(OpNo, V);
- return cast<Instruction>(U);
- }
- return nullptr;
- };
- Instruction *Sink = nullptr;
- for (uint64_t SinkTy : SinkTys) {
- switch (SinkTy) {
- case SinkToInstInCurBlock:
- Sink = findSinkAndConnect(Insts);
- if (Sink)
- return Sink;
- break;
- case PointersInDominator: {
- auto Dominators = getDominators(&BB);
- std::shuffle(Dominators.begin(), Dominators.end(), Rand);
- for (BasicBlock *Dom : Dominators) {
- for (Instruction &I : *Dom) {
- if (PointerType *PtrTy = dyn_cast<PointerType>(I.getType()))
- return new StoreInst(V, &I, Insts.back());
- }
- }
- break;
- }
- case InstInDominatee: {
- auto Dominatees = getDominatees(&BB);
- std::shuffle(Dominatees.begin(), Dominatees.end(), Rand);
- for (BasicBlock *Dominee : Dominatees) {
- std::vector<Instruction *> Instructions;
- for (Instruction &I : *Dominee)
- Instructions.push_back(&I);
- Sink = findSinkAndConnect(Instructions);
- if (Sink) {
- return Sink;
- }
- }
- break;
- }
- case NewStore:
- /// TODO: allocate a new stack memory.
- return newSink(BB, Insts, V);
- case SinkToGlobalVariable: {
- Module *M = BB.getParent()->getParent();
- auto [GV, DidCreate] =
- findOrCreateGlobalVariable(M, {}, fuzzerop::onlyType(V->getType()));
- return new StoreInst(V, GV, Insts.back());
- }
- case EndOfValueSink:
- default:
- llvm_unreachable("EndOfValueSink executed");
- }
+void RandomIRBuilder::connectToSink(BasicBlock &BB,
+ ArrayRef<Instruction *> Insts, Value *V) {
+ auto RS = makeSampler<Use *>(Rand);
+ for (auto &I : Insts) {
+ if (isa<IntrinsicInst>(I))
+ // TODO: Replacing operands of intrinsics would be interesting, but
+ // there's no easy way to verify that a given replacement is valid given
+ // that intrinsics can impose arbitrary constraints.
+ continue;
+ for (Use &U : I->operands())
+ if (isCompatibleReplacement(I, U, V))
+ RS.sample(&U, 1);
}
- llvm_unreachable("Can't find a sink");
+ // Also consider choosing no sink, meaning we want a new one.
+ RS.sample(nullptr, /*Weight=*/1);
+
+ if (Use *Sink = RS.getSelection()) {
+ User *U = Sink->getUser();
+ unsigned OpNo = Sink->getOperandNo();
+ U->setOperand(OpNo, V);
+ return;
+ }
+ newSink(BB, Insts, V);
}
-Instruction *RandomIRBuilder::newSink(BasicBlock &BB,
- ArrayRef<Instruction *> Insts, Value *V) {
+void RandomIRBuilder::newSink(BasicBlock &BB, ArrayRef<Instruction *> Insts,
+ Value *V) {
Value *Ptr = findPointer(BB, Insts, {V}, matchFirstType());
if (!Ptr) {
- if (uniform(Rand, 0, 1)) {
- Type *Ty = V->getType();
- Ptr = createStackMemory(BB.getParent(), Ty, UndefValue::get(Ty));
- } else {
+ if (uniform(Rand, 0, 1))
+ Ptr = new AllocaInst(V->getType(), 0, "A", &*BB.getFirstInsertionPt());
+ else
Ptr = UndefValue::get(PointerType::get(V->getType(), 0));
- }
}
- return new StoreInst(V, Ptr, Insts.back());
+ new StoreInst(V, Ptr, Insts.back());
}
Value *RandomIRBuilder::findPointer(BasicBlock &BB,
diff --git a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
index 3a1f91ad61ae4..89bb42c254470 100644
--- a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
+++ b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp
@@ -15,7 +15,6 @@
#include "llvm/FuzzMutate/Operations.h"
#include "llvm/FuzzMutate/Random.h"
#include "llvm/IR/Constants.h"
-#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -99,8 +98,8 @@ TEST(RandomIRBuilderTest, InsertValueIndexes) {
fuzzerop::OpDescriptor IVDescr = fuzzerop::insertValueDescriptor(1);
- std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
- Type::getInt64Ty(Ctx)};
+ std::vector<Type *> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
+ Type::getInt64Ty(Ctx)};
RandomIRBuilder IB(Seed, Types);
// Get first basic block of the first function
@@ -177,8 +176,8 @@ TEST(RandomIRBuilderTest, InsertValueArray) {
fuzzerop::OpDescriptor Descr = fuzzerop::insertValueDescriptor(1);
- std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
- Type::getInt64Ty(Ctx)};
+ std::vector<Type *> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
+ Type::getInt64Ty(Ctx)};
RandomIRBuilder IB(Seed, Types);
// Get first basic block of the first function
@@ -218,7 +217,7 @@ TEST(RandomIRBuilderTest, Invokes) {
"}";
auto M = parseAssembly(SourceCode, Ctx);
- std::array<Type *, 1> Types = {Type::getInt8Ty(Ctx)};
+ std::vector<Type *> Types = {Type::getInt8Ty(Ctx)};
RandomIRBuilder IB(Seed, Types);
// Get first basic block of the test function
@@ -234,39 +233,6 @@ TEST(RandomIRBuilderTest, Invokes) {
}
}
-TEST(RandomIRBuilderTest, FirstClassTypes) {
- // Check that we never insert new source as a load from non first class
- // or unsized type.
-
- LLVMContext Ctx;
- const char *SourceCode = "%Opaque = type opaque\n"
- "define void @test(i8* %ptr) {\n"
- "entry:\n"
- " %tmp = bitcast i8* %ptr to i32* (i32*)*\n"
- " %tmp1 = bitcast i8* %ptr to %Opaque*\n"
- " ret void\n"
- "}";
- auto M = parseAssembly(SourceCode, Ctx);
-
- std::array<Type *, 1> Types = {Type::getInt8Ty(Ctx)};
- RandomIRBuilder IB(Seed, Types);
-
- Function &F = *M->getFunction("test");
- BasicBlock &BB = *F.begin();
- // Non first class type
- Instruction *FuncPtr = &*BB.begin();
- // Unsized type
- Instruction *OpaquePtr = &*std::next(BB.begin());
-
- for (int i = 0; i < 10; ++i) {
- Value *V = IB.findOrCreateSource(BB, {FuncPtr, OpaquePtr});
- // To make sure we are allowed to load from a global variable
- if (LoadInst *LI = dyn_cast<LoadInst>(V)) {
- EXPECT_NE(LI->getOperand(0), FuncPtr);
- }
- }
-}
-
TEST(RandomIRBuilderTest, SwiftError) {
// Check that we never pick swifterror value as a source for operation
// other than load, store and call.
@@ -281,7 +247,7 @@ TEST(RandomIRBuilderTest, SwiftError) {
"}";
auto M = parseAssembly(SourceCode, Ctx);
- std::array<Type *, 1> Types = {Type::getInt8Ty(Ctx)};
+ std::vector<Type *> Types = {Type::getInt8Ty(Ctx)};
RandomIRBuilder IB(Seed, Types);
// Get first basic block of the test function
@@ -321,7 +287,7 @@ TEST(RandomIRBuilderTest, dontConnectToSwitch) {
ret void \n\
}";
- std::array<Type *, 2> Types = {Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)};
+ std::vector<Type *> Types = {Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)};
RandomIRBuilder IB(Seed, Types);
for (int i = 0; i < 20; i++) {
std::unique_ptr<Module> M = parseAssembly(SourceCode, Ctx);
@@ -342,228 +308,4 @@ TEST(RandomIRBuilderTest, dontConnectToSwitch) {
}
}
-TEST(RandomIRBuilderTest, createStackMemory) {
- LLVMContext Ctx;
- const char *SourceCode = "\n\
- define void @test(i1 %C1, i1 %C2, i32 %I, i32 %J) { \n\
- Entry: \n\
- ret void \n\
- }";
- Type *Int32Ty = Type::getInt32Ty(Ctx);
- Constant *Int32_1 = ConstantInt::get(Int32Ty, APInt(32, 1));
- Type *Int64Ty = Type::getInt64Ty(Ctx);
- Constant *Int64_42 = ConstantInt::get(Int64Ty, APInt(64, 42));
- Type *DoubleTy = Type::getDoubleTy(Ctx);
- Constant *Double_0 =
- ConstantFP::get(Ctx, APFloat::getZero(DoubleTy->getFltSemantics()));
- std::array<Type *, 8> Types = {
- Int32Ty,
- Int64Ty,
- DoubleTy,
- PointerType::get(Ctx, 0),
- PointerType::get(Int32Ty, 0),
- VectorType::get(Int32Ty, 4, false),
- StructType::create({Int32Ty, DoubleTy, Int64Ty}),
- ArrayType::get(Int64Ty, 4),
- };
- std::array<Value *, 8> Inits = {
- Int32_1,
- Int64_42,
- Double_0,
- UndefValue::get(Types[3]),
- UndefValue::get(Types[4]),
- ConstantVector::get({Int32_1, Int32_1, Int32_1, Int32_1}),
- ConstantStruct::get(cast<StructType>(Types[6]),
- {Int32_1, Double_0, Int64_42}),
- ConstantArray::get(cast<ArrayType>(Types[7]),
- {Int64_42, Int64_42, Int64_42, Int64_42}),
- };
- ASSERT_EQ(Types.size(), Inits.size());
- unsigned NumTests = Types.size();
- RandomIRBuilder IB(Seed, Types);
- auto CreateStackMemoryAndVerify = [&Ctx, &SourceCode, &IB](Type *Ty,
- Value *Init) {
- std::unique_ptr<Module> M = parseAssembly(SourceCode, Ctx);
- Function &F = *M->getFunction("test");
- // Create stack memory without initializer.
- IB.createStackMemory(&F, Ty, nullptr);
- // Create stack memory with initializer.
- IB.createStackMemory(&F, Ty, Init);
- EXPECT_FALSE(verifyModule(*M, &errs()));
- };
- for (unsigned i = 0; i < NumTests; i++) {
- CreateStackMemoryAndVerify(Types[i], Inits[i]);
- }
-}
-
-TEST(RandomIRBuilderTest, findOrCreateGlobalVariable) {
- LLVMContext Ctx;
- const char *SourceCode = "\n\
- @G0 = external global i16 \n\
- @G1 = global i32 1 \n\
- ";
- std::array<Type *, 3> Types = {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx),
- Type::getInt64Ty(Ctx)};
- RandomIRBuilder IB(Seed, Types);
-
- // Find external global
- std::unique_ptr<Module> M0 = parseAssembly(SourceCode, Ctx);
- Type *ExternalTy = M0->globals().begin()->getValueType();
- ASSERT_TRUE(ExternalTy->isIntegerTy(16));
- IB.findOrCreateGlobalVariable(&*M0, {}, fuzzerop::onlyType(Types[0]));
- ASSERT_FALSE(verifyModule(*M0, &errs()));
- unsigned NumGV0 = M0->getNumNamedValues();
- auto [GV0, DidCreate0] =
- IB.findOrCreateGlobalVariable(&*M0, {}, fuzzerop::onlyType(Types[0]));
- ASSERT_FALSE(verifyModule(*M0, &errs()));
- ASSERT_EQ(M0->getNumNamedValues(), NumGV0 + DidCreate0);
-
- // Find existing global
- std::unique_ptr<Module> M1 = parseAssembly(SourceCode, Ctx);
- IB.findOrCreateGlobalVariable(&*M1, {}, fuzzerop::onlyType(Types[1]));
- ASSERT_FALSE(verifyModule(*M1, &errs()));
- unsigned NumGV1 = M1->getNumNamedValues();
- auto [GV1, DidCreate1] =
- IB.findOrCreateGlobalVariable(&*M1, {}, fuzzerop::onlyType(Types[1]));
- ASSERT_FALSE(verifyModule(*M1, &errs()));
- ASSERT_EQ(M1->getNumNamedValues(), NumGV1 + DidCreate1);
-
- // Create new global
- std::unique_ptr<Module> M2 = parseAssembly(SourceCode, Ctx);
- auto [GV2, DidCreate2] =
- IB.findOrCreateGlobalVariable(&*M2, {}, fuzzerop::onlyType(Types[2]));
- ASSERT_FALSE(verifyModule(*M2, &errs()));
- ASSERT_TRUE(DidCreate2);
-}
-
-/// Checks if the source and sink we find for an instruction has correct
-/// domination relation.
-TEST(RandomIRBuilderTest, findSourceAndSink) {
- const char *Source = "\n\
- define i64 @test(i1 %0, i1 %1, i1 %2, i32 %3, i32 %4) { \n\
- Entry: \n\
- %A = alloca i32, i32 8, align 4 \n\
- %E.1 = and i32 %3, %4 \n\
- %E.2 = add i32 %4 , 1 \n\
- %A.GEP.1 = getelementptr i32, ptr %A, i32 0 \n\
- %A.GEP.2 = getelementptr i32, ptr %A.GEP.1, i32 1 \n\
- %L.2 = load i32, ptr %A.GEP.2 \n\
- %L.1 = load i32, ptr %A.GEP.1 \n\
- %E.3 = sub i32 %E.2, %L.1 \n\
- %Cond.1 = icmp eq i32 %E.3, %E.2 \n\
- %Cond.2 = and i1 %0, %1 \n\
- %Cond = or i1 %Cond.1, %Cond.2 \n\
- br i1 %Cond, label %BB0, label %BB1 \n\
- BB0: \n\
- %Add = add i32 %L.1, %L.2 \n\
- %Sub = sub i32 %L.1, %L.2 \n\
- %Sub.1 = sub i32 %Sub, 12 \n\
- %Cast.1 = bitcast i32 %4 to float \n\
- %Add.2 = add i32 %3, 1 \n\
- %Cast.2 = bitcast i32 %Add.2 to float \n\
- %FAdd = fadd float %Cast.1, %Cast.2 \n\
- %Add.3 = add i32 %L.2, %L.1 \n\
- %Cast.3 = bitcast float %FAdd to i32 \n\
- %Sub.2 = sub i32 %Cast.3, %Sub.1 \n\
- %SExt = sext i32 %Cast.3 to i64 \n\
- %A.GEP.3 = getelementptr i64, ptr %A, i32 1 \n\
- store i64 %SExt, ptr %A.GEP.3 \n\
- br label %Exit \n\
- BB1: \n\
- %PHI.1 = phi i32 [0, %Entry] \n\
- %SExt.1 = sext i1 %Cond.2 to i32 \n\
- %SExt.2 = sext i1 %Cond.1 to i32 \n\
- %E.164 = zext i32 %E.1 to i64 \n\
- %E.264 = zext i32 %E.2 to i64 \n\
- %E.1264 = mul i64 %E.164, %E.264 \n\
- %E.12 = trunc i64 %E.1264 to i32 \n\
- %A.GEP.4 = getelementptr i32, ptr %A, i32 2 \n\
- %A.GEP.5 = getelementptr i32, ptr %A.GEP.4, i32 2 \n\
- store i32 %E.12, ptr %A.GEP.5 \n\
- br label %Exit \n\
- Exit: \n\
- %PHI.2 = phi i32 [%Add, %BB0], [%E.3, %BB1] \n\
- %PHI.3 = phi i64 [%SExt, %BB0], [%E.1264, %BB1] \n\
- %ZExt = zext i32 %PHI.2 to i64 \n\
- %Add.5 = add i64 %PHI.3, 3 \n\
- ret i64 %Add.5 \n\
- }";
- LLVMContext Ctx;
- std::array<Type *, 3> Types = {Type::getInt1Ty(Ctx), Type::getInt32Ty(Ctx),
- Type::getInt64Ty(Ctx)};
- std::mt19937 mt(Seed);
- std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
-
- // Get a random instruction, try to find source and sink, make sure it is
- // dominated.
- for (int i = 0; i < 100; i++) {
- RandomIRBuilder IB(RandInt(mt), Types);
- std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
- Function &F = *M->getFunction("test");
- DominatorTree DT(F);
- BasicBlock *BB = makeSampler(IB.Rand, make_pointer_range(F)).getSelection();
- SmallVector<Instruction *, 32> Insts;
- for (auto I = BB->getFirstInsertionPt(), E = BB->end(); I != E; ++I)
- Insts.push_back(&*I);
- // Choose an insertion point for our new instruction.
- size_t IP = uniform<size_t>(IB.Rand, 1, Insts.size() - 2);
-
- auto InstsBefore = ArrayRef(Insts).slice(0, IP);
- auto InstsAfter = ArrayRef(Insts).slice(IP);
- Value *Src = IB.findOrCreateSource(
- *BB, InstsBefore, {}, fuzzerop::onlyType(Types[i % Types.size()]));
- ASSERT_TRUE(DT.dominates(Src, Insts[IP + 1]));
- Instruction *Sink = IB.connectToSink(*BB, InstsAfter, Insts[IP - 1]);
- if (!DT.dominates(Insts[IP - 1], Sink)) {
- errs() << *Insts[IP - 1] << "\n" << *Sink << "\n ";
- }
- ASSERT_TRUE(DT.dominates(Insts[IP - 1], Sink));
- }
-}
-TEST(RandomIRBuilderTest, sinkToInstrinsic) {
- const char *Source = "\n\
- declare double @llvm.sqrt.f64(double %Val) \n\
- declare void @llvm.ubsantrap(i8 immarg) cold noreturn nounwind \n\
- \n\
- define double @test(double %0, double %1, i64 %2, i64 %3, i64 %4, i8 %5) { \n\
- Entry: \n\
- %sqrt = call double @llvm.sqrt.f64(double %0) \n\
- call void @llvm.ubsantrap(i8 1) \n\
- ret double %sqrt \n\
- }";
- LLVMContext Ctx;
- std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt64Ty(Ctx),
- Type::getDoubleTy(Ctx)};
- std::mt19937 mt(Seed);
- std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
-
- RandomIRBuilder IB(RandInt(mt), Types);
- std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
- Function &F = *M->getFunction("test");
- BasicBlock &BB = F.getEntryBlock();
- bool Modified = false;
-
- Instruction *I = &*BB.begin();
- for (int i = 0; i < 20; i++) {
- Value *OldOperand = I->getOperand(0);
- Value *Src = F.getArg(1);
- IB.connectToSink(BB, {I}, Src);
- Value *NewOperand = I->getOperand(0);
- Modified |= (OldOperand != NewOperand);
- ASSERT_FALSE(verifyModule(*M, &errs()));
- }
- ASSERT_TRUE(Modified);
-
- Modified = false;
- I = I->getNextNonDebugInstruction();
- for (int i = 0; i < 20; i++) {
- Value *OldOperand = I->getOperand(0);
- Value *Src = F.getArg(5);
- IB.connectToSink(BB, {I}, Src);
- Value *NewOperand = I->getOperand(0);
- Modified |= (OldOperand != NewOperand);
- ASSERT_FALSE(verifyModule(*M, &errs()));
- }
- ASSERT_FALSE(Modified);
-}
} // namespace
More information about the llvm-commits
mailing list