1//===-- IRMutator.h - Mutation engine for fuzzing IR ------------*- C++ -*-===//
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// Provides the IRMutator class, which drives mutations on IR based on a
10// configurable set of strategies. Some common strategies are also included
11// here.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_FUZZMUTATE_IRMUTATOR_H
16#define LLVM_FUZZMUTATE_IRMUTATOR_H
17
18#include "llvm/ADT/Optional.h"
19#include "llvm/FuzzMutate/OpDescriptor.h"
20#include "llvm/Support/ErrorHandling.h"
21
22namespace llvm {
23class BasicBlock;
24class Function;
25class Instruction;
26class Module;
27
28struct RandomIRBuilder;
29
30/// Base class for describing how to mutate a module. mutation functions for
31/// each IR unit forward to the contained unit.
32class IRMutationStrategy {
33public:
34  virtual ~IRMutationStrategy() = default;
35
36  /// Provide a weight to bias towards choosing this strategy for a mutation.
37  ///
38  /// The value of the weight is arbitrary, but a good default is "the number of
39  /// distinct ways in which this strategy can mutate a unit". This can also be
40  /// used to prefer strategies that shrink the overall size of the result when
41  /// we start getting close to \c MaxSize.
42  virtual uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
43                             uint64_t CurrentWeight) = 0;
44
45  /// @{
46  /// Mutators for each IR unit. By default these forward to a contained
47  /// instance of the next smaller unit.
48  virtual void mutate(Module &M, RandomIRBuilder &IB);
49  virtual void mutate(Function &F, RandomIRBuilder &IB);
50  virtual void mutate(BasicBlock &BB, RandomIRBuilder &IB);
51  virtual void mutate(Instruction &I, RandomIRBuilder &IB) {
52    llvm_unreachable("Strategy does not implement any mutators");
53  }
54  /// @}
55};
56
57using TypeGetter = std::function<Type *(LLVMContext &)>;
58
59/// Entry point for configuring and running IR mutations.
60class IRMutator {
61  std::vector<TypeGetter> AllowedTypes;
62  std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
63
64public:
65  IRMutator(std::vector<TypeGetter> &&AllowedTypes,
66            std::vector<std::unique_ptr<IRMutationStrategy>> &&Strategies)
67      : AllowedTypes(std::move(AllowedTypes)),
68        Strategies(std::move(Strategies)) {}
69
70  void mutateModule(Module &M, int Seed, size_t CurSize, size_t MaxSize);
71};
72
73/// Strategy that injects operations into the function.
74class InjectorIRStrategy : public IRMutationStrategy {
75  std::vector<fuzzerop::OpDescriptor> Operations;
76
77  Optional<fuzzerop::OpDescriptor> chooseOperation(Value *Src,
78                                                   RandomIRBuilder &IB);
79
80public:
81  InjectorIRStrategy(std::vector<fuzzerop::OpDescriptor> &&Operations)
82      : Operations(std::move(Operations)) {}
83  static std::vector<fuzzerop::OpDescriptor> getDefaultOps();
84
85  uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
86                     uint64_t CurrentWeight) override {
87    return Operations.size();
88  }
89
90  using IRMutationStrategy::mutate;
91  void mutate(Function &F, RandomIRBuilder &IB) override;
92  void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;
93};
94
95class InstDeleterIRStrategy : public IRMutationStrategy {
96public:
97  uint64_t getWeight(size_t CurrentSize, size_t MaxSize,
98                     uint64_t CurrentWeight) override;
99
100  using IRMutationStrategy::mutate;
101  void mutate(Function &F, RandomIRBuilder &IB) override;
102  void mutate(Instruction &Inst, RandomIRBuilder &IB) override;
103};
104
105} // end llvm namespace
106
107#endif // LLVM_FUZZMUTATE_IRMUTATOR_H
108