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 == "x86_mmx" ) |
177 | Ty = Type::getX86_MMXTy(C&: Context); |
178 | else if (Arg.starts_with(Prefix: "i" )) { |
179 | unsigned N = 0; |
180 | Arg.drop_front().getAsInteger(Radix: 10, Result&: N); |
181 | if (N > 0) |
182 | Ty = Type::getIntNTy(C&: Context, N); |
183 | } |
184 | if (!Ty) { |
185 | errs() << "Invalid IR scalar type: '" << Arg << "'!\n" ; |
186 | exit(status: 1); |
187 | } |
188 | |
189 | ScalarTypes.push_back(x: Ty); |
190 | } |
191 | } |
192 | |
193 | /// virtual D'tor to silence warnings. |
194 | virtual ~Modifier() = default; |
195 | |
196 | /// Add a new instruction. |
197 | virtual void Act() = 0; |
198 | |
199 | /// Add N new instructions, |
200 | virtual void ActN(unsigned n) { |
201 | for (unsigned i=0; i<n; ++i) |
202 | Act(); |
203 | } |
204 | |
205 | protected: |
206 | /// Return a random integer. |
207 | uint32_t getRandom() { |
208 | return Ran->Rand(); |
209 | } |
210 | |
211 | /// Return a random value from the list of known values. |
212 | Value *getRandomVal() { |
213 | assert(PT->size()); |
214 | return PT->at(n: getRandom() % PT->size()); |
215 | } |
216 | |
217 | Constant *getRandomConstant(Type *Tp) { |
218 | if (Tp->isIntegerTy()) { |
219 | if (getRandom() & 1) |
220 | return ConstantInt::getAllOnesValue(Ty: Tp); |
221 | return ConstantInt::getNullValue(Ty: Tp); |
222 | } else if (Tp->isFloatingPointTy()) { |
223 | if (getRandom() & 1) |
224 | return ConstantFP::getAllOnesValue(Ty: Tp); |
225 | return ConstantFP::getZero(Ty: Tp); |
226 | } |
227 | return UndefValue::get(T: Tp); |
228 | } |
229 | |
230 | /// Return a random value with a known type. |
231 | Value *getRandomValue(Type *Tp) { |
232 | unsigned index = getRandom(); |
233 | for (unsigned i=0; i<PT->size(); ++i) { |
234 | Value *V = PT->at(n: (index + i) % PT->size()); |
235 | if (V->getType() == Tp) |
236 | return V; |
237 | } |
238 | |
239 | // If the requested type was not found, generate a constant value. |
240 | if (Tp->isIntegerTy()) { |
241 | if (getRandom() & 1) |
242 | return ConstantInt::getAllOnesValue(Ty: Tp); |
243 | return ConstantInt::getNullValue(Ty: Tp); |
244 | } else if (Tp->isFloatingPointTy()) { |
245 | if (getRandom() & 1) |
246 | return ConstantFP::getAllOnesValue(Ty: Tp); |
247 | return ConstantFP::getZero(Ty: Tp); |
248 | } else if (auto *VTp = dyn_cast<FixedVectorType>(Val: Tp)) { |
249 | std::vector<Constant*> TempValues; |
250 | TempValues.reserve(n: VTp->getNumElements()); |
251 | for (unsigned i = 0; i < VTp->getNumElements(); ++i) |
252 | TempValues.push_back(x: getRandomConstant(Tp: VTp->getScalarType())); |
253 | |
254 | ArrayRef<Constant*> VectorValue(TempValues); |
255 | return ConstantVector::get(V: VectorValue); |
256 | } |
257 | |
258 | return UndefValue::get(T: Tp); |
259 | } |
260 | |
261 | /// Return a random value of any pointer type. |
262 | Value *getRandomPointerValue() { |
263 | unsigned index = getRandom(); |
264 | for (unsigned i=0; i<PT->size(); ++i) { |
265 | Value *V = PT->at(n: (index + i) % PT->size()); |
266 | if (V->getType()->isPointerTy()) |
267 | return V; |
268 | } |
269 | return UndefValue::get(T: pickPointerType()); |
270 | } |
271 | |
272 | /// Return a random value of any vector type. |
273 | Value *getRandomVectorValue() { |
274 | unsigned index = getRandom(); |
275 | for (unsigned i=0; i<PT->size(); ++i) { |
276 | Value *V = PT->at(n: (index + i) % PT->size()); |
277 | if (V->getType()->isVectorTy()) |
278 | return V; |
279 | } |
280 | return UndefValue::get(T: pickVectorType()); |
281 | } |
282 | |
283 | /// Pick a random type. |
284 | Type *pickType() { |
285 | return (getRandom() & 1) ? pickVectorType() : pickScalarType(); |
286 | } |
287 | |
288 | /// Pick a random pointer type. |
289 | Type *pickPointerType() { |
290 | Type *Ty = pickType(); |
291 | return PointerType::get(ElementType: Ty, AddressSpace: 0); |
292 | } |
293 | |
294 | /// Pick a random vector type. |
295 | Type *pickVectorType(VectorType *VTy = nullptr) { |
296 | |
297 | // Vectors of x86mmx are illegal; keep trying till we get something else. |
298 | Type *Ty; |
299 | do { |
300 | Ty = pickScalarType(); |
301 | } while (Ty->isX86_MMXTy()); |
302 | |
303 | if (VTy) |
304 | return VectorType::get(ElementType: Ty, EC: VTy->getElementCount()); |
305 | |
306 | // Select either fixed length or scalable vectors with 50% probability |
307 | // (only if scalable vectors are enabled) |
308 | bool Scalable = EnableScalableVectors && getRandom() & 1; |
309 | |
310 | // Pick a random vector width in the range 2**0 to 2**4. |
311 | // by adding two randoms we are generating a normal-like distribution |
312 | // around 2**3. |
313 | unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3)); |
314 | return VectorType::get(ElementType: Ty, NumElements: width, Scalable); |
315 | } |
316 | |
317 | /// Pick a random scalar type. |
318 | Type *pickScalarType() { |
319 | return ScalarTypes[getRandom() % ScalarTypes.size()]; |
320 | } |
321 | |
322 | /// Basic block to populate |
323 | BasicBlock *BB; |
324 | |
325 | /// Value table |
326 | PieceTable *PT; |
327 | |
328 | /// Random number generator |
329 | Random *Ran; |
330 | |
331 | /// Context |
332 | LLVMContext &Context; |
333 | |
334 | std::vector<Type *> ScalarTypes; |
335 | }; |
336 | |
337 | struct LoadModifier: public Modifier { |
338 | LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
339 | : Modifier(BB, PT, R) {} |
340 | |
341 | void Act() override { |
342 | // Try to use predefined pointers. If non-exist, use undef pointer value; |
343 | Value *Ptr = getRandomPointerValue(); |
344 | Type *Ty = pickType(); |
345 | Value *V = new LoadInst(Ty, Ptr, "L" , BB->getTerminator()); |
346 | PT->push_back(x: V); |
347 | } |
348 | }; |
349 | |
350 | struct StoreModifier: public Modifier { |
351 | StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
352 | : Modifier(BB, PT, R) {} |
353 | |
354 | void Act() override { |
355 | // Try to use predefined pointers. If non-exist, use undef pointer value; |
356 | Value *Ptr = getRandomPointerValue(); |
357 | Type *ValTy = pickType(); |
358 | |
359 | // Do not store vectors of i1s because they are unsupported |
360 | // by the codegen. |
361 | if (ValTy->isVectorTy() && ValTy->getScalarSizeInBits() == 1) |
362 | return; |
363 | |
364 | Value *Val = getRandomValue(Tp: ValTy); |
365 | new StoreInst(Val, Ptr, BB->getTerminator()); |
366 | } |
367 | }; |
368 | |
369 | struct BinModifier: public Modifier { |
370 | BinModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
371 | : Modifier(BB, PT, R) {} |
372 | |
373 | void Act() override { |
374 | Value *Val0 = getRandomVal(); |
375 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
376 | |
377 | // Don't handle pointer types. |
378 | if (Val0->getType()->isPointerTy() || |
379 | Val1->getType()->isPointerTy()) |
380 | return; |
381 | |
382 | // Don't handle i1 types. |
383 | if (Val0->getType()->getScalarSizeInBits() == 1) |
384 | return; |
385 | |
386 | bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy(); |
387 | Instruction* Term = BB->getTerminator(); |
388 | unsigned R = getRandom() % (isFloat ? 7 : 13); |
389 | Instruction::BinaryOps Op; |
390 | |
391 | switch (R) { |
392 | default: llvm_unreachable("Invalid BinOp" ); |
393 | case 0:{Op = (isFloat?Instruction::FAdd : Instruction::Add); break; } |
394 | case 1:{Op = (isFloat?Instruction::FSub : Instruction::Sub); break; } |
395 | case 2:{Op = (isFloat?Instruction::FMul : Instruction::Mul); break; } |
396 | case 3:{Op = (isFloat?Instruction::FDiv : Instruction::SDiv); break; } |
397 | case 4:{Op = (isFloat?Instruction::FDiv : Instruction::UDiv); break; } |
398 | case 5:{Op = (isFloat?Instruction::FRem : Instruction::SRem); break; } |
399 | case 6:{Op = (isFloat?Instruction::FRem : Instruction::URem); break; } |
400 | case 7: {Op = Instruction::Shl; break; } |
401 | case 8: {Op = Instruction::LShr; break; } |
402 | case 9: {Op = Instruction::AShr; break; } |
403 | case 10:{Op = Instruction::And; break; } |
404 | case 11:{Op = Instruction::Or; break; } |
405 | case 12:{Op = Instruction::Xor; break; } |
406 | } |
407 | |
408 | PT->push_back(x: BinaryOperator::Create(Op, S1: Val0, S2: Val1, Name: "B" , InsertBefore: Term)); |
409 | } |
410 | }; |
411 | |
412 | /// Generate constant values. |
413 | struct ConstModifier: public Modifier { |
414 | ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
415 | : Modifier(BB, PT, R) {} |
416 | |
417 | void Act() override { |
418 | Type *Ty = pickType(); |
419 | |
420 | if (Ty->isVectorTy()) { |
421 | switch (getRandom() % 2) { |
422 | case 0: if (Ty->isIntOrIntVectorTy()) |
423 | return PT->push_back(x: ConstantVector::getAllOnesValue(Ty)); |
424 | break; |
425 | case 1: if (Ty->isIntOrIntVectorTy()) |
426 | return PT->push_back(x: ConstantVector::getNullValue(Ty)); |
427 | } |
428 | } |
429 | |
430 | if (Ty->isFloatingPointTy()) { |
431 | // Generate 128 random bits, the size of the (currently) |
432 | // largest floating-point types. |
433 | uint64_t RandomBits[2]; |
434 | for (unsigned i = 0; i < 2; ++i) |
435 | RandomBits[i] = Ran->Rand64(); |
436 | |
437 | APInt RandomInt(Ty->getPrimitiveSizeInBits(), ArrayRef(RandomBits)); |
438 | APFloat RandomFloat(Ty->getFltSemantics(), RandomInt); |
439 | |
440 | if (getRandom() & 1) |
441 | return PT->push_back(x: ConstantFP::getZero(Ty)); |
442 | return PT->push_back(x: ConstantFP::get(Context&: Ty->getContext(), V: RandomFloat)); |
443 | } |
444 | |
445 | if (Ty->isIntegerTy()) { |
446 | switch (getRandom() % 7) { |
447 | case 0: |
448 | return PT->push_back(x: ConstantInt::get( |
449 | Ty, V: APInt::getAllOnes(numBits: Ty->getPrimitiveSizeInBits()))); |
450 | case 1: |
451 | return PT->push_back( |
452 | x: ConstantInt::get(Ty, V: APInt::getZero(numBits: Ty->getPrimitiveSizeInBits()))); |
453 | case 2: |
454 | case 3: |
455 | case 4: |
456 | case 5: |
457 | case 6: |
458 | PT->push_back(x: ConstantInt::get(Ty, V: getRandom())); |
459 | } |
460 | } |
461 | } |
462 | }; |
463 | |
464 | struct AllocaModifier: public Modifier { |
465 | AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
466 | : Modifier(BB, PT, R) {} |
467 | |
468 | void Act() override { |
469 | Type *Tp = pickType(); |
470 | const DataLayout &DL = BB->getDataLayout(); |
471 | PT->push_back(x: new AllocaInst(Tp, DL.getAllocaAddrSpace(), |
472 | "A" , BB->getFirstNonPHI())); |
473 | } |
474 | }; |
475 | |
476 | struct : public Modifier { |
477 | ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
478 | : Modifier(BB, PT, R) {} |
479 | |
480 | void () override { |
481 | Value *Val0 = getRandomVectorValue(); |
482 | Value *V = ExtractElementInst::Create( |
483 | Vec: Val0, |
484 | Idx: getRandomValue(Tp: Type::getInt32Ty(C&: BB->getContext())), |
485 | NameStr: "E" , InsertBefore: BB->getTerminator()); |
486 | return PT->push_back(x: V); |
487 | } |
488 | }; |
489 | |
490 | struct ShuffModifier: public Modifier { |
491 | ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
492 | : Modifier(BB, PT, R) {} |
493 | |
494 | void Act() override { |
495 | Value *Val0 = getRandomVectorValue(); |
496 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
497 | |
498 | // Can't express arbitrary shufflevectors for scalable vectors |
499 | if (isa<ScalableVectorType>(Val: Val0->getType())) |
500 | return; |
501 | |
502 | unsigned Width = cast<FixedVectorType>(Val: Val0->getType())->getNumElements(); |
503 | std::vector<Constant*> Idxs; |
504 | |
505 | Type *I32 = Type::getInt32Ty(C&: BB->getContext()); |
506 | for (unsigned i=0; i<Width; ++i) { |
507 | Constant *CI = ConstantInt::get(Ty: I32, V: getRandom() % (Width*2)); |
508 | // Pick some undef values. |
509 | if (!(getRandom() % 5)) |
510 | CI = UndefValue::get(T: I32); |
511 | Idxs.push_back(x: CI); |
512 | } |
513 | |
514 | Constant *Mask = ConstantVector::get(V: Idxs); |
515 | |
516 | Value *V = new ShuffleVectorInst(Val0, Val1, Mask, "Shuff" , |
517 | BB->getTerminator()); |
518 | PT->push_back(x: V); |
519 | } |
520 | }; |
521 | |
522 | struct InsertElementModifier: public Modifier { |
523 | InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
524 | : Modifier(BB, PT, R) {} |
525 | |
526 | void Act() override { |
527 | Value *Val0 = getRandomVectorValue(); |
528 | Value *Val1 = getRandomValue(Tp: Val0->getType()->getScalarType()); |
529 | |
530 | Value *V = InsertElementInst::Create( |
531 | Vec: Val0, NewElt: Val1, |
532 | Idx: getRandomValue(Tp: Type::getInt32Ty(C&: BB->getContext())), |
533 | NameStr: "I" , InsertBefore: BB->getTerminator()); |
534 | return PT->push_back(x: V); |
535 | } |
536 | }; |
537 | |
538 | struct CastModifier: public Modifier { |
539 | CastModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
540 | : Modifier(BB, PT, R) {} |
541 | |
542 | void Act() override { |
543 | Value *V = getRandomVal(); |
544 | Type *VTy = V->getType(); |
545 | Type *DestTy = pickScalarType(); |
546 | |
547 | // Handle vector casts vectors. |
548 | if (VTy->isVectorTy()) |
549 | DestTy = pickVectorType(VTy: cast<VectorType>(Val: VTy)); |
550 | |
551 | // no need to cast. |
552 | if (VTy == DestTy) return; |
553 | |
554 | // Pointers: |
555 | if (VTy->isPointerTy()) { |
556 | if (!DestTy->isPointerTy()) |
557 | DestTy = PointerType::get(ElementType: DestTy, AddressSpace: 0); |
558 | return PT->push_back( |
559 | x: new BitCastInst(V, DestTy, "PC" , BB->getTerminator())); |
560 | } |
561 | |
562 | unsigned VSize = VTy->getScalarType()->getPrimitiveSizeInBits(); |
563 | unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits(); |
564 | |
565 | // Generate lots of bitcasts. |
566 | if ((getRandom() & 1) && VSize == DestSize) { |
567 | return PT->push_back( |
568 | x: new BitCastInst(V, DestTy, "BC" , BB->getTerminator())); |
569 | } |
570 | |
571 | // Both types are integers: |
572 | if (VTy->isIntOrIntVectorTy() && DestTy->isIntOrIntVectorTy()) { |
573 | if (VSize > DestSize) { |
574 | return PT->push_back( |
575 | x: new TruncInst(V, DestTy, "Tr" , BB->getTerminator())); |
576 | } else { |
577 | assert(VSize < DestSize && "Different int types with the same size?" ); |
578 | if (getRandom() & 1) |
579 | return PT->push_back( |
580 | x: new ZExtInst(V, DestTy, "ZE" , BB->getTerminator())); |
581 | return PT->push_back(x: new SExtInst(V, DestTy, "Se" , BB->getTerminator())); |
582 | } |
583 | } |
584 | |
585 | // Fp to int. |
586 | if (VTy->isFPOrFPVectorTy() && DestTy->isIntOrIntVectorTy()) { |
587 | if (getRandom() & 1) |
588 | return PT->push_back( |
589 | x: new FPToSIInst(V, DestTy, "FC" , BB->getTerminator())); |
590 | return PT->push_back(x: new FPToUIInst(V, DestTy, "FC" , BB->getTerminator())); |
591 | } |
592 | |
593 | // Int to fp. |
594 | if (VTy->isIntOrIntVectorTy() && DestTy->isFPOrFPVectorTy()) { |
595 | if (getRandom() & 1) |
596 | return PT->push_back( |
597 | x: new SIToFPInst(V, DestTy, "FC" , BB->getTerminator())); |
598 | return PT->push_back(x: new UIToFPInst(V, DestTy, "FC" , BB->getTerminator())); |
599 | } |
600 | |
601 | // Both floats. |
602 | if (VTy->isFPOrFPVectorTy() && DestTy->isFPOrFPVectorTy()) { |
603 | if (VSize > DestSize) { |
604 | return PT->push_back( |
605 | x: new FPTruncInst(V, DestTy, "Tr" , BB->getTerminator())); |
606 | } else if (VSize < DestSize) { |
607 | return PT->push_back( |
608 | x: new FPExtInst(V, DestTy, "ZE" , BB->getTerminator())); |
609 | } |
610 | // If VSize == DestSize, then the two types must be fp128 and ppc_fp128, |
611 | // for which there is no defined conversion. So do nothing. |
612 | } |
613 | } |
614 | }; |
615 | |
616 | struct SelectModifier: public Modifier { |
617 | SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
618 | : Modifier(BB, PT, R) {} |
619 | |
620 | void Act() override { |
621 | // Try a bunch of different select configuration until a valid one is found. |
622 | Value *Val0 = getRandomVal(); |
623 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
624 | |
625 | Type *CondTy = Type::getInt1Ty(C&: Context); |
626 | |
627 | // If the value type is a vector, and we allow vector select, then in 50% |
628 | // of the cases generate a vector select. |
629 | if (auto *VTy = dyn_cast<VectorType>(Val: Val0->getType())) |
630 | if (getRandom() & 1) |
631 | CondTy = VectorType::get(ElementType: CondTy, EC: VTy->getElementCount()); |
632 | |
633 | Value *Cond = getRandomValue(Tp: CondTy); |
634 | Value *V = SelectInst::Create(C: Cond, S1: Val0, S2: Val1, NameStr: "Sl" , InsertBefore: BB->getTerminator()); |
635 | return PT->push_back(x: V); |
636 | } |
637 | }; |
638 | |
639 | struct CmpModifier: public Modifier { |
640 | CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R) |
641 | : Modifier(BB, PT, R) {} |
642 | |
643 | void Act() override { |
644 | Value *Val0 = getRandomVal(); |
645 | Value *Val1 = getRandomValue(Tp: Val0->getType()); |
646 | |
647 | if (Val0->getType()->isPointerTy()) return; |
648 | bool fp = Val0->getType()->getScalarType()->isFloatingPointTy(); |
649 | |
650 | int op; |
651 | if (fp) { |
652 | op = getRandom() % |
653 | (CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) + |
654 | CmpInst::FIRST_FCMP_PREDICATE; |
655 | } else { |
656 | op = getRandom() % |
657 | (CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) + |
658 | CmpInst::FIRST_ICMP_PREDICATE; |
659 | } |
660 | |
661 | Value *V = CmpInst::Create(Op: fp ? Instruction::FCmp : Instruction::ICmp, |
662 | Pred: (CmpInst::Predicate)op, S1: Val0, S2: Val1, Name: "Cmp" , |
663 | InsertBefore: BB->getTerminator()); |
664 | return PT->push_back(x: V); |
665 | } |
666 | }; |
667 | |
668 | } // end anonymous namespace |
669 | |
670 | static void FillFunction(Function *F, Random &R) { |
671 | // Create a legal entry block. |
672 | BasicBlock *BB = BasicBlock::Create(Context&: F->getContext(), Name: "BB" , Parent: F); |
673 | ReturnInst::Create(C&: F->getContext(), InsertAtEnd: BB); |
674 | |
675 | // Create the value table. |
676 | Modifier::PieceTable PT; |
677 | |
678 | // Consider arguments as legal values. |
679 | for (auto &arg : F->args()) |
680 | PT.push_back(x: &arg); |
681 | |
682 | // List of modifiers which add new random instructions. |
683 | std::vector<std::unique_ptr<Modifier>> Modifiers; |
684 | Modifiers.emplace_back(args: new LoadModifier(BB, &PT, &R)); |
685 | Modifiers.emplace_back(args: new StoreModifier(BB, &PT, &R)); |
686 | auto SM = Modifiers.back().get(); |
687 | Modifiers.emplace_back(args: new ExtractElementModifier(BB, &PT, &R)); |
688 | Modifiers.emplace_back(args: new ShuffModifier(BB, &PT, &R)); |
689 | Modifiers.emplace_back(args: new InsertElementModifier(BB, &PT, &R)); |
690 | Modifiers.emplace_back(args: new BinModifier(BB, &PT, &R)); |
691 | Modifiers.emplace_back(args: new CastModifier(BB, &PT, &R)); |
692 | Modifiers.emplace_back(args: new SelectModifier(BB, &PT, &R)); |
693 | Modifiers.emplace_back(args: new CmpModifier(BB, &PT, &R)); |
694 | |
695 | // Generate the random instructions |
696 | AllocaModifier{BB, &PT, &R}.ActN(n: 5); // Throw in a few allocas |
697 | ConstModifier{BB, &PT, &R}.ActN(n: 40); // Throw in a few constants |
698 | |
699 | for (unsigned i = 0; i < SizeCL / Modifiers.size(); ++i) |
700 | for (auto &Mod : Modifiers) |
701 | Mod->Act(); |
702 | |
703 | SM->ActN(n: 5); // Throw in a few stores. |
704 | } |
705 | |
706 | static void IntroduceControlFlow(Function *F, Random &R) { |
707 | std::vector<Instruction*> BoolInst; |
708 | for (auto &Instr : F->front()) { |
709 | if (Instr.getType() == IntegerType::getInt1Ty(C&: F->getContext())) |
710 | BoolInst.push_back(x: &Instr); |
711 | } |
712 | |
713 | llvm::shuffle(first: BoolInst.begin(), last: BoolInst.end(), g&: R); |
714 | |
715 | for (auto *Instr : BoolInst) { |
716 | BasicBlock *Curr = Instr->getParent(); |
717 | BasicBlock::iterator Loc = Instr->getIterator(); |
718 | BasicBlock *Next = Curr->splitBasicBlock(I: Loc, BBName: "CF" ); |
719 | Instr->moveBefore(MovePos: Curr->getTerminator()); |
720 | if (Curr != &F->getEntryBlock()) { |
721 | BranchInst::Create(IfTrue: Curr, IfFalse: Next, Cond: Instr, InsertBefore: Curr->getTerminator()); |
722 | Curr->getTerminator()->eraseFromParent(); |
723 | } |
724 | } |
725 | } |
726 | |
727 | } // end namespace llvm |
728 | |
729 | int main(int argc, char **argv) { |
730 | using namespace llvm; |
731 | |
732 | InitLLVM X(argc, argv); |
733 | cl::HideUnrelatedOptions(Categories: {&StressCategory, &getColorCategory()}); |
734 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm codegen stress-tester\n" ); |
735 | |
736 | LLVMContext Context; |
737 | auto M = std::make_unique<Module>(args: "/tmp/autogen.bc" , args&: Context); |
738 | Function *F = GenEmptyFunction(M: M.get()); |
739 | |
740 | // Pick an initial seed value |
741 | Random R(SeedCL); |
742 | // Generate lots of random instructions inside a single basic block. |
743 | FillFunction(F, R); |
744 | // Break the basic block into many loops. |
745 | IntroduceControlFlow(F, R); |
746 | |
747 | // Figure out what stream we are supposed to write to... |
748 | std::unique_ptr<ToolOutputFile> Out; |
749 | // Default to standard output. |
750 | if (OutputFilename.empty()) |
751 | OutputFilename = "-" ; |
752 | |
753 | std::error_code EC; |
754 | Out.reset(p: new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); |
755 | if (EC) { |
756 | errs() << EC.message() << '\n'; |
757 | return 1; |
758 | } |
759 | |
760 | // Check that the generated module is accepted by the verifier. |
761 | if (verifyModule(M: *M.get(), OS: &Out->os())) |
762 | report_fatal_error(reason: "Broken module found, compilation aborted!" ); |
763 | |
764 | // Output textual IR. |
765 | M->print(OS&: Out->os(), AAW: nullptr); |
766 | |
767 | Out->keep(); |
768 | |
769 | return 0; |
770 | } |
771 | |