| 1 | //===- llvm-stress.cpp - Generate random LL files to stress-test LLVM -----===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This program is a utility that generates random .ll files to stress-test |
| 10 | // different components in LLVM. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "llvm/ADT/APFloat.h" |
| 15 | #include "llvm/ADT/APInt.h" |
| 16 | #include "llvm/ADT/ArrayRef.h" |
| 17 | #include "llvm/ADT/STLExtras.h" |
| 18 | #include "llvm/ADT/StringRef.h" |
| 19 | #include "llvm/ADT/Twine.h" |
| 20 | #include "llvm/IR/BasicBlock.h" |
| 21 | #include "llvm/IR/CallingConv.h" |
| 22 | #include "llvm/IR/Constants.h" |
| 23 | #include "llvm/IR/DataLayout.h" |
| 24 | #include "llvm/IR/DerivedTypes.h" |
| 25 | #include "llvm/IR/Function.h" |
| 26 | #include "llvm/IR/GlobalValue.h" |
| 27 | #include "llvm/IR/InstrTypes.h" |
| 28 | #include "llvm/IR/Instruction.h" |
| 29 | #include "llvm/IR/Instructions.h" |
| 30 | #include "llvm/IR/LLVMContext.h" |
| 31 | #include "llvm/IR/Module.h" |
| 32 | #include "llvm/IR/Type.h" |
| 33 | #include "llvm/IR/Value.h" |
| 34 | #include "llvm/IR/Verifier.h" |
| 35 | #include "llvm/Support/Casting.h" |
| 36 | #include "llvm/Support/CommandLine.h" |
| 37 | #include "llvm/Support/ErrorHandling.h" |
| 38 | #include "llvm/Support/FileSystem.h" |
| 39 | #include "llvm/Support/InitLLVM.h" |
| 40 | #include "llvm/Support/ToolOutputFile.h" |
| 41 | #include "llvm/Support/WithColor.h" |
| 42 | #include "llvm/Support/raw_ostream.h" |
| 43 | #include <algorithm> |
| 44 | #include <cassert> |
| 45 | #include <cstddef> |
| 46 | #include <cstdint> |
| 47 | #include <memory> |
| 48 | #include <string> |
| 49 | #include <system_error> |
| 50 | #include <vector> |
| 51 | |
| 52 | namespace llvm { |
| 53 | |
| 54 | static cl::OptionCategory StressCategory("Stress Options" ); |
| 55 | |
| 56 | static cl::opt<unsigned> SeedCL("seed" , cl::desc("Seed used for randomness" ), |
| 57 | cl::init(Val: 0), cl::cat(StressCategory)); |
| 58 | |
| 59 | static cl::opt<unsigned> SizeCL( |
| 60 | "size" , |
| 61 | cl::desc("The estimated size of the generated function (# of instrs)" ), |
| 62 | cl::init(Val: 100), cl::cat(StressCategory)); |
| 63 | |
| 64 | static cl::opt<std::string> OutputFilename("o" , |
| 65 | cl::desc("Override output filename" ), |
| 66 | cl::value_desc("filename" ), |
| 67 | cl::cat(StressCategory)); |
| 68 | |
| 69 | static cl::list<StringRef> AdditionalScalarTypes( |
| 70 | "types" , cl::CommaSeparated, |
| 71 | cl::desc("Additional IR scalar types " |
| 72 | "(always includes i1, i8, i16, i32, i64, float and double)" )); |
| 73 | |
| 74 | static cl::opt<bool> EnableScalableVectors( |
| 75 | "enable-scalable-vectors" , |
| 76 | cl::desc("Generate IR involving scalable vector types" ), |
| 77 | cl::init(Val: false), cl::cat(StressCategory)); |
| 78 | |
| 79 | |
| 80 | namespace { |
| 81 | |
| 82 | /// A utility class to provide a pseudo-random number generator which is |
| 83 | /// the same across all platforms. This is somewhat close to the libc |
| 84 | /// implementation. Note: This is not a cryptographically secure pseudorandom |
| 85 | /// number generator. |
| 86 | class Random { |
| 87 | public: |
| 88 | /// C'tor |
| 89 | Random(unsigned _seed):Seed(_seed) {} |
| 90 | |
| 91 | /// Return a random integer, up to a |
| 92 | /// maximum of 2**19 - 1. |
| 93 | uint32_t Rand() { |
| 94 | uint32_t Val = Seed + 0x000b07a1; |
| 95 | Seed = (Val * 0x3c7c0ac1); |
| 96 | // Only lowest 19 bits are random-ish. |
| 97 | return Seed & 0x7ffff; |
| 98 | } |
| 99 | |
| 100 | /// Return a random 64 bit integer. |
| 101 | uint64_t Rand64() { |
| 102 | uint64_t Val = Rand() & 0xffff; |
| 103 | Val |= uint64_t(Rand() & 0xffff) << 16; |
| 104 | Val |= uint64_t(Rand() & 0xffff) << 32; |
| 105 | Val |= uint64_t(Rand() & 0xffff) << 48; |
| 106 | return Val; |
| 107 | } |
| 108 | |
| 109 | /// Rand operator for STL algorithms. |
| 110 | ptrdiff_t operator()(ptrdiff_t y) { |
| 111 | return Rand64() % y; |
| 112 | } |
| 113 | |
| 114 | /// Make this like a C++11 random device |
| 115 | using result_type = uint32_t ; |
| 116 | |
| 117 | static constexpr result_type min() { return 0; } |
| 118 | static constexpr result_type max() { return 0x7ffff; } |
| 119 | |
| 120 | uint32_t operator()() { |
| 121 | uint32_t Val = Rand(); |
| 122 | assert(Val <= max() && "Random value out of range" ); |
| 123 | return Val; |
| 124 | } |
| 125 | |
| 126 | private: |
| 127 | unsigned Seed; |
| 128 | }; |
| 129 | |
| 130 | /// Generate an empty function with a default argument list. |
| 131 | Function *GenEmptyFunction(Module *M) { |
| 132 | // Define a few arguments |
| 133 | LLVMContext &Context = M->getContext(); |
| 134 | Type* ArgsTy[] = { |
| 135 | PointerType::get(C&: Context, AddressSpace: 0), |
| 136 | PointerType::get(C&: Context, AddressSpace: 0), |
| 137 | PointerType::get(C&: Context, AddressSpace: 0), |
| 138 | Type::getInt32Ty(C&: Context), |
| 139 | Type::getInt64Ty(C&: Context), |
| 140 | Type::getInt8Ty(C&: Context) |
| 141 | }; |
| 142 | |
| 143 | auto *FuncTy = FunctionType::get(Result: Type::getVoidTy(C&: Context), Params: ArgsTy, isVarArg: false); |
| 144 | // Pick a unique name to describe the input parameters |
| 145 | Twine Name = "autogen_SD" + Twine{SeedCL}; |
| 146 | auto *Func = Function::Create(Ty: FuncTy, Linkage: GlobalValue::ExternalLinkage, N: Name, M); |
| 147 | Func->setCallingConv(CallingConv::C); |
| 148 | return Func; |
| 149 | } |
| 150 | |
| 151 | /// A base class, implementing utilities needed for |
| 152 | /// modifying and adding new random instructions. |
| 153 | struct Modifier { |
| 154 | /// Used to store the randomly generated values. |
| 155 | using PieceTable = std::vector<Value *>; |
| 156 | |
| 157 | public: |
| 158 | /// C'tor |
| 159 | Modifier(BasicBlock *Block, PieceTable *PT, Random *R) |
| 160 | : BB(Block), PT(PT), Ran(R), Context(BB->getContext()) { |
| 161 | ScalarTypes.assign(l: {Type::getInt1Ty(C&: Context), Type::getInt8Ty(C&: Context), |
| 162 | Type::getInt16Ty(C&: Context), Type::getInt32Ty(C&: Context), |
| 163 | Type::getInt64Ty(C&: Context), Type::getFloatTy(C&: Context), |
| 164 | Type::getDoubleTy(C&: Context)}); |
| 165 | |
| 166 | for (auto &Arg : AdditionalScalarTypes) { |
| 167 | Type *Ty = nullptr; |
| 168 | if (Arg == "half" ) |
| 169 | Ty = Type::getHalfTy(C&: Context); |
| 170 | else if (Arg == "fp128" ) |
| 171 | Ty = Type::getFP128Ty(C&: Context); |
| 172 | else if (Arg == "x86_fp80" ) |
| 173 | Ty = Type::getX86_FP80Ty(C&: Context); |
| 174 | else if (Arg == "ppc_fp128" ) |
| 175 | Ty = Type::getPPC_FP128Ty(C&: Context); |
| 176 | else if (Arg.starts_with(Prefix: "i" )) { |
| 177 | unsigned N = 0; |
| 178 | Arg.drop_front().getAsInteger(Radix: 10, Result&: N); |
| 179 | if (N > 0) |
| 180 | Ty = Type::getIntNTy(C&: Context, N); |
| 181 | } |
| 182 | if (!Ty) { |
| 183 | errs() << "Invalid IR scalar type: '" << Arg << "'!\n" ; |
| 184 | exit(status: 1); |
| 185 | } |
| 186 | |
| 187 | ScalarTypes.push_back(x: Ty); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | /// virtual D'tor to silence warnings. |
| 192 | virtual ~Modifier() = default; |
| 193 | |
| 194 | /// Add a new instruction. |
| 195 | virtual void Act() = 0; |
| 196 | |
| 197 | /// Add N new instructions, |
| 198 | virtual void ActN(unsigned n) { |
| 199 | for (unsigned i=0; i<n; ++i) |
| 200 | Act(); |
| 201 | } |
| 202 | |
| 203 | protected: |
| 204 | /// Return a random integer. |
| 205 | uint32_t getRandom() { |
| 206 | return Ran->Rand(); |
| 207 | } |
| 208 | |
| 209 | /// Return a random value from the list of known values. |
| 210 | Value *getRandomVal() { |
| 211 | assert(PT->size()); |
| 212 | return PT->at(n: getRandom() % PT->size()); |
| 213 | } |
| 214 | |
| 215 | Constant *getRandomConstant(Type *Tp) { |
| 216 | if (Tp->isIntegerTy()) { |
| 217 | if (getRandom() & 1) |
| 218 | return ConstantInt::getAllOnesValue(Ty: Tp); |
| 219 | return ConstantInt::getNullValue(Ty: Tp); |
| 220 | } else if (Tp->isFloatingPointTy()) { |
| 221 | if (getRandom() & 1) |
| 222 | return ConstantFP::getAllOnesValue(Ty: Tp); |
| 223 | return ConstantFP::getZero(Ty: Tp); |
| 224 | } |
| 225 | return UndefValue::get(T: Tp); |
| 226 | } |
| 227 | |
| 228 | /// Return a random value with a known type. |
| 229 | Value *getRandomValue(Type *Tp) { |
| 230 | unsigned index = getRandom(); |
| 231 | for (unsigned i=0; i<PT->size(); ++i) { |
| 232 | Value *V = PT->at(n: (index + i) % PT->size()); |
| 233 | if (V->getType() == Tp) |
| 234 | return V; |
| 235 | } |
| 236 | |
| 237 | // If the requested type was not found, generate a constant value. |
| 238 | if (Tp->isIntegerTy()) { |
| 239 | if (getRandom() & 1) |
| 240 | return ConstantInt::getAllOnesValue(Ty: Tp); |
| 241 | return ConstantInt::getNullValue(Ty: Tp); |
| 242 | } else if (Tp->isFloatingPointTy()) { |
| 243 | if (getRandom() & 1) |
| 244 | return ConstantFP::getAllOnesValue(Ty: Tp); |
| 245 | return ConstantFP::getZero(Ty: Tp); |
| 246 | } else if (auto *VTp = dyn_cast<FixedVectorType>(Val: Tp)) { |
| 247 | std::vector<Constant*> TempValues; |
| 248 | TempValues.reserve(n: VTp->getNumElements()); |
| 249 | for (unsigned i = 0; i < VTp->getNumElements(); ++i) |
| 250 | TempValues.push_back(x: getRandomConstant(Tp: VTp->getScalarType())); |
| 251 | |
| 252 | ArrayRef<Constant*> VectorValue(TempValues); |
| 253 | return ConstantVector::get(V: VectorValue); |
| 254 | } |
| 255 | |
| 256 | return UndefValue::get(T: Tp); |
| 257 | } |
| 258 | |
| 259 | /// Return a random value of any pointer type. |
| 260 | Value *getRandomPointerValue() { |
| 261 | unsigned index = getRandom(); |
| 262 | for (unsigned i=0; i<PT->size(); ++i) { |
| 263 | Value *V = PT->at(n: (index + i) % PT->size()); |
| 264 | if (V->getType()->isPointerTy()) |
| 265 | return V; |
| 266 | } |
| 267 | return UndefValue::get(T: PointerType::get(C&: Context, AddressSpace: 0)); |
| 268 | } |
| 269 | |
| 270 | /// Return a random value of any vector type. |
| 271 | Value *getRandomVectorValue() { |
| 272 | unsigned index = getRandom(); |
| 273 | for (unsigned i=0; i<PT->size(); ++i) { |
| 274 | Value *V = PT->at(n: (index + i) % PT->size()); |
| 275 | if (V->getType()->isVectorTy()) |
| 276 | return V; |
| 277 | } |
| 278 | return UndefValue::get(T: pickVectorType()); |
| 279 | } |
| 280 | |
| 281 | /// Pick a random type. |
| 282 | Type *pickType() { |
| 283 | return (getRandom() & 1) ? pickVectorType() : pickScalarType(); |
| 284 | } |
| 285 | |
| 286 | /// Pick a random vector type. |
| 287 | Type *pickVectorType(VectorType *VTy = nullptr) { |
| 288 | |
| 289 | Type *Ty = pickScalarType(); |
| 290 | |
| 291 | if (VTy) |
| 292 | return VectorType::get(ElementType: Ty, EC: VTy->getElementCount()); |
| 293 | |
| 294 | // Select either fixed length or scalable vectors with 50% probability |
| 295 | // (only if scalable vectors are enabled) |
| 296 | bool Scalable = EnableScalableVectors && getRandom() & 1; |
| 297 | |
| 298 | // Pick a random vector width in the range 2**0 to 2**4. |
| 299 | // by adding two randoms we are generating a normal-like distribution |
| 300 | // around 2**3. |
| 301 | unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3)); |
| 302 | return VectorType::get(ElementType: Ty, NumElements: width, Scalable); |
| 303 | } |
| 304 | |
| 305 | /// Pick a random scalar type. |
| 306 | Type *pickScalarType() { |
| 307 | return ScalarTypes[getRandom() % ScalarTypes.size()]; |
| 308 | } |
| 309 | |
| 310 | /// Basic block to populate |
| 311 | BasicBlock *BB; |
| 312 | |
| 313 | /// Value table |
| 314 | PieceTable *PT; |
| 315 | |
| 316 | /// Random number generator |
| 317 | Random *Ran; |
| 318 | |
| 319 | /// Context |
| 320 | LLVMContext &Context; |
| 321 | |
| 322 | std::vector<Type *> ScalarTypes; |
| 323 | }; |
| 324 | |
| 325 | struct LoadModifier: public Modifier { |
| 326 | LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 327 | : Modifier(BB, PT, R) {} |
| 328 | |
| 329 | void Act() override { |
| 330 | // Try to use predefined pointers. If non-exist, use undef pointer value; |
| 331 | Value *Ptr = getRandomPointerValue(); |
| 332 | Type *Ty = pickType(); |
| 333 | Value *V = new LoadInst(Ty, Ptr, "L" , BB->getTerminator()->getIterator()); |
| 334 | PT->push_back(x: V); |
| 335 | } |
| 336 | }; |
| 337 | |
| 338 | struct StoreModifier: public Modifier { |
| 339 | StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 340 | : Modifier(BB, PT, R) {} |
| 341 | |
| 342 | void Act() override { |
| 343 | // Try to use predefined pointers. If non-exist, use undef pointer value; |
| 344 | Value *Ptr = getRandomPointerValue(); |
| 345 | Type *ValTy = pickType(); |
| 346 | |
| 347 | // Do not store vectors of i1s because they are unsupported |
| 348 | // by the codegen. |
| 349 | if (ValTy->isVectorTy() && ValTy->getScalarSizeInBits() == 1) |
| 350 | return; |
| 351 | |
| 352 | Value *Val = getRandomValue(Tp: ValTy); |
| 353 | new StoreInst(Val, Ptr, BB->getTerminator()->getIterator()); |
| 354 | } |
| 355 | }; |
| 356 | |
| 357 | struct BinModifier: public Modifier { |
| 358 | BinModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 359 | : Modifier(BB, PT, R) {} |
| 360 | |
| 361 | void Act() override { |
| 362 | Value *Val0 = getRandomVal(); |
| 363 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
| 364 | |
| 365 | // Don't handle pointer types. |
| 366 | if (Val0->getType()->isPointerTy() || |
| 367 | Val1->getType()->isPointerTy()) |
| 368 | return; |
| 369 | |
| 370 | // Don't handle i1 types. |
| 371 | if (Val0->getType()->getScalarSizeInBits() == 1) |
| 372 | return; |
| 373 | |
| 374 | bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy(); |
| 375 | Instruction* Term = BB->getTerminator(); |
| 376 | unsigned R = getRandom() % (isFloat ? 7 : 13); |
| 377 | Instruction::BinaryOps Op; |
| 378 | |
| 379 | switch (R) { |
| 380 | default: llvm_unreachable("Invalid BinOp" ); |
| 381 | case 0:{Op = (isFloat?Instruction::FAdd : Instruction::Add); break; } |
| 382 | case 1:{Op = (isFloat?Instruction::FSub : Instruction::Sub); break; } |
| 383 | case 2:{Op = (isFloat?Instruction::FMul : Instruction::Mul); break; } |
| 384 | case 3:{Op = (isFloat?Instruction::FDiv : Instruction::SDiv); break; } |
| 385 | case 4:{Op = (isFloat?Instruction::FDiv : Instruction::UDiv); break; } |
| 386 | case 5:{Op = (isFloat?Instruction::FRem : Instruction::SRem); break; } |
| 387 | case 6:{Op = (isFloat?Instruction::FRem : Instruction::URem); break; } |
| 388 | case 7: {Op = Instruction::Shl; break; } |
| 389 | case 8: {Op = Instruction::LShr; break; } |
| 390 | case 9: {Op = Instruction::AShr; break; } |
| 391 | case 10:{Op = Instruction::And; break; } |
| 392 | case 11:{Op = Instruction::Or; break; } |
| 393 | case 12:{Op = Instruction::Xor; break; } |
| 394 | } |
| 395 | |
| 396 | PT->push_back( |
| 397 | x: BinaryOperator::Create(Op, S1: Val0, S2: Val1, Name: "B" , InsertBefore: Term->getIterator())); |
| 398 | } |
| 399 | }; |
| 400 | |
| 401 | /// Generate constant values. |
| 402 | struct ConstModifier: public Modifier { |
| 403 | ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 404 | : Modifier(BB, PT, R) {} |
| 405 | |
| 406 | void Act() override { |
| 407 | Type *Ty = pickType(); |
| 408 | |
| 409 | if (Ty->isVectorTy()) { |
| 410 | switch (getRandom() % 2) { |
| 411 | case 0: if (Ty->isIntOrIntVectorTy()) |
| 412 | return PT->push_back(x: ConstantVector::getAllOnesValue(Ty)); |
| 413 | break; |
| 414 | case 1: if (Ty->isIntOrIntVectorTy()) |
| 415 | return PT->push_back(x: ConstantVector::getNullValue(Ty)); |
| 416 | } |
| 417 | } |
| 418 | |
| 419 | if (Ty->isFloatingPointTy()) { |
| 420 | // Generate 128 random bits, the size of the (currently) |
| 421 | // largest floating-point types. |
| 422 | uint64_t RandomBits[2]; |
| 423 | for (unsigned i = 0; i < 2; ++i) |
| 424 | RandomBits[i] = Ran->Rand64(); |
| 425 | |
| 426 | APInt RandomInt(Ty->getPrimitiveSizeInBits(), ArrayRef(RandomBits)); |
| 427 | APFloat RandomFloat(Ty->getFltSemantics(), RandomInt); |
| 428 | |
| 429 | if (getRandom() & 1) |
| 430 | return PT->push_back(x: ConstantFP::getZero(Ty)); |
| 431 | return PT->push_back(x: ConstantFP::get(Context&: Ty->getContext(), V: RandomFloat)); |
| 432 | } |
| 433 | |
| 434 | if (Ty->isIntegerTy()) { |
| 435 | switch (getRandom() % 7) { |
| 436 | case 0: |
| 437 | return PT->push_back(x: ConstantInt::get( |
| 438 | Ty, V: APInt::getAllOnes(numBits: Ty->getPrimitiveSizeInBits()))); |
| 439 | case 1: |
| 440 | return PT->push_back( |
| 441 | x: ConstantInt::get(Ty, V: APInt::getZero(numBits: Ty->getPrimitiveSizeInBits()))); |
| 442 | case 2: |
| 443 | case 3: |
| 444 | case 4: |
| 445 | case 5: |
| 446 | case 6: |
| 447 | PT->push_back(x: ConstantInt::get(Ty, V: getRandom())); |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | }; |
| 452 | |
| 453 | struct AllocaModifier: public Modifier { |
| 454 | AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 455 | : Modifier(BB, PT, R) {} |
| 456 | |
| 457 | void Act() override { |
| 458 | Type *Tp = pickType(); |
| 459 | const DataLayout &DL = BB->getDataLayout(); |
| 460 | PT->push_back(x: new AllocaInst(Tp, DL.getAllocaAddrSpace(), "A" , |
| 461 | BB->getFirstNonPHIIt())); |
| 462 | } |
| 463 | }; |
| 464 | |
| 465 | struct : public Modifier { |
| 466 | ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 467 | : Modifier(BB, PT, R) {} |
| 468 | |
| 469 | void () override { |
| 470 | Value *Val0 = getRandomVectorValue(); |
| 471 | Value *V = ExtractElementInst::Create( |
| 472 | Vec: Val0, Idx: getRandomValue(Tp: Type::getInt32Ty(C&: BB->getContext())), NameStr: "E" , |
| 473 | InsertBefore: BB->getTerminator()->getIterator()); |
| 474 | return PT->push_back(x: V); |
| 475 | } |
| 476 | }; |
| 477 | |
| 478 | struct ShuffModifier: public Modifier { |
| 479 | ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 480 | : Modifier(BB, PT, R) {} |
| 481 | |
| 482 | void Act() override { |
| 483 | Value *Val0 = getRandomVectorValue(); |
| 484 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
| 485 | |
| 486 | // Can't express arbitrary shufflevectors for scalable vectors |
| 487 | if (isa<ScalableVectorType>(Val: Val0->getType())) |
| 488 | return; |
| 489 | |
| 490 | unsigned Width = cast<FixedVectorType>(Val: Val0->getType())->getNumElements(); |
| 491 | std::vector<Constant*> Idxs; |
| 492 | |
| 493 | Type *I32 = Type::getInt32Ty(C&: BB->getContext()); |
| 494 | for (unsigned i=0; i<Width; ++i) { |
| 495 | Constant *CI = ConstantInt::get(Ty: I32, V: getRandom() % (Width*2)); |
| 496 | // Pick some undef values. |
| 497 | if (!(getRandom() % 5)) |
| 498 | CI = UndefValue::get(T: I32); |
| 499 | Idxs.push_back(x: CI); |
| 500 | } |
| 501 | |
| 502 | Constant *Mask = ConstantVector::get(V: Idxs); |
| 503 | |
| 504 | Value *V = new ShuffleVectorInst(Val0, Val1, Mask, "Shuff" , |
| 505 | BB->getTerminator()->getIterator()); |
| 506 | PT->push_back(x: V); |
| 507 | } |
| 508 | }; |
| 509 | |
| 510 | struct InsertElementModifier: public Modifier { |
| 511 | InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 512 | : Modifier(BB, PT, R) {} |
| 513 | |
| 514 | void Act() override { |
| 515 | Value *Val0 = getRandomVectorValue(); |
| 516 | Value *Val1 = getRandomValue(Tp: Val0->getType()->getScalarType()); |
| 517 | |
| 518 | Value *V = InsertElementInst::Create( |
| 519 | Vec: Val0, NewElt: Val1, Idx: getRandomValue(Tp: Type::getInt32Ty(C&: BB->getContext())), NameStr: "I" , |
| 520 | InsertBefore: BB->getTerminator()->getIterator()); |
| 521 | return PT->push_back(x: V); |
| 522 | } |
| 523 | }; |
| 524 | |
| 525 | struct CastModifier: public Modifier { |
| 526 | CastModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 527 | : Modifier(BB, PT, R) {} |
| 528 | |
| 529 | void Act() override { |
| 530 | Value *V = getRandomVal(); |
| 531 | Type *VTy = V->getType(); |
| 532 | Type *DestTy = pickScalarType(); |
| 533 | |
| 534 | // Handle vector casts vectors. |
| 535 | if (VTy->isVectorTy()) |
| 536 | DestTy = pickVectorType(VTy: cast<VectorType>(Val: VTy)); |
| 537 | |
| 538 | // no need to cast. |
| 539 | if (VTy == DestTy) return; |
| 540 | |
| 541 | // Pointers: |
| 542 | if (VTy->isPointerTy()) { |
| 543 | if (!DestTy->isPointerTy()) |
| 544 | DestTy = PointerType::get(C&: Context, AddressSpace: 0); |
| 545 | return PT->push_back( |
| 546 | x: new BitCastInst(V, DestTy, "PC" , BB->getTerminator()->getIterator())); |
| 547 | } |
| 548 | |
| 549 | unsigned VSize = VTy->getScalarType()->getPrimitiveSizeInBits(); |
| 550 | unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits(); |
| 551 | |
| 552 | // Generate lots of bitcasts. |
| 553 | if ((getRandom() & 1) && VSize == DestSize) { |
| 554 | return PT->push_back( |
| 555 | x: new BitCastInst(V, DestTy, "BC" , BB->getTerminator()->getIterator())); |
| 556 | } |
| 557 | |
| 558 | // Both types are integers: |
| 559 | if (VTy->isIntOrIntVectorTy() && DestTy->isIntOrIntVectorTy()) { |
| 560 | if (VSize > DestSize) { |
| 561 | return PT->push_back( |
| 562 | x: new TruncInst(V, DestTy, "Tr" , BB->getTerminator()->getIterator())); |
| 563 | } else { |
| 564 | assert(VSize < DestSize && "Different int types with the same size?" ); |
| 565 | if (getRandom() & 1) |
| 566 | return PT->push_back(x: new ZExtInst( |
| 567 | V, DestTy, "ZE" , BB->getTerminator()->getIterator())); |
| 568 | return PT->push_back( |
| 569 | x: new SExtInst(V, DestTy, "Se" , BB->getTerminator()->getIterator())); |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | // Fp to int. |
| 574 | if (VTy->isFPOrFPVectorTy() && DestTy->isIntOrIntVectorTy()) { |
| 575 | if (getRandom() & 1) |
| 576 | return PT->push_back(x: new FPToSIInst( |
| 577 | V, DestTy, "FC" , BB->getTerminator()->getIterator())); |
| 578 | return PT->push_back( |
| 579 | x: new FPToUIInst(V, DestTy, "FC" , BB->getTerminator()->getIterator())); |
| 580 | } |
| 581 | |
| 582 | // Int to fp. |
| 583 | if (VTy->isIntOrIntVectorTy() && DestTy->isFPOrFPVectorTy()) { |
| 584 | if (getRandom() & 1) |
| 585 | return PT->push_back(x: new SIToFPInst( |
| 586 | V, DestTy, "FC" , BB->getTerminator()->getIterator())); |
| 587 | return PT->push_back( |
| 588 | x: new UIToFPInst(V, DestTy, "FC" , BB->getTerminator()->getIterator())); |
| 589 | } |
| 590 | |
| 591 | // Both floats. |
| 592 | if (VTy->isFPOrFPVectorTy() && DestTy->isFPOrFPVectorTy()) { |
| 593 | if (VSize > DestSize) { |
| 594 | return PT->push_back(x: new FPTruncInst( |
| 595 | V, DestTy, "Tr" , BB->getTerminator()->getIterator())); |
| 596 | } else if (VSize < DestSize) { |
| 597 | return PT->push_back( |
| 598 | x: new FPExtInst(V, DestTy, "ZE" , BB->getTerminator()->getIterator())); |
| 599 | } |
| 600 | // If VSize == DestSize, then the two types must be fp128 and ppc_fp128, |
| 601 | // for which there is no defined conversion. So do nothing. |
| 602 | } |
| 603 | } |
| 604 | }; |
| 605 | |
| 606 | struct SelectModifier: public Modifier { |
| 607 | SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 608 | : Modifier(BB, PT, R) {} |
| 609 | |
| 610 | void Act() override { |
| 611 | // Try a bunch of different select configuration until a valid one is found. |
| 612 | Value *Val0 = getRandomVal(); |
| 613 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
| 614 | |
| 615 | Type *CondTy = Type::getInt1Ty(C&: Context); |
| 616 | |
| 617 | // If the value type is a vector, and we allow vector select, then in 50% |
| 618 | // of the cases generate a vector select. |
| 619 | if (auto *VTy = dyn_cast<VectorType>(Val: Val0->getType())) |
| 620 | if (getRandom() & 1) |
| 621 | CondTy = VectorType::get(ElementType: CondTy, EC: VTy->getElementCount()); |
| 622 | |
| 623 | Value *Cond = getRandomValue(Tp: CondTy); |
| 624 | Value *V = SelectInst::Create(C: Cond, S1: Val0, S2: Val1, NameStr: "Sl" , |
| 625 | InsertBefore: BB->getTerminator()->getIterator()); |
| 626 | return PT->push_back(x: V); |
| 627 | } |
| 628 | }; |
| 629 | |
| 630 | struct CmpModifier: public Modifier { |
| 631 | CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
| 632 | : Modifier(BB, PT, R) {} |
| 633 | |
| 634 | void Act() override { |
| 635 | Value *Val0 = getRandomVal(); |
| 636 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
| 637 | |
| 638 | if (Val0->getType()->isPointerTy()) return; |
| 639 | bool fp = Val0->getType()->getScalarType()->isFloatingPointTy(); |
| 640 | |
| 641 | int op; |
| 642 | if (fp) { |
| 643 | op = getRandom() % |
| 644 | (CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) + |
| 645 | CmpInst::FIRST_FCMP_PREDICATE; |
| 646 | } else { |
| 647 | op = getRandom() % |
| 648 | (CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) + |
| 649 | CmpInst::FIRST_ICMP_PREDICATE; |
| 650 | } |
| 651 | |
| 652 | Value *V = CmpInst::Create(Op: fp ? Instruction::FCmp : Instruction::ICmp, |
| 653 | Pred: (CmpInst::Predicate)op, S1: Val0, S2: Val1, Name: "Cmp" , |
| 654 | InsertBefore: BB->getTerminator()->getIterator()); |
| 655 | return PT->push_back(x: V); |
| 656 | } |
| 657 | }; |
| 658 | |
| 659 | } // end anonymous namespace |
| 660 | |
| 661 | static void FillFunction(Function *F, Random &R) { |
| 662 | // Create a legal entry block. |
| 663 | BasicBlock *BB = BasicBlock::Create(Context&: F->getContext(), Name: "BB" , Parent: F); |
| 664 | ReturnInst::Create(C&: F->getContext(), InsertAtEnd: BB); |
| 665 | |
| 666 | // Create the value table. |
| 667 | Modifier::PieceTable PT; |
| 668 | |
| 669 | // Consider arguments as legal values. |
| 670 | for (auto &arg : F->args()) |
| 671 | PT.push_back(x: &arg); |
| 672 | |
| 673 | // List of modifiers which add new random instructions. |
| 674 | std::vector<std::unique_ptr<Modifier>> Modifiers; |
| 675 | Modifiers.emplace_back(args: new LoadModifier(BB, &PT, &R)); |
| 676 | Modifiers.emplace_back(args: new StoreModifier(BB, &PT, &R)); |
| 677 | auto SM = Modifiers.back().get(); |
| 678 | Modifiers.emplace_back(args: new ExtractElementModifier(BB, &PT, &R)); |
| 679 | Modifiers.emplace_back(args: new ShuffModifier(BB, &PT, &R)); |
| 680 | Modifiers.emplace_back(args: new InsertElementModifier(BB, &PT, &R)); |
| 681 | Modifiers.emplace_back(args: new BinModifier(BB, &PT, &R)); |
| 682 | Modifiers.emplace_back(args: new CastModifier(BB, &PT, &R)); |
| 683 | Modifiers.emplace_back(args: new SelectModifier(BB, &PT, &R)); |
| 684 | Modifiers.emplace_back(args: new CmpModifier(BB, &PT, &R)); |
| 685 | |
| 686 | // Generate the random instructions |
| 687 | AllocaModifier{BB, &PT, &R}.ActN(n: 5); // Throw in a few allocas |
| 688 | ConstModifier{BB, &PT, &R}.ActN(n: 40); // Throw in a few constants |
| 689 | |
| 690 | for (unsigned i = 0; i < SizeCL / Modifiers.size(); ++i) |
| 691 | for (auto &Mod : Modifiers) |
| 692 | Mod->Act(); |
| 693 | |
| 694 | SM->ActN(n: 5); // Throw in a few stores. |
| 695 | } |
| 696 | |
| 697 | static void IntroduceControlFlow(Function *F, Random &R) { |
| 698 | std::vector<Instruction*> BoolInst; |
| 699 | for (auto &Instr : F->front()) { |
| 700 | if (Instr.getType() == IntegerType::getInt1Ty(C&: F->getContext())) |
| 701 | BoolInst.push_back(x: &Instr); |
| 702 | } |
| 703 | |
| 704 | llvm::shuffle(first: BoolInst.begin(), last: BoolInst.end(), g&: R); |
| 705 | |
| 706 | for (auto *Instr : BoolInst) { |
| 707 | BasicBlock *Curr = Instr->getParent(); |
| 708 | BasicBlock::iterator Loc = Instr->getIterator(); |
| 709 | BasicBlock *Next = Curr->splitBasicBlock(I: Loc, BBName: "CF" ); |
| 710 | Instr->moveBefore(InsertPos: Curr->getTerminator()->getIterator()); |
| 711 | if (Curr != &F->getEntryBlock()) { |
| 712 | BranchInst::Create(IfTrue: Curr, IfFalse: Next, Cond: Instr, |
| 713 | InsertBefore: Curr->getTerminator()->getIterator()); |
| 714 | Curr->getTerminator()->eraseFromParent(); |
| 715 | } |
| 716 | } |
| 717 | } |
| 718 | |
| 719 | } // end namespace llvm |
| 720 | |
| 721 | int main(int argc, char **argv) { |
| 722 | using namespace llvm; |
| 723 | |
| 724 | InitLLVM X(argc, argv); |
| 725 | cl::HideUnrelatedOptions(Categories: {&StressCategory, &getColorCategory()}); |
| 726 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm codegen stress-tester\n" ); |
| 727 | |
| 728 | LLVMContext Context; |
| 729 | auto M = std::make_unique<Module>(args: "/tmp/autogen.bc" , args&: Context); |
| 730 | Function *F = GenEmptyFunction(M: M.get()); |
| 731 | |
| 732 | // Pick an initial seed value |
| 733 | Random R(SeedCL); |
| 734 | // Generate lots of random instructions inside a single basic block. |
| 735 | FillFunction(F, R); |
| 736 | // Break the basic block into many loops. |
| 737 | IntroduceControlFlow(F, R); |
| 738 | |
| 739 | // Figure out what stream we are supposed to write to... |
| 740 | std::unique_ptr<ToolOutputFile> Out; |
| 741 | // Default to standard output. |
| 742 | if (OutputFilename.empty()) |
| 743 | OutputFilename = "-" ; |
| 744 | |
| 745 | std::error_code EC; |
| 746 | Out.reset(p: new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); |
| 747 | if (EC) { |
| 748 | errs() << EC.message() << '\n'; |
| 749 | return 1; |
| 750 | } |
| 751 | |
| 752 | // Check that the generated module is accepted by the verifier. |
| 753 | if (verifyModule(M: *M.get(), OS: &Out->os())) |
| 754 | report_fatal_error(reason: "Broken module found, compilation aborted!" ); |
| 755 | |
| 756 | // Output textual IR. |
| 757 | M->print(OS&: Out->os(), AAW: nullptr); |
| 758 | |
| 759 | Out->keep(); |
| 760 | |
| 761 | return 0; |
| 762 | } |
| 763 | |