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 | |