mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-22 12:08:26 +00:00
e0b3c335a2
LLVM makes several assumptions about address space 0. However, alloca is presently constrained to always return this address space. There's no real way to avoid using alloca, so without this there is no way to opt out of these assumptions. The problematic assumptions include: - That the pointer size used for the stack is the same size as the code size pointer, which is also the maximum sized pointer. - That 0 is an invalid, non-dereferencable pointer value. These are problems for AMDGPU because alloca is used to implement the private address space, which uses a 32-bit index as the pointer value. Other pointers are 64-bit and behave more like LLVM's notion of generic address space. By changing the address space used for allocas, we can change our generic pointer type to be LLVM's generic pointer type which does have similar properties. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299888 91177308-0d34-0410-b5e6-96231b3b80d8
729 lines
23 KiB
C++
729 lines
23 KiB
C++
//===-- llvm-stress.cpp - Generate random LL files to stress-test LLVM ----===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This program is a utility that generates random .ll files to stress-test
|
|
// different components in LLVM.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/CallGraphSCCPass.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/LegacyPassNameParser.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/PluginLoader.h"
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
#include "llvm/Support/ToolOutputFile.h"
|
|
#include <algorithm>
|
|
#include <random>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
|
|
static cl::opt<unsigned> SeedCL("seed",
|
|
cl::desc("Seed used for randomness"), cl::init(0));
|
|
static cl::opt<unsigned> SizeCL("size",
|
|
cl::desc("The estimated size of the generated function (# of instrs)"),
|
|
cl::init(100));
|
|
static cl::opt<std::string>
|
|
OutputFilename("o", cl::desc("Override output filename"),
|
|
cl::value_desc("filename"));
|
|
|
|
static LLVMContext Context;
|
|
|
|
namespace cl {
|
|
template <> class parser<Type*> final : public basic_parser<Type*> {
|
|
public:
|
|
parser(Option &O) : basic_parser(O) {}
|
|
|
|
// Parse options as IR types. Return true on error.
|
|
bool parse(Option &O, StringRef, StringRef Arg, Type *&Value) {
|
|
if (Arg == "half") Value = Type::getHalfTy(Context);
|
|
else if (Arg == "fp128") Value = Type::getFP128Ty(Context);
|
|
else if (Arg == "x86_fp80") Value = Type::getX86_FP80Ty(Context);
|
|
else if (Arg == "ppc_fp128") Value = Type::getPPC_FP128Ty(Context);
|
|
else if (Arg == "x86_mmx") Value = Type::getX86_MMXTy(Context);
|
|
else if (Arg.startswith("i")) {
|
|
unsigned N = 0;
|
|
Arg.drop_front().getAsInteger(10, N);
|
|
if (N > 0)
|
|
Value = Type::getIntNTy(Context, N);
|
|
}
|
|
|
|
if (!Value)
|
|
return O.error("Invalid IR scalar type: '" + Arg + "'!");
|
|
return false;
|
|
}
|
|
|
|
StringRef getValueName() const override { return "IR scalar type"; }
|
|
};
|
|
}
|
|
|
|
|
|
static cl::list<Type*> AdditionalScalarTypes("types", cl::CommaSeparated,
|
|
cl::desc("Additional IR scalar types "
|
|
"(always includes i1, i8, i16, i32, i64, float and double)"));
|
|
|
|
namespace {
|
|
/// A utility class to provide a pseudo-random number generator which is
|
|
/// the same across all platforms. This is somewhat close to the libc
|
|
/// implementation. Note: This is not a cryptographically secure pseudorandom
|
|
/// number generator.
|
|
class Random {
|
|
public:
|
|
/// C'tor
|
|
Random(unsigned _seed):Seed(_seed) {}
|
|
|
|
/// Return a random integer, up to a
|
|
/// maximum of 2**19 - 1.
|
|
uint32_t Rand() {
|
|
uint32_t Val = Seed + 0x000b07a1;
|
|
Seed = (Val * 0x3c7c0ac1);
|
|
// Only lowest 19 bits are random-ish.
|
|
return Seed & 0x7ffff;
|
|
}
|
|
|
|
/// Return a random 32 bit integer.
|
|
uint32_t Rand32() {
|
|
uint32_t Val = Rand();
|
|
Val &= 0xffff;
|
|
return Val | (Rand() << 16);
|
|
}
|
|
|
|
/// Return a random 64 bit integer.
|
|
uint64_t Rand64() {
|
|
uint64_t Val = Rand32();
|
|
return Val | (uint64_t(Rand32()) << 32);
|
|
}
|
|
|
|
/// Rand operator for STL algorithms.
|
|
ptrdiff_t operator()(ptrdiff_t y) {
|
|
return Rand64() % y;
|
|
}
|
|
|
|
/// Make this like a C++11 random device
|
|
typedef uint32_t result_type;
|
|
uint32_t operator()() { return Rand32(); }
|
|
static constexpr result_type min() { return 0; }
|
|
static constexpr result_type max() { return 0x7ffff; }
|
|
|
|
private:
|
|
unsigned Seed;
|
|
};
|
|
|
|
/// Generate an empty function with a default argument list.
|
|
Function *GenEmptyFunction(Module *M) {
|
|
// Define a few arguments
|
|
LLVMContext &Context = M->getContext();
|
|
Type* ArgsTy[] = {
|
|
Type::getInt8PtrTy(Context),
|
|
Type::getInt32PtrTy(Context),
|
|
Type::getInt64PtrTy(Context),
|
|
Type::getInt32Ty(Context),
|
|
Type::getInt64Ty(Context),
|
|
Type::getInt8Ty(Context)
|
|
};
|
|
|
|
auto *FuncTy = FunctionType::get(Type::getVoidTy(Context), ArgsTy, false);
|
|
// Pick a unique name to describe the input parameters
|
|
Twine Name = "autogen_SD" + Twine{SeedCL};
|
|
auto *Func = Function::Create(FuncTy, GlobalValue::ExternalLinkage, Name, M);
|
|
Func->setCallingConv(CallingConv::C);
|
|
return Func;
|
|
}
|
|
|
|
/// A base class, implementing utilities needed for
|
|
/// modifying and adding new random instructions.
|
|
struct Modifier {
|
|
/// Used to store the randomly generated values.
|
|
typedef std::vector<Value*> PieceTable;
|
|
|
|
public:
|
|
/// C'tor
|
|
Modifier(BasicBlock *Block, PieceTable *PT, Random *R):
|
|
BB(Block),PT(PT),Ran(R),Context(BB->getContext()) {}
|
|
|
|
/// virtual D'tor to silence warnings.
|
|
virtual ~Modifier() {}
|
|
|
|
/// Add a new instruction.
|
|
virtual void Act() = 0;
|
|
/// Add N new instructions,
|
|
virtual void ActN(unsigned n) {
|
|
for (unsigned i=0; i<n; ++i)
|
|
Act();
|
|
}
|
|
|
|
protected:
|
|
/// Return a random value from the list of known values.
|
|
Value *getRandomVal() {
|
|
assert(PT->size());
|
|
return PT->at(Ran->Rand() % PT->size());
|
|
}
|
|
|
|
Constant *getRandomConstant(Type *Tp) {
|
|
if (Tp->isIntegerTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return ConstantInt::getAllOnesValue(Tp);
|
|
return ConstantInt::getNullValue(Tp);
|
|
} else if (Tp->isFloatingPointTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return ConstantFP::getAllOnesValue(Tp);
|
|
return ConstantFP::getNullValue(Tp);
|
|
}
|
|
return UndefValue::get(Tp);
|
|
}
|
|
|
|
/// Return a random value with a known type.
|
|
Value *getRandomValue(Type *Tp) {
|
|
unsigned index = Ran->Rand();
|
|
for (unsigned i=0; i<PT->size(); ++i) {
|
|
Value *V = PT->at((index + i) % PT->size());
|
|
if (V->getType() == Tp)
|
|
return V;
|
|
}
|
|
|
|
// If the requested type was not found, generate a constant value.
|
|
if (Tp->isIntegerTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return ConstantInt::getAllOnesValue(Tp);
|
|
return ConstantInt::getNullValue(Tp);
|
|
} else if (Tp->isFloatingPointTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return ConstantFP::getAllOnesValue(Tp);
|
|
return ConstantFP::getNullValue(Tp);
|
|
} else if (Tp->isVectorTy()) {
|
|
VectorType *VTp = cast<VectorType>(Tp);
|
|
|
|
std::vector<Constant*> TempValues;
|
|
TempValues.reserve(VTp->getNumElements());
|
|
for (unsigned i = 0; i < VTp->getNumElements(); ++i)
|
|
TempValues.push_back(getRandomConstant(VTp->getScalarType()));
|
|
|
|
ArrayRef<Constant*> VectorValue(TempValues);
|
|
return ConstantVector::get(VectorValue);
|
|
}
|
|
|
|
return UndefValue::get(Tp);
|
|
}
|
|
|
|
/// Return a random value of any pointer type.
|
|
Value *getRandomPointerValue() {
|
|
unsigned index = Ran->Rand();
|
|
for (unsigned i=0; i<PT->size(); ++i) {
|
|
Value *V = PT->at((index + i) % PT->size());
|
|
if (V->getType()->isPointerTy())
|
|
return V;
|
|
}
|
|
return UndefValue::get(pickPointerType());
|
|
}
|
|
|
|
/// Return a random value of any vector type.
|
|
Value *getRandomVectorValue() {
|
|
unsigned index = Ran->Rand();
|
|
for (unsigned i=0; i<PT->size(); ++i) {
|
|
Value *V = PT->at((index + i) % PT->size());
|
|
if (V->getType()->isVectorTy())
|
|
return V;
|
|
}
|
|
return UndefValue::get(pickVectorType());
|
|
}
|
|
|
|
/// Pick a random type.
|
|
Type *pickType() {
|
|
return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType());
|
|
}
|
|
|
|
/// Pick a random pointer type.
|
|
Type *pickPointerType() {
|
|
Type *Ty = pickType();
|
|
return PointerType::get(Ty, 0);
|
|
}
|
|
|
|
/// Pick a random vector type.
|
|
Type *pickVectorType(unsigned len = (unsigned)-1) {
|
|
// Pick a random vector width in the range 2**0 to 2**4.
|
|
// by adding two randoms we are generating a normal-like distribution
|
|
// around 2**3.
|
|
unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3));
|
|
Type *Ty;
|
|
|
|
// Vectors of x86mmx are illegal; keep trying till we get something else.
|
|
do {
|
|
Ty = pickScalarType();
|
|
} while (Ty->isX86_MMXTy());
|
|
|
|
if (len != (unsigned)-1)
|
|
width = len;
|
|
return VectorType::get(Ty, width);
|
|
}
|
|
|
|
/// Pick a random scalar type.
|
|
Type *pickScalarType() {
|
|
static std::vector<Type*> ScalarTypes;
|
|
if (ScalarTypes.empty()) {
|
|
ScalarTypes.assign({
|
|
Type::getInt1Ty(Context),
|
|
Type::getInt8Ty(Context),
|
|
Type::getInt16Ty(Context),
|
|
Type::getInt32Ty(Context),
|
|
Type::getInt64Ty(Context),
|
|
Type::getFloatTy(Context),
|
|
Type::getDoubleTy(Context)
|
|
});
|
|
ScalarTypes.insert(ScalarTypes.end(),
|
|
AdditionalScalarTypes.begin(), AdditionalScalarTypes.end());
|
|
}
|
|
|
|
return ScalarTypes[Ran->Rand() % ScalarTypes.size()];
|
|
}
|
|
|
|
/// Basic block to populate
|
|
BasicBlock *BB;
|
|
/// Value table
|
|
PieceTable *PT;
|
|
/// Random number generator
|
|
Random *Ran;
|
|
/// Context
|
|
LLVMContext &Context;
|
|
};
|
|
|
|
struct LoadModifier: public Modifier {
|
|
LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
// Try to use predefined pointers. If non-exist, use undef pointer value;
|
|
Value *Ptr = getRandomPointerValue();
|
|
Value *V = new LoadInst(Ptr, "L", BB->getTerminator());
|
|
PT->push_back(V);
|
|
}
|
|
};
|
|
|
|
struct StoreModifier: public Modifier {
|
|
StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
// Try to use predefined pointers. If non-exist, use undef pointer value;
|
|
Value *Ptr = getRandomPointerValue();
|
|
Type *Tp = Ptr->getType();
|
|
Value *Val = getRandomValue(Tp->getContainedType(0));
|
|
Type *ValTy = Val->getType();
|
|
|
|
// Do not store vectors of i1s because they are unsupported
|
|
// by the codegen.
|
|
if (ValTy->isVectorTy() && ValTy->getScalarSizeInBits() == 1)
|
|
return;
|
|
|
|
new StoreInst(Val, Ptr, BB->getTerminator());
|
|
}
|
|
};
|
|
|
|
struct BinModifier: public Modifier {
|
|
BinModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
|
|
void Act() override {
|
|
Value *Val0 = getRandomVal();
|
|
Value *Val1 = getRandomValue(Val0->getType());
|
|
|
|
// Don't handle pointer types.
|
|
if (Val0->getType()->isPointerTy() ||
|
|
Val1->getType()->isPointerTy())
|
|
return;
|
|
|
|
// Don't handle i1 types.
|
|
if (Val0->getType()->getScalarSizeInBits() == 1)
|
|
return;
|
|
|
|
|
|
bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy();
|
|
Instruction* Term = BB->getTerminator();
|
|
unsigned R = Ran->Rand() % (isFloat ? 7 : 13);
|
|
Instruction::BinaryOps Op;
|
|
|
|
switch (R) {
|
|
default: llvm_unreachable("Invalid BinOp");
|
|
case 0:{Op = (isFloat?Instruction::FAdd : Instruction::Add); break; }
|
|
case 1:{Op = (isFloat?Instruction::FSub : Instruction::Sub); break; }
|
|
case 2:{Op = (isFloat?Instruction::FMul : Instruction::Mul); break; }
|
|
case 3:{Op = (isFloat?Instruction::FDiv : Instruction::SDiv); break; }
|
|
case 4:{Op = (isFloat?Instruction::FDiv : Instruction::UDiv); break; }
|
|
case 5:{Op = (isFloat?Instruction::FRem : Instruction::SRem); break; }
|
|
case 6:{Op = (isFloat?Instruction::FRem : Instruction::URem); break; }
|
|
case 7: {Op = Instruction::Shl; break; }
|
|
case 8: {Op = Instruction::LShr; break; }
|
|
case 9: {Op = Instruction::AShr; break; }
|
|
case 10:{Op = Instruction::And; break; }
|
|
case 11:{Op = Instruction::Or; break; }
|
|
case 12:{Op = Instruction::Xor; break; }
|
|
}
|
|
|
|
PT->push_back(BinaryOperator::Create(Op, Val0, Val1, "B", Term));
|
|
}
|
|
};
|
|
|
|
/// Generate constant values.
|
|
struct ConstModifier: public Modifier {
|
|
ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
Type *Ty = pickType();
|
|
|
|
if (Ty->isVectorTy()) {
|
|
switch (Ran->Rand() % 2) {
|
|
case 0: if (Ty->getScalarType()->isIntegerTy())
|
|
return PT->push_back(ConstantVector::getAllOnesValue(Ty));
|
|
case 1: if (Ty->getScalarType()->isIntegerTy())
|
|
return PT->push_back(ConstantVector::getNullValue(Ty));
|
|
}
|
|
}
|
|
|
|
if (Ty->isFloatingPointTy()) {
|
|
// Generate 128 random bits, the size of the (currently)
|
|
// largest floating-point types.
|
|
uint64_t RandomBits[2];
|
|
for (unsigned i = 0; i < 2; ++i)
|
|
RandomBits[i] = Ran->Rand64();
|
|
|
|
APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits));
|
|
APFloat RandomFloat(Ty->getFltSemantics(), RandomInt);
|
|
|
|
if (Ran->Rand() & 1)
|
|
return PT->push_back(ConstantFP::getNullValue(Ty));
|
|
return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat));
|
|
}
|
|
|
|
if (Ty->isIntegerTy()) {
|
|
switch (Ran->Rand() % 7) {
|
|
case 0: if (Ty->isIntegerTy())
|
|
return PT->push_back(ConstantInt::get(Ty,
|
|
APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits())));
|
|
case 1: if (Ty->isIntegerTy())
|
|
return PT->push_back(ConstantInt::get(Ty,
|
|
APInt::getNullValue(Ty->getPrimitiveSizeInBits())));
|
|
case 2: case 3: case 4: case 5:
|
|
case 6: if (Ty->isIntegerTy())
|
|
PT->push_back(ConstantInt::get(Ty, Ran->Rand()));
|
|
}
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
struct AllocaModifier: public Modifier {
|
|
AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R){}
|
|
|
|
void Act() override {
|
|
Type *Tp = pickType();
|
|
const DataLayout &DL = BB->getModule()->getDataLayout();
|
|
PT->push_back(new AllocaInst(Tp, DL.getAllocaAddrSpace(),
|
|
"A", BB->getFirstNonPHI()));
|
|
}
|
|
};
|
|
|
|
struct ExtractElementModifier: public Modifier {
|
|
ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R):
|
|
Modifier(BB, PT, R) {}
|
|
|
|
void Act() override {
|
|
Value *Val0 = getRandomVectorValue();
|
|
Value *V = ExtractElementInst::Create(Val0,
|
|
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
|
|
Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
|
|
"E", BB->getTerminator());
|
|
return PT->push_back(V);
|
|
}
|
|
};
|
|
|
|
struct ShuffModifier: public Modifier {
|
|
ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
|
|
Value *Val0 = getRandomVectorValue();
|
|
Value *Val1 = getRandomValue(Val0->getType());
|
|
|
|
unsigned Width = cast<VectorType>(Val0->getType())->getNumElements();
|
|
std::vector<Constant*> Idxs;
|
|
|
|
Type *I32 = Type::getInt32Ty(BB->getContext());
|
|
for (unsigned i=0; i<Width; ++i) {
|
|
Constant *CI = ConstantInt::get(I32, Ran->Rand() % (Width*2));
|
|
// Pick some undef values.
|
|
if (!(Ran->Rand() % 5))
|
|
CI = UndefValue::get(I32);
|
|
Idxs.push_back(CI);
|
|
}
|
|
|
|
Constant *Mask = ConstantVector::get(Idxs);
|
|
|
|
Value *V = new ShuffleVectorInst(Val0, Val1, Mask, "Shuff",
|
|
BB->getTerminator());
|
|
PT->push_back(V);
|
|
}
|
|
};
|
|
|
|
struct InsertElementModifier: public Modifier {
|
|
InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R):
|
|
Modifier(BB, PT, R) {}
|
|
|
|
void Act() override {
|
|
Value *Val0 = getRandomVectorValue();
|
|
Value *Val1 = getRandomValue(Val0->getType()->getScalarType());
|
|
|
|
Value *V = InsertElementInst::Create(Val0, Val1,
|
|
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
|
|
Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
|
|
"I", BB->getTerminator());
|
|
return PT->push_back(V);
|
|
}
|
|
|
|
};
|
|
|
|
struct CastModifier: public Modifier {
|
|
CastModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
|
|
Value *V = getRandomVal();
|
|
Type *VTy = V->getType();
|
|
Type *DestTy = pickScalarType();
|
|
|
|
// Handle vector casts vectors.
|
|
if (VTy->isVectorTy()) {
|
|
VectorType *VecTy = cast<VectorType>(VTy);
|
|
DestTy = pickVectorType(VecTy->getNumElements());
|
|
}
|
|
|
|
// no need to cast.
|
|
if (VTy == DestTy) return;
|
|
|
|
// Pointers:
|
|
if (VTy->isPointerTy()) {
|
|
if (!DestTy->isPointerTy())
|
|
DestTy = PointerType::get(DestTy, 0);
|
|
return PT->push_back(
|
|
new BitCastInst(V, DestTy, "PC", BB->getTerminator()));
|
|
}
|
|
|
|
unsigned VSize = VTy->getScalarType()->getPrimitiveSizeInBits();
|
|
unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits();
|
|
|
|
// Generate lots of bitcasts.
|
|
if ((Ran->Rand() & 1) && VSize == DestSize) {
|
|
return PT->push_back(
|
|
new BitCastInst(V, DestTy, "BC", BB->getTerminator()));
|
|
}
|
|
|
|
// Both types are integers:
|
|
if (VTy->getScalarType()->isIntegerTy() &&
|
|
DestTy->getScalarType()->isIntegerTy()) {
|
|
if (VSize > DestSize) {
|
|
return PT->push_back(
|
|
new TruncInst(V, DestTy, "Tr", BB->getTerminator()));
|
|
} else {
|
|
assert(VSize < DestSize && "Different int types with the same size?");
|
|
if (Ran->Rand() & 1)
|
|
return PT->push_back(
|
|
new ZExtInst(V, DestTy, "ZE", BB->getTerminator()));
|
|
return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator()));
|
|
}
|
|
}
|
|
|
|
// Fp to int.
|
|
if (VTy->getScalarType()->isFloatingPointTy() &&
|
|
DestTy->getScalarType()->isIntegerTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return PT->push_back(
|
|
new FPToSIInst(V, DestTy, "FC", BB->getTerminator()));
|
|
return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator()));
|
|
}
|
|
|
|
// Int to fp.
|
|
if (VTy->getScalarType()->isIntegerTy() &&
|
|
DestTy->getScalarType()->isFloatingPointTy()) {
|
|
if (Ran->Rand() & 1)
|
|
return PT->push_back(
|
|
new SIToFPInst(V, DestTy, "FC", BB->getTerminator()));
|
|
return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator()));
|
|
|
|
}
|
|
|
|
// Both floats.
|
|
if (VTy->getScalarType()->isFloatingPointTy() &&
|
|
DestTy->getScalarType()->isFloatingPointTy()) {
|
|
if (VSize > DestSize) {
|
|
return PT->push_back(
|
|
new FPTruncInst(V, DestTy, "Tr", BB->getTerminator()));
|
|
} else if (VSize < DestSize) {
|
|
return PT->push_back(
|
|
new FPExtInst(V, DestTy, "ZE", BB->getTerminator()));
|
|
}
|
|
// If VSize == DestSize, then the two types must be fp128 and ppc_fp128,
|
|
// for which there is no defined conversion. So do nothing.
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
struct SelectModifier: public Modifier {
|
|
SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R):
|
|
Modifier(BB, PT, R) {}
|
|
|
|
void Act() override {
|
|
// Try a bunch of different select configuration until a valid one is found.
|
|
Value *Val0 = getRandomVal();
|
|
Value *Val1 = getRandomValue(Val0->getType());
|
|
|
|
Type *CondTy = Type::getInt1Ty(Context);
|
|
|
|
// If the value type is a vector, and we allow vector select, then in 50%
|
|
// of the cases generate a vector select.
|
|
if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) {
|
|
unsigned NumElem = cast<VectorType>(Val0->getType())->getNumElements();
|
|
CondTy = VectorType::get(CondTy, NumElem);
|
|
}
|
|
|
|
Value *Cond = getRandomValue(CondTy);
|
|
Value *V = SelectInst::Create(Cond, Val0, Val1, "Sl", BB->getTerminator());
|
|
return PT->push_back(V);
|
|
}
|
|
};
|
|
|
|
|
|
struct CmpModifier: public Modifier {
|
|
CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
|
|
void Act() override {
|
|
|
|
Value *Val0 = getRandomVal();
|
|
Value *Val1 = getRandomValue(Val0->getType());
|
|
|
|
if (Val0->getType()->isPointerTy()) return;
|
|
bool fp = Val0->getType()->getScalarType()->isFloatingPointTy();
|
|
|
|
int op;
|
|
if (fp) {
|
|
op = Ran->Rand() %
|
|
(CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) +
|
|
CmpInst::FIRST_FCMP_PREDICATE;
|
|
} else {
|
|
op = Ran->Rand() %
|
|
(CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) +
|
|
CmpInst::FIRST_ICMP_PREDICATE;
|
|
}
|
|
|
|
Value *V = CmpInst::Create(fp ? Instruction::FCmp : Instruction::ICmp,
|
|
(CmpInst::Predicate)op, Val0, Val1, "Cmp",
|
|
BB->getTerminator());
|
|
return PT->push_back(V);
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
static void FillFunction(Function *F, Random &R) {
|
|
// Create a legal entry block.
|
|
BasicBlock *BB = BasicBlock::Create(F->getContext(), "BB", F);
|
|
ReturnInst::Create(F->getContext(), BB);
|
|
|
|
// Create the value table.
|
|
Modifier::PieceTable PT;
|
|
|
|
// Consider arguments as legal values.
|
|
for (auto &arg : F->args())
|
|
PT.push_back(&arg);
|
|
|
|
// List of modifiers which add new random instructions.
|
|
std::vector<std::unique_ptr<Modifier>> Modifiers;
|
|
Modifiers.emplace_back(new LoadModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new StoreModifier(BB, &PT, &R));
|
|
auto SM = Modifiers.back().get();
|
|
Modifiers.emplace_back(new ExtractElementModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new ShuffModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new InsertElementModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new BinModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new CastModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new SelectModifier(BB, &PT, &R));
|
|
Modifiers.emplace_back(new CmpModifier(BB, &PT, &R));
|
|
|
|
// Generate the random instructions
|
|
AllocaModifier{BB, &PT, &R}.ActN(5); // Throw in a few allocas
|
|
ConstModifier{BB, &PT, &R}.ActN(40); // Throw in a few constants
|
|
|
|
for (unsigned i = 0; i < SizeCL / Modifiers.size(); ++i)
|
|
for (auto &Mod : Modifiers)
|
|
Mod->Act();
|
|
|
|
SM->ActN(5); // Throw in a few stores.
|
|
}
|
|
|
|
static void IntroduceControlFlow(Function *F, Random &R) {
|
|
std::vector<Instruction*> BoolInst;
|
|
for (auto &Instr : F->front()) {
|
|
if (Instr.getType() == IntegerType::getInt1Ty(F->getContext()))
|
|
BoolInst.push_back(&Instr);
|
|
}
|
|
|
|
std::shuffle(BoolInst.begin(), BoolInst.end(), R);
|
|
|
|
for (auto *Instr : BoolInst) {
|
|
BasicBlock *Curr = Instr->getParent();
|
|
BasicBlock::iterator Loc = Instr->getIterator();
|
|
BasicBlock *Next = Curr->splitBasicBlock(Loc, "CF");
|
|
Instr->moveBefore(Curr->getTerminator());
|
|
if (Curr != &F->getEntryBlock()) {
|
|
BranchInst::Create(Curr, Next, Instr, Curr->getTerminator());
|
|
Curr->getTerminator()->eraseFromParent();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
using namespace llvm;
|
|
|
|
// Init LLVM, call llvm_shutdown() on exit, parse args, etc.
|
|
PrettyStackTraceProgram X(argc, argv);
|
|
cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n");
|
|
llvm_shutdown_obj Y;
|
|
|
|
auto M = make_unique<Module>("/tmp/autogen.bc", Context);
|
|
Function *F = GenEmptyFunction(M.get());
|
|
|
|
// Pick an initial seed value
|
|
Random R(SeedCL);
|
|
// Generate lots of random instructions inside a single basic block.
|
|
FillFunction(F, R);
|
|
// Break the basic block into many loops.
|
|
IntroduceControlFlow(F, R);
|
|
|
|
// Figure out what stream we are supposed to write to...
|
|
std::unique_ptr<tool_output_file> Out;
|
|
// Default to standard output.
|
|
if (OutputFilename.empty())
|
|
OutputFilename = "-";
|
|
|
|
std::error_code EC;
|
|
Out.reset(new tool_output_file(OutputFilename, EC, sys::fs::F_None));
|
|
if (EC) {
|
|
errs() << EC.message() << '\n';
|
|
return 1;
|
|
}
|
|
|
|
legacy::PassManager Passes;
|
|
Passes.add(createVerifierPass());
|
|
Passes.add(createPrintModulePass(Out->os()));
|
|
Passes.run(*M.get());
|
|
Out->keep();
|
|
|
|
return 0;
|
|
}
|