llir-opt  0.0.1
Low-Level Post-Link Optimiser for OCaml and C
symbolic_value.h
1 // This file if part of the llir-opt project.
2 // Licensing information can be found in the LICENSE file.
3 // (C) 2018 Nandor Licker. All rights reserved.
4 
5 #pragma once
6 
7 #include <llvm/ADT/APFloat.h>
8 #include <llvm/ADT/APInt.h>
9 #include <llvm/Support/raw_ostream.h>
10 
11 #include "core/ref.h"
12 #include "passes/pre_eval/symbolic_pointer.h"
13 
14 class SymbolicFrame;
15 class Inst;
16 using APInt = llvm::APInt;
17 using APFloat = llvm::APFloat;
18 
19 
20 
24 class SymbolicValue final {
25 public:
27  enum class Kind {
29  UNDEFINED,
31  SCALAR,
33  INTEGER,
39  FLOAT,
41  POINTER,
43  NULLABLE,
45  VALUE,
46  };
47 
49  using Origin = std::pair<ID<SymbolicFrame>, Ref<Inst>>;
50 
51 public:
53  SymbolicValue() : kind_(Kind::UNDEFINED) {}
55  SymbolicValue(const SymbolicValue &that);
58 
61 
62  static SymbolicValue Scalar(
63  const std::optional<Origin> &orig = std::nullopt
64  );
65 
66  static SymbolicValue Undefined(
67  const std::optional<Origin> &orig = std::nullopt
68  );
69 
70  static SymbolicValue Float(
71  const APFloat &val,
72  const std::optional<Origin> &orig = std::nullopt
73  );
74 
75  static SymbolicValue Integer(
76  const APInt &val,
77  const std::optional<Origin> &orig = std::nullopt
78  );
79 
80  static SymbolicValue LowerBoundedInteger(
81  const APInt &bound,
82  const std::optional<Origin> &orig = std::nullopt
83  );
84 
85  static SymbolicValue Mask(
86  const APInt &known,
87  const APInt &value,
88  const std::optional<Origin> &orig = std::nullopt
89  );
90 
91  static SymbolicValue Pointer(
92  const SymbolicPointer::Ref &pointer,
93  const std::optional<Origin> &orig = std::nullopt
94  );
95 
96  static SymbolicValue Value(
97  const SymbolicPointer::Ref &pointer,
98  const std::optional<Origin> &orig = std::nullopt
99  );
100 
101  static SymbolicValue Nullable(
102  const SymbolicPointer::Ref &pointer,
103  const std::optional<Origin> &orig = std::nullopt
104  );
105 
106  Kind GetKind() const { return kind_; }
107 
108  bool IsInteger() const { return GetKind() == Kind::INTEGER; }
109  bool IsScalar() const { return GetKind() == Kind::SCALAR; }
110  bool IsLowerBoundedInteger() const { return GetKind() == Kind::LOWER_BOUNDED_INTEGER; }
111  bool IsMaskedInteger() const { return GetKind() == Kind::MASKED_INTEGER; }
112  bool IsFloat() const { return GetKind() == Kind::FLOAT; }
113  bool IsPointer() const { return GetKind() == Kind::POINTER; }
114  bool IsValue() const { return GetKind() == Kind::VALUE; }
115  bool IsNullable() const { return GetKind() == Kind::NULLABLE; }
116 
117  bool IsPointerLike() const { return IsPointer() || IsValue() || IsNullable(); }
118  bool IsIntegerLike() const { return IsInteger() || IsLowerBoundedInteger(); }
119 
120  APInt GetInteger() const { assert(IsIntegerLike()); return intVal_; }
121 
122  APInt GetMaskKnown() const { assert(IsMaskedInteger()); return maskVal_.Known; }
123  APInt GetMaskValue() const { assert(IsMaskedInteger()); return maskVal_.Value; }
124 
125  APFloat GetFloat() const { assert(IsFloat()); return floatVal_; }
126 
127  const SymbolicPointer::Ref &GetPointer() const
128  {
129  assert(IsPointerLike());
130  return ptrVal_;
131  }
132 
133  const SymbolicPointer *AsPointer() const
134  {
135  if (IsPointerLike()) {
136  return &*GetPointer();
137  } else {
138  return nullptr;
139  }
140  }
141 
142  std::optional<APInt> AsInt() const
143  {
144  if (IsInteger()) {
145  return std::optional<APInt>(GetInteger());
146  } else {
147  return std::nullopt;
148  }
149  }
150 
152  SymbolicValue Pin(Ref<Inst> ref, ID<SymbolicFrame> frame) const;
153 
155  bool IsTrue() const;
157  bool IsFalse() const;
158 
160  std::optional<Origin> GetOrigin() const { return origin_; }
161 
163  SymbolicValue Cast(Type type) const;
164 
166  void Merge(const SymbolicValue &that);
168  [[nodiscard]] SymbolicValue LUB(const SymbolicValue &that) const
169  {
170  SymbolicValue result(*this);
171  result.Merge(that);
172  return result;
173  }
174 
176  bool operator==(const SymbolicValue &that) const;
177  bool operator!=(const SymbolicValue &that) const { return !(*this == that); }
178 
180  void dump(llvm::raw_ostream &os) const;
181 
182 private:
184  SymbolicValue(Kind kind, std::optional<Origin> origin)
185  : kind_(kind)
186  , origin_(origin)
187  {
188  }
189 
191  void Destroy();
192 
193 private:
195  Kind kind_;
197  std::optional<Origin> origin_;
199  union {
201  APInt intVal_;
203  APFloat floatVal_;
205  struct {
207  APInt Known;
209  APInt Value;
210  } maskVal_;
212  std::shared_ptr<SymbolicPointer> ptrVal_;
213  };
214 };
215 
217 inline llvm::raw_ostream &operator<<(
218  llvm::raw_ostream &os,
219  const SymbolicValue &sym)
220 {
221  sym.dump(os);
222  return os;
223 }
Inst
Definition: inst.h:53
SymbolicPointer
Definition: symbolic_pointer.h:270
SymbolicValue
Definition: symbolic_value.h:24
SymbolicValue::maskVal_
struct SymbolicValue::@8::@10 maskVal_
Value is kind is mask.
SymbolicValue::Origin
std::pair< ID< SymbolicFrame >, Ref< Inst > > Origin
Instruction which originated the value.
Definition: symbolic_value.h:49
SymbolicValue::~SymbolicValue
~SymbolicValue()
Cleanup.
Definition: symbolic_value.cpp:44
SymbolicValue::Kind::UNDEFINED
@ UNDEFINED
A undefined value.
SymbolicValue::operator==
bool operator==(const SymbolicValue &that) const
Compares two values for equality.
Definition: symbolic_value.cpp:617
SymbolicValue::Cast
SymbolicValue Cast(Type type) const
Cast the value to a specific type.
Definition: symbolic_value.cpp:237
SymbolicValue::Pin
SymbolicValue Pin(Ref< Inst > ref, ID< SymbolicFrame > frame) const
Pin the value to a different instruction.
Definition: symbolic_value.cpp:169
SymbolicValue::GetOrigin
std::optional< Origin > GetOrigin() const
Return the origin, if there is one.
Definition: symbolic_value.h:160
SymbolicValue::Known
APInt Known
1's for bits whose values are known.
Definition: symbolic_value.h:207
SymbolicValue::Kind
Kind
Enumeration of value kinds.
Definition: symbolic_value.h:27
SymbolicValue::Kind::POINTER
@ POINTER
A pointer or a range of pointers.
ID< SymbolicFrame >
SymbolicValue::floatVal_
APFloat floatVal_
Value if kind is float.
Definition: symbolic_value.h:203
SymbolicValue::LUB
SymbolicValue LUB(const SymbolicValue &that) const
Computes the least-upper-bound.
Definition: symbolic_value.h:168
SymbolicValue::Kind::FLOAT
@ FLOAT
Floating-point value.
SymbolicValue::Kind::LOWER_BOUNDED_INTEGER
@ LOWER_BOUNDED_INTEGER
An unknown integer with a lower bound.
SymbolicValue::Kind::NULLABLE
@ NULLABLE
A pointer or null.
SymbolicValue::IsTrue
bool IsTrue() const
Checks whether the value evaluates to true.
Definition: symbolic_value.cpp:177
SymbolicValue::Value
APInt Value
Values of the known bits.
Definition: symbolic_value.h:209
Ref
Definition: ref.h:63
SymbolicValue::Kind::INTEGER
@ INTEGER
A specific integer.
SymbolicFrame
Definition: symbolic_frame.h:29
SymbolicValue::Merge
void Merge(const SymbolicValue &that)
Merges a value into this one.
Definition: symbolic_value.cpp:323
SymbolicValue::intVal_
APInt intVal_
Value if kind is integer.
Definition: symbolic_value.h:201
SymbolicValue::dump
void dump(llvm::raw_ostream &os) const
Dump the textual representation to a stream.
Definition: symbolic_value.cpp:660
SymbolicValue::operator=
SymbolicValue & operator=(const SymbolicValue &that)
Copy assignment operator.
Definition: symbolic_value.cpp:50
SymbolicValue::Kind::SCALAR
@ SCALAR
A integer of an unknown value.
SymbolicValue::Kind::MASKED_INTEGER
@ MASKED_INTEGER
An integer with some known bits.
SymbolicValue::SymbolicValue
SymbolicValue()
Undefined constructor.
Definition: symbolic_value.h:53
SymbolicValue::ptrVal_
std::shared_ptr< SymbolicPointer > ptrVal_
Value if kind is pointer.
Definition: symbolic_value.h:212
SymbolicValue::IsFalse
bool IsFalse() const
Checks whether the value evaluates to false.
Definition: symbolic_value.cpp:208
SymbolicValue::Kind::VALUE
@ VALUE
Value - unknown integer or pointer.