1 | //===- SandboxIR.h ----------------------------------------------*- 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 | // Sandbox IR is a lightweight overlay transactional IR on top of LLVM IR. |
10 | // Features: |
11 | // - You can save/rollback the state of the IR at any time. |
12 | // - Any changes made to Sandbox IR will automatically update the underlying |
13 | // LLVM IR so both IRs are always in sync. |
14 | // - Feels like LLVM IR, similar API. |
15 | // |
16 | // SandboxIR forms a class hierarchy that resembles that of LLVM IR |
17 | // but is in the `sandboxir` namespace: |
18 | // |
19 | // namespace sandboxir { |
20 | // |
21 | // +- Argument +- BinaryOperator |
22 | // | | |
23 | // Value -+- BasicBlock +- BranchInst |
24 | // | | |
25 | // +- Function +- Constant +- CastInst |
26 | // | | | |
27 | // +- User ------+- Instruction -+- CallInst |
28 | // | |
29 | // +- CmpInst |
30 | // | |
31 | // +- ExtractElementInst |
32 | // | |
33 | // +- GetElementPtrInst |
34 | // | |
35 | // +- InsertElementInst |
36 | // | |
37 | // +- LoadInst |
38 | // | |
39 | // +- OpaqueInst |
40 | // | |
41 | // +- PHINode |
42 | // | |
43 | // +- ReturnInst |
44 | // | |
45 | // +- SelectInst |
46 | // | |
47 | // +- ShuffleVectorInst |
48 | // | |
49 | // +- StoreInst |
50 | // | |
51 | // +- UnaryOperator |
52 | // |
53 | // Use |
54 | // |
55 | // } // namespace sandboxir |
56 | // |
57 | |
58 | #ifndef LLVM_SANDBOXIR_SANDBOXIR_H |
59 | #define LLVM_SANDBOXIR_SANDBOXIR_H |
60 | |
61 | #include "llvm/IR/Function.h" |
62 | #include "llvm/IR/IRBuilder.h" |
63 | #include "llvm/IR/User.h" |
64 | #include "llvm/IR/Value.h" |
65 | #include "llvm/SandboxIR/Tracker.h" |
66 | #include "llvm/SandboxIR/Use.h" |
67 | #include "llvm/Support/raw_ostream.h" |
68 | #include <iterator> |
69 | |
70 | namespace llvm { |
71 | |
72 | namespace sandboxir { |
73 | |
74 | class BasicBlock; |
75 | class Context; |
76 | class Function; |
77 | class Instruction; |
78 | class SelectInst; |
79 | class LoadInst; |
80 | class ReturnInst; |
81 | class StoreInst; |
82 | class User; |
83 | class Value; |
84 | |
85 | /// Iterator for the `Use` edges of a User's operands. |
86 | /// \Returns the operand `Use` when dereferenced. |
87 | class OperandUseIterator { |
88 | sandboxir::Use Use; |
89 | /// Don't let the user create a non-empty OperandUseIterator. |
90 | OperandUseIterator(const class Use &Use) : Use(Use) {} |
91 | friend class User; // For constructor |
92 | #define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; // For constructor |
93 | #include "llvm/SandboxIR/SandboxIRValues.def" |
94 | |
95 | public: |
96 | using difference_type = std::ptrdiff_t; |
97 | using value_type = sandboxir::Use; |
98 | using pointer = value_type *; |
99 | using reference = value_type &; |
100 | using iterator_category = std::input_iterator_tag; |
101 | |
102 | OperandUseIterator() = default; |
103 | value_type operator*() const; |
104 | OperandUseIterator &operator++(); |
105 | bool operator==(const OperandUseIterator &Other) const { |
106 | return Use == Other.Use; |
107 | } |
108 | bool operator!=(const OperandUseIterator &Other) const { |
109 | return !(*this == Other); |
110 | } |
111 | }; |
112 | |
113 | /// Iterator for the `Use` edges of a Value's users. |
114 | /// \Returns a `Use` when dereferenced. |
115 | class UserUseIterator { |
116 | sandboxir::Use Use; |
117 | /// Don't let the user create a non-empty UserUseIterator. |
118 | UserUseIterator(const class Use &Use) : Use(Use) {} |
119 | friend class Value; // For constructor |
120 | |
121 | public: |
122 | using difference_type = std::ptrdiff_t; |
123 | using value_type = sandboxir::Use; |
124 | using pointer = value_type *; |
125 | using reference = value_type &; |
126 | using iterator_category = std::input_iterator_tag; |
127 | |
128 | UserUseIterator() = default; |
129 | value_type operator*() const { return Use; } |
130 | UserUseIterator &operator++(); |
131 | bool operator==(const UserUseIterator &Other) const { |
132 | return Use == Other.Use; |
133 | } |
134 | bool operator!=(const UserUseIterator &Other) const { |
135 | return !(*this == Other); |
136 | } |
137 | }; |
138 | |
139 | /// A SandboxIR Value has users. This is the base class. |
140 | class Value { |
141 | public: |
142 | enum class ClassID : unsigned { |
143 | #define DEF_VALUE(ID, CLASS) ID, |
144 | #define DEF_USER(ID, CLASS) ID, |
145 | #define DEF_INSTR(ID, OPC, CLASS) ID, |
146 | #include "llvm/SandboxIR/SandboxIRValues.def" |
147 | }; |
148 | |
149 | protected: |
150 | static const char *getSubclassIDStr(ClassID ID) { |
151 | switch (ID) { |
152 | #define DEF_VALUE(ID, CLASS) \ |
153 | case ClassID::ID: \ |
154 | return #ID; |
155 | #define DEF_USER(ID, CLASS) \ |
156 | case ClassID::ID: \ |
157 | return #ID; |
158 | #define DEF_INSTR(ID, OPC, CLASS) \ |
159 | case ClassID::ID: \ |
160 | return #ID; |
161 | #include "llvm/SandboxIR/SandboxIRValues.def" |
162 | } |
163 | llvm_unreachable("Unimplemented ID" ); |
164 | } |
165 | |
166 | /// For isa/dyn_cast. |
167 | ClassID SubclassID; |
168 | #ifndef NDEBUG |
169 | /// A unique ID used for forming the name (used for debugging). |
170 | unsigned UID; |
171 | #endif |
172 | /// The LLVM Value that corresponds to this SandboxIR Value. |
173 | /// NOTE: Some sandboxir Instructions, like Packs, may include more than one |
174 | /// value and in these cases `Val` points to the last instruction in program |
175 | /// order. |
176 | llvm::Value *Val = nullptr; |
177 | |
178 | friend class Context; // For getting `Val`. |
179 | friend class User; // For getting `Val`. |
180 | friend class Use; // For getting `Val`. |
181 | friend class SelectInst; // For getting `Val`. |
182 | friend class LoadInst; // For getting `Val`. |
183 | friend class StoreInst; // For getting `Val`. |
184 | friend class ReturnInst; // For getting `Val`. |
185 | |
186 | /// All values point to the context. |
187 | Context &Ctx; |
188 | // This is used by eraseFromParent(). |
189 | void clearValue() { Val = nullptr; } |
190 | template <typename ItTy, typename SBTy> friend class LLVMOpUserItToSBTy; |
191 | |
192 | Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx); |
193 | |
194 | public: |
195 | virtual ~Value() = default; |
196 | ClassID getSubclassID() const { return SubclassID; } |
197 | |
198 | using use_iterator = UserUseIterator; |
199 | using const_use_iterator = UserUseIterator; |
200 | |
201 | use_iterator use_begin(); |
202 | const_use_iterator use_begin() const { |
203 | return const_cast<Value *>(this)->use_begin(); |
204 | } |
205 | use_iterator use_end() { return use_iterator(Use(nullptr, nullptr, Ctx)); } |
206 | const_use_iterator use_end() const { |
207 | return const_cast<Value *>(this)->use_end(); |
208 | } |
209 | |
210 | iterator_range<use_iterator> uses() { |
211 | return make_range<use_iterator>(x: use_begin(), y: use_end()); |
212 | } |
213 | iterator_range<const_use_iterator> uses() const { |
214 | return make_range<const_use_iterator>(x: use_begin(), y: use_end()); |
215 | } |
216 | |
217 | /// Helper for mapped_iterator. |
218 | struct UseToUser { |
219 | User *operator()(const Use &Use) const { return &*Use.getUser(); } |
220 | }; |
221 | |
222 | using user_iterator = mapped_iterator<sandboxir::UserUseIterator, UseToUser>; |
223 | using const_user_iterator = user_iterator; |
224 | |
225 | user_iterator user_begin(); |
226 | user_iterator user_end() { |
227 | return user_iterator(Use(nullptr, nullptr, Ctx), UseToUser()); |
228 | } |
229 | const_user_iterator user_begin() const { |
230 | return const_cast<Value *>(this)->user_begin(); |
231 | } |
232 | const_user_iterator user_end() const { |
233 | return const_cast<Value *>(this)->user_end(); |
234 | } |
235 | |
236 | iterator_range<user_iterator> users() { |
237 | return make_range<user_iterator>(x: user_begin(), y: user_end()); |
238 | } |
239 | iterator_range<const_user_iterator> users() const { |
240 | return make_range<const_user_iterator>(x: user_begin(), y: user_end()); |
241 | } |
242 | /// \Returns the number of user edges (not necessarily to unique users). |
243 | /// WARNING: This is a linear-time operation. |
244 | unsigned getNumUses() const; |
245 | /// Return true if this value has N uses or more. |
246 | /// This is logically equivalent to getNumUses() >= N. |
247 | /// WARNING: This can be expensive, as it is linear to the number of users. |
248 | bool hasNUsesOrMore(unsigned Num) const { |
249 | unsigned Cnt = 0; |
250 | for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) { |
251 | if (++Cnt >= Num) |
252 | return true; |
253 | } |
254 | return false; |
255 | } |
256 | /// Return true if this Value has exactly N uses. |
257 | bool hasNUses(unsigned Num) const { |
258 | unsigned Cnt = 0; |
259 | for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) { |
260 | if (++Cnt > Num) |
261 | return false; |
262 | } |
263 | return Cnt == Num; |
264 | } |
265 | |
266 | Type *getType() const { return Val->getType(); } |
267 | |
268 | Context &getContext() const { return Ctx; } |
269 | |
270 | void replaceUsesWithIf(Value *OtherV, |
271 | llvm::function_ref<bool(const Use &)> ShouldReplace); |
272 | void replaceAllUsesWith(Value *Other); |
273 | |
274 | /// \Returns the LLVM IR name of the bottom-most LLVM value. |
275 | StringRef getName() const { return Val->getName(); } |
276 | |
277 | #ifndef NDEBUG |
278 | /// Should crash if there is something wrong with the instruction. |
279 | virtual void verify() const = 0; |
280 | /// Returns the unique id in the form 'SB<number>.' like 'SB1.' |
281 | std::string getUid() const; |
282 | virtual void dumpCommonHeader(raw_ostream &OS) const; |
283 | void dumpCommonFooter(raw_ostream &OS) const; |
284 | void dumpCommonPrefix(raw_ostream &OS) const; |
285 | void dumpCommonSuffix(raw_ostream &OS) const; |
286 | void printAsOperandCommon(raw_ostream &OS) const; |
287 | friend raw_ostream &operator<<(raw_ostream &OS, const sandboxir::Value &V) { |
288 | V.dump(OS); |
289 | return OS; |
290 | } |
291 | virtual void dump(raw_ostream &OS) const = 0; |
292 | LLVM_DUMP_METHOD virtual void dump() const = 0; |
293 | #endif |
294 | }; |
295 | |
296 | /// Argument of a sandboxir::Function. |
297 | class Argument : public sandboxir::Value { |
298 | Argument(llvm::Argument *Arg, sandboxir::Context &Ctx) |
299 | : sandboxir::Value(ClassID::Argument, Arg, Ctx) {} |
300 | friend class Context; // For constructor. |
301 | |
302 | public: |
303 | static bool classof(const sandboxir::Value *From) { |
304 | return From->getSubclassID() == ClassID::Argument; |
305 | } |
306 | #ifndef NDEBUG |
307 | void verify() const final { |
308 | assert(isa<llvm::Argument>(Val) && "Expected Argument!" ); |
309 | } |
310 | friend raw_ostream &operator<<(raw_ostream &OS, |
311 | const sandboxir::Argument &TArg) { |
312 | TArg.dump(OS); |
313 | return OS; |
314 | } |
315 | void printAsOperand(raw_ostream &OS) const; |
316 | void dump(raw_ostream &OS) const final; |
317 | LLVM_DUMP_METHOD void dump() const final; |
318 | #endif |
319 | }; |
320 | |
321 | /// A sandboxir::User has operands. |
322 | class User : public Value { |
323 | protected: |
324 | User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {} |
325 | |
326 | /// \Returns the Use edge that corresponds to \p OpIdx. |
327 | /// Note: This is the default implementation that works for instructions that |
328 | /// match the underlying LLVM instruction. All others should use a different |
329 | /// implementation. |
330 | Use getOperandUseDefault(unsigned OpIdx, bool Verify) const; |
331 | /// \Returns the Use for the \p OpIdx'th operand. This is virtual to allow |
332 | /// instructions to deviate from the LLVM IR operands, which is a requirement |
333 | /// for sandboxir Instructions that consist of more than one LLVM Instruction. |
334 | virtual Use getOperandUseInternal(unsigned OpIdx, bool Verify) const = 0; |
335 | friend class OperandUseIterator; // for getOperandUseInternal() |
336 | |
337 | /// The default implementation works only for single-LLVMIR-instruction |
338 | /// Users and only if they match exactly the LLVM instruction. |
339 | unsigned getUseOperandNoDefault(const Use &Use) const { |
340 | return Use.LLVMUse->getOperandNo(); |
341 | } |
342 | /// \Returns the operand index of \p Use. |
343 | virtual unsigned getUseOperandNo(const Use &Use) const = 0; |
344 | friend unsigned Use::getOperandNo() const; // For getUseOperandNo() |
345 | |
346 | #ifndef NDEBUG |
347 | void verifyUserOfLLVMUse(const llvm::Use &Use) const; |
348 | #endif // NDEBUG |
349 | |
350 | public: |
351 | /// For isa/dyn_cast. |
352 | static bool classof(const Value *From); |
353 | using op_iterator = OperandUseIterator; |
354 | using const_op_iterator = OperandUseIterator; |
355 | using op_range = iterator_range<op_iterator>; |
356 | using const_op_range = iterator_range<const_op_iterator>; |
357 | |
358 | virtual op_iterator op_begin() { |
359 | assert(isa<llvm::User>(Val) && "Expect User value!" ); |
360 | return op_iterator(getOperandUseInternal(OpIdx: 0, /*Verify=*/Verify: false)); |
361 | } |
362 | virtual op_iterator op_end() { |
363 | assert(isa<llvm::User>(Val) && "Expect User value!" ); |
364 | return op_iterator( |
365 | getOperandUseInternal(OpIdx: getNumOperands(), /*Verify=*/Verify: false)); |
366 | } |
367 | virtual const_op_iterator op_begin() const { |
368 | return const_cast<User *>(this)->op_begin(); |
369 | } |
370 | virtual const_op_iterator op_end() const { |
371 | return const_cast<User *>(this)->op_end(); |
372 | } |
373 | |
374 | op_range operands() { return make_range<op_iterator>(x: op_begin(), y: op_end()); } |
375 | const_op_range operands() const { |
376 | return make_range<const_op_iterator>(x: op_begin(), y: op_end()); |
377 | } |
378 | Value *getOperand(unsigned OpIdx) const { return getOperandUse(OpIdx).get(); } |
379 | /// \Returns the operand edge for \p OpIdx. NOTE: This should also work for |
380 | /// OpIdx == getNumOperands(), which is used for op_end(). |
381 | Use getOperandUse(unsigned OpIdx) const { |
382 | return getOperandUseInternal(OpIdx, /*Verify=*/Verify: true); |
383 | } |
384 | virtual unsigned getNumOperands() const { |
385 | return isa<llvm::User>(Val) ? cast<llvm::User>(Val)->getNumOperands() : 0; |
386 | } |
387 | |
388 | virtual void setOperand(unsigned OperandIdx, Value *Operand); |
389 | /// Replaces any operands that match \p FromV with \p ToV. Returns whether any |
390 | /// operands were replaced. |
391 | bool replaceUsesOfWith(Value *FromV, Value *ToV); |
392 | |
393 | #ifndef NDEBUG |
394 | void verify() const override { |
395 | assert(isa<llvm::User>(Val) && "Expected User!" ); |
396 | } |
397 | void dumpCommonHeader(raw_ostream &OS) const final; |
398 | void dump(raw_ostream &OS) const override { |
399 | // TODO: Remove this tmp implementation once we get the Instruction classes. |
400 | } |
401 | LLVM_DUMP_METHOD void dump() const override { |
402 | // TODO: Remove this tmp implementation once we get the Instruction classes. |
403 | } |
404 | #endif |
405 | }; |
406 | |
407 | class Constant : public sandboxir::User { |
408 | Constant(llvm::Constant *C, sandboxir::Context &SBCtx) |
409 | : sandboxir::User(ClassID::Constant, C, SBCtx) {} |
410 | friend class Context; // For constructor. |
411 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
412 | return getOperandUseDefault(OpIdx, Verify); |
413 | } |
414 | |
415 | public: |
416 | static Constant *createInt(Type *Ty, uint64_t V, Context &Ctx, |
417 | bool IsSigned = false); |
418 | /// For isa/dyn_cast. |
419 | static bool classof(const sandboxir::Value *From) { |
420 | return From->getSubclassID() == ClassID::Constant || |
421 | From->getSubclassID() == ClassID::Function; |
422 | } |
423 | sandboxir::Context &getParent() const { return getContext(); } |
424 | unsigned getUseOperandNo(const Use &Use) const final { |
425 | return getUseOperandNoDefault(Use); |
426 | } |
427 | #ifndef NDEBUG |
428 | void verify() const final { |
429 | assert(isa<llvm::Constant>(Val) && "Expected Constant!" ); |
430 | } |
431 | friend raw_ostream &operator<<(raw_ostream &OS, |
432 | const sandboxir::Constant &SBC) { |
433 | SBC.dump(OS); |
434 | return OS; |
435 | } |
436 | void dump(raw_ostream &OS) const override; |
437 | LLVM_DUMP_METHOD void dump() const override; |
438 | #endif |
439 | }; |
440 | |
441 | /// Iterator for `Instruction`s in a `BasicBlock. |
442 | /// \Returns an sandboxir::Instruction & when derereferenced. |
443 | class BBIterator { |
444 | public: |
445 | using difference_type = std::ptrdiff_t; |
446 | using value_type = Instruction; |
447 | using pointer = value_type *; |
448 | using reference = value_type &; |
449 | using iterator_category = std::bidirectional_iterator_tag; |
450 | |
451 | private: |
452 | llvm::BasicBlock *BB; |
453 | llvm::BasicBlock::iterator It; |
454 | Context *Ctx; |
455 | pointer getInstr(llvm::BasicBlock::iterator It) const; |
456 | |
457 | public: |
458 | BBIterator() : BB(nullptr), Ctx(nullptr) {} |
459 | BBIterator(llvm::BasicBlock *BB, llvm::BasicBlock::iterator It, Context *Ctx) |
460 | : BB(BB), It(It), Ctx(Ctx) {} |
461 | reference operator*() const { return *getInstr(It); } |
462 | BBIterator &operator++(); |
463 | BBIterator operator++(int) { |
464 | auto Copy = *this; |
465 | ++*this; |
466 | return Copy; |
467 | } |
468 | BBIterator &operator--(); |
469 | BBIterator operator--(int) { |
470 | auto Copy = *this; |
471 | --*this; |
472 | return Copy; |
473 | } |
474 | bool operator==(const BBIterator &Other) const { |
475 | assert(Ctx == Other.Ctx && "BBIterators in different context!" ); |
476 | return It == Other.It; |
477 | } |
478 | bool operator!=(const BBIterator &Other) const { return !(*this == Other); } |
479 | /// \Returns the SBInstruction that corresponds to this iterator, or null if |
480 | /// the instruction is not found in the IR-to-SandboxIR tables. |
481 | pointer get() const { return getInstr(It); } |
482 | }; |
483 | |
484 | /// A sandboxir::User with operands, opcode and linked with previous/next |
485 | /// instructions in an instruction list. |
486 | class Instruction : public sandboxir::User { |
487 | public: |
488 | enum class Opcode { |
489 | #define DEF_VALUE(ID, CLASS) |
490 | #define DEF_USER(ID, CLASS) |
491 | #define OP(OPC) OPC, |
492 | #define DEF_INSTR(ID, OPC, CLASS) OPC |
493 | #include "llvm/SandboxIR/SandboxIRValues.def" |
494 | }; |
495 | |
496 | protected: |
497 | Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I, |
498 | sandboxir::Context &SBCtx) |
499 | : sandboxir::User(ID, I, SBCtx), Opc(Opc) {} |
500 | |
501 | Opcode Opc; |
502 | |
503 | /// A SandboxIR Instruction may map to multiple LLVM IR Instruction. This |
504 | /// returns its topmost LLVM IR instruction. |
505 | llvm::Instruction *getTopmostLLVMInstruction() const; |
506 | friend class SelectInst; // For getTopmostLLVMInstruction(). |
507 | friend class LoadInst; // For getTopmostLLVMInstruction(). |
508 | friend class StoreInst; // For getTopmostLLVMInstruction(). |
509 | friend class ReturnInst; // For getTopmostLLVMInstruction(). |
510 | |
511 | /// \Returns the LLVM IR Instructions that this SandboxIR maps to in program |
512 | /// order. |
513 | virtual SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const = 0; |
514 | friend class EraseFromParent; // For getLLVMInstrs(). |
515 | |
516 | public: |
517 | static const char *getOpcodeName(Opcode Opc); |
518 | #ifndef NDEBUG |
519 | friend raw_ostream &operator<<(raw_ostream &OS, Opcode Opc) { |
520 | OS << getOpcodeName(Opc); |
521 | return OS; |
522 | } |
523 | #endif |
524 | /// This is used by BasicBlock::iterator. |
525 | virtual unsigned getNumOfIRInstrs() const = 0; |
526 | /// \Returns a BasicBlock::iterator for this Instruction. |
527 | BBIterator getIterator() const; |
528 | /// \Returns the next sandboxir::Instruction in the block, or nullptr if at |
529 | /// the end of the block. |
530 | Instruction *getNextNode() const; |
531 | /// \Returns the previous sandboxir::Instruction in the block, or nullptr if |
532 | /// at the beginning of the block. |
533 | Instruction *getPrevNode() const; |
534 | /// \Returns this Instruction's opcode. Note that SandboxIR has its own opcode |
535 | /// state to allow for new SandboxIR-specific instructions. |
536 | Opcode getOpcode() const { return Opc; } |
537 | /// Detach this from its parent BasicBlock without deleting it. |
538 | void removeFromParent(); |
539 | /// Detach this Value from its parent and delete it. |
540 | void eraseFromParent(); |
541 | /// Insert this detached instruction before \p BeforeI. |
542 | void insertBefore(Instruction *BeforeI); |
543 | /// Insert this detached instruction after \p AfterI. |
544 | void insertAfter(Instruction *AfterI); |
545 | /// Insert this detached instruction into \p BB at \p WhereIt. |
546 | void insertInto(BasicBlock *BB, const BBIterator &WhereIt); |
547 | /// Move this instruction to \p WhereIt. |
548 | void moveBefore(BasicBlock &BB, const BBIterator &WhereIt); |
549 | /// Move this instruction before \p Before. |
550 | void moveBefore(Instruction *Before) { |
551 | moveBefore(BB&: *Before->getParent(), WhereIt: Before->getIterator()); |
552 | } |
553 | /// Move this instruction after \p After. |
554 | void moveAfter(Instruction *After) { |
555 | moveBefore(BB&: *After->getParent(), WhereIt: std::next(x: After->getIterator())); |
556 | } |
557 | /// \Returns the BasicBlock containing this Instruction, or null if it is |
558 | /// detached. |
559 | BasicBlock *getParent() const; |
560 | /// For isa/dyn_cast. |
561 | static bool classof(const sandboxir::Value *From); |
562 | |
563 | #ifndef NDEBUG |
564 | friend raw_ostream &operator<<(raw_ostream &OS, |
565 | const sandboxir::Instruction &SBI) { |
566 | SBI.dump(OS); |
567 | return OS; |
568 | } |
569 | void dump(raw_ostream &OS) const override; |
570 | LLVM_DUMP_METHOD void dump() const override; |
571 | #endif |
572 | }; |
573 | |
574 | class SelectInst : public Instruction { |
575 | /// Use Context::createSelectInst(). Don't call the |
576 | /// constructor directly. |
577 | SelectInst(llvm::SelectInst *CI, Context &Ctx) |
578 | : Instruction(ClassID::Select, Opcode::Select, CI, Ctx) {} |
579 | friend Context; // for SelectInst() |
580 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
581 | return getOperandUseDefault(OpIdx, Verify); |
582 | } |
583 | SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final { |
584 | return {cast<llvm::Instruction>(Val)}; |
585 | } |
586 | static Value *createCommon(Value *Cond, Value *True, Value *False, |
587 | const Twine &Name, IRBuilder<> &Builder, |
588 | Context &Ctx); |
589 | |
590 | public: |
591 | unsigned getUseOperandNo(const Use &Use) const final { |
592 | return getUseOperandNoDefault(Use); |
593 | } |
594 | unsigned getNumOfIRInstrs() const final { return 1u; } |
595 | static Value *create(Value *Cond, Value *True, Value *False, |
596 | Instruction *InsertBefore, Context &Ctx, |
597 | const Twine &Name = "" ); |
598 | static Value *create(Value *Cond, Value *True, Value *False, |
599 | BasicBlock *InsertAtEnd, Context &Ctx, |
600 | const Twine &Name = "" ); |
601 | Value *getCondition() { return getOperand(OpIdx: 0); } |
602 | Value *getTrueValue() { return getOperand(OpIdx: 1); } |
603 | Value *getFalseValue() { return getOperand(OpIdx: 2); } |
604 | |
605 | void setCondition(Value *New) { setOperand(OperandIdx: 0, Operand: New); } |
606 | void setTrueValue(Value *New) { setOperand(OperandIdx: 1, Operand: New); } |
607 | void setFalseValue(Value *New) { setOperand(OperandIdx: 2, Operand: New); } |
608 | void swapValues() { cast<llvm::SelectInst>(Val)->swapValues(); } |
609 | /// For isa/dyn_cast. |
610 | static bool classof(const Value *From); |
611 | #ifndef NDEBUG |
612 | void verify() const final { |
613 | assert(isa<llvm::SelectInst>(Val) && "Expected SelectInst!" ); |
614 | } |
615 | void dump(raw_ostream &OS) const override; |
616 | LLVM_DUMP_METHOD void dump() const override; |
617 | #endif |
618 | }; |
619 | |
620 | class LoadInst final : public Instruction { |
621 | /// Use LoadInst::create() instead of calling the constructor. |
622 | LoadInst(llvm::LoadInst *LI, Context &Ctx) |
623 | : Instruction(ClassID::Load, Opcode::Load, LI, Ctx) {} |
624 | friend Context; // for LoadInst() |
625 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
626 | return getOperandUseDefault(OpIdx, Verify); |
627 | } |
628 | SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final { |
629 | return {cast<llvm::Instruction>(Val)}; |
630 | } |
631 | |
632 | public: |
633 | unsigned getUseOperandNo(const Use &Use) const final { |
634 | return getUseOperandNoDefault(Use); |
635 | } |
636 | |
637 | unsigned getNumOfIRInstrs() const final { return 1u; } |
638 | static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, |
639 | Instruction *InsertBefore, Context &Ctx, |
640 | const Twine &Name = "" ); |
641 | static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align, |
642 | BasicBlock *InsertAtEnd, Context &Ctx, |
643 | const Twine &Name = "" ); |
644 | /// For isa/dyn_cast. |
645 | static bool classof(const Value *From); |
646 | Value *getPointerOperand() const; |
647 | Align getAlign() const { return cast<llvm::LoadInst>(Val)->getAlign(); } |
648 | bool isUnordered() const { return cast<llvm::LoadInst>(Val)->isUnordered(); } |
649 | bool isSimple() const { return cast<llvm::LoadInst>(Val)->isSimple(); } |
650 | #ifndef NDEBUG |
651 | void verify() const final { |
652 | assert(isa<llvm::LoadInst>(Val) && "Expected LoadInst!" ); |
653 | } |
654 | void dump(raw_ostream &OS) const override; |
655 | LLVM_DUMP_METHOD void dump() const override; |
656 | #endif |
657 | }; |
658 | |
659 | class StoreInst final : public Instruction { |
660 | /// Use StoreInst::create(). |
661 | StoreInst(llvm::StoreInst *SI, Context &Ctx) |
662 | : Instruction(ClassID::Store, Opcode::Store, SI, Ctx) {} |
663 | friend Context; // for StoreInst() |
664 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
665 | return getOperandUseDefault(OpIdx, Verify); |
666 | } |
667 | SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final { |
668 | return {cast<llvm::Instruction>(Val)}; |
669 | } |
670 | |
671 | public: |
672 | unsigned getUseOperandNo(const Use &Use) const final { |
673 | return getUseOperandNoDefault(Use); |
674 | } |
675 | unsigned getNumOfIRInstrs() const final { return 1u; } |
676 | static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, |
677 | Instruction *InsertBefore, Context &Ctx); |
678 | static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align, |
679 | BasicBlock *InsertAtEnd, Context &Ctx); |
680 | /// For isa/dyn_cast. |
681 | static bool classof(const Value *From); |
682 | Value *getValueOperand() const; |
683 | Value *getPointerOperand() const; |
684 | Align getAlign() const { return cast<llvm::StoreInst>(Val)->getAlign(); } |
685 | bool isSimple() const { return cast<llvm::StoreInst>(Val)->isSimple(); } |
686 | bool isUnordered() const { return cast<llvm::StoreInst>(Val)->isUnordered(); } |
687 | #ifndef NDEBUG |
688 | void verify() const final { |
689 | assert(isa<llvm::StoreInst>(Val) && "Expected StoreInst!" ); |
690 | } |
691 | void dump(raw_ostream &OS) const override; |
692 | LLVM_DUMP_METHOD void dump() const override; |
693 | #endif |
694 | }; |
695 | |
696 | class ReturnInst final : public Instruction { |
697 | /// Use ReturnInst::create() instead of calling the constructor. |
698 | ReturnInst(llvm::Instruction *I, Context &Ctx) |
699 | : Instruction(ClassID::Ret, Opcode::Ret, I, Ctx) {} |
700 | ReturnInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx) |
701 | : Instruction(SubclassID, Opcode::Ret, I, Ctx) {} |
702 | friend class Context; // For accessing the constructor in create*() |
703 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
704 | return getOperandUseDefault(OpIdx, Verify); |
705 | } |
706 | SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final { |
707 | return {cast<llvm::Instruction>(Val)}; |
708 | } |
709 | static ReturnInst *createCommon(Value *RetVal, IRBuilder<> &Builder, |
710 | Context &Ctx); |
711 | |
712 | public: |
713 | static ReturnInst *create(Value *RetVal, Instruction *InsertBefore, |
714 | Context &Ctx); |
715 | static ReturnInst *create(Value *RetVal, BasicBlock *InsertAtEnd, |
716 | Context &Ctx); |
717 | static bool classof(const Value *From) { |
718 | return From->getSubclassID() == ClassID::Ret; |
719 | } |
720 | unsigned getUseOperandNo(const Use &Use) const final { |
721 | return getUseOperandNoDefault(Use); |
722 | } |
723 | unsigned getNumOfIRInstrs() const final { return 1u; } |
724 | /// \Returns null if there is no return value. |
725 | Value *getReturnValue() const; |
726 | #ifndef NDEBUG |
727 | void verify() const final {} |
728 | void dump(raw_ostream &OS) const override; |
729 | LLVM_DUMP_METHOD void dump() const override; |
730 | #endif |
731 | }; |
732 | |
733 | /// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to |
734 | /// an OpaqueInstr. |
735 | class OpaqueInst : public sandboxir::Instruction { |
736 | OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx) |
737 | : sandboxir::Instruction(ClassID::Opaque, Opcode::Opaque, I, Ctx) {} |
738 | OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx) |
739 | : sandboxir::Instruction(SubclassID, Opcode::Opaque, I, Ctx) {} |
740 | friend class Context; // For constructor. |
741 | Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { |
742 | return getOperandUseDefault(OpIdx, Verify); |
743 | } |
744 | SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final { |
745 | return {cast<llvm::Instruction>(Val)}; |
746 | } |
747 | |
748 | public: |
749 | static bool classof(const sandboxir::Value *From) { |
750 | return From->getSubclassID() == ClassID::Opaque; |
751 | } |
752 | unsigned getUseOperandNo(const Use &Use) const final { |
753 | return getUseOperandNoDefault(Use); |
754 | } |
755 | unsigned getNumOfIRInstrs() const final { return 1u; } |
756 | #ifndef NDEBUG |
757 | void verify() const final { |
758 | // Nothing to do |
759 | } |
760 | friend raw_ostream &operator<<(raw_ostream &OS, |
761 | const sandboxir::OpaqueInst &OI) { |
762 | OI.dump(OS); |
763 | return OS; |
764 | } |
765 | void dump(raw_ostream &OS) const override; |
766 | LLVM_DUMP_METHOD void dump() const override; |
767 | #endif |
768 | }; |
769 | |
770 | /// Contains a list of sandboxir::Instruction's. |
771 | class BasicBlock : public Value { |
772 | /// Builds a graph that contains all values in \p BB in their original form |
773 | /// i.e., no vectorization is taking place here. |
774 | void buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB); |
775 | friend class Context; // For `buildBasicBlockFromIR` |
776 | friend class Instruction; // For LLVM Val. |
777 | |
778 | BasicBlock(llvm::BasicBlock *BB, Context &SBCtx) |
779 | : Value(ClassID::Block, BB, SBCtx) { |
780 | buildBasicBlockFromLLVMIR(LLVMBB: BB); |
781 | } |
782 | |
783 | public: |
784 | ~BasicBlock() = default; |
785 | /// For isa/dyn_cast. |
786 | static bool classof(const Value *From) { |
787 | return From->getSubclassID() == Value::ClassID::Block; |
788 | } |
789 | Function *getParent() const; |
790 | using iterator = BBIterator; |
791 | iterator begin() const; |
792 | iterator end() const { |
793 | auto *BB = cast<llvm::BasicBlock>(Val); |
794 | return iterator(BB, BB->end(), &Ctx); |
795 | } |
796 | std::reverse_iterator<iterator> rbegin() const { |
797 | return std::make_reverse_iterator(i: end()); |
798 | } |
799 | std::reverse_iterator<iterator> rend() const { |
800 | return std::make_reverse_iterator(i: begin()); |
801 | } |
802 | Context &getContext() const { return Ctx; } |
803 | Instruction *getTerminator() const; |
804 | bool empty() const { return begin() == end(); } |
805 | Instruction &front() const; |
806 | Instruction &back() const; |
807 | |
808 | #ifndef NDEBUG |
809 | void verify() const final { |
810 | assert(isa<llvm::BasicBlock>(Val) && "Expected BasicBlock!" ); |
811 | } |
812 | friend raw_ostream &operator<<(raw_ostream &OS, const BasicBlock &SBBB) { |
813 | SBBB.dump(OS); |
814 | return OS; |
815 | } |
816 | void dump(raw_ostream &OS) const final; |
817 | LLVM_DUMP_METHOD void dump() const final; |
818 | #endif |
819 | }; |
820 | |
821 | class Context { |
822 | protected: |
823 | LLVMContext &LLVMCtx; |
824 | Tracker IRTracker; |
825 | |
826 | /// Maps LLVM Value to the corresponding sandboxir::Value. Owns all |
827 | /// SandboxIR objects. |
828 | DenseMap<llvm::Value *, std::unique_ptr<sandboxir::Value>> |
829 | LLVMValueToValueMap; |
830 | |
831 | /// Remove \p V from the maps and returns the unique_ptr. |
832 | std::unique_ptr<Value> detachLLVMValue(llvm::Value *V); |
833 | /// Remove \p SBV from all SandboxIR maps and stop owning it. This effectively |
834 | /// detaches \p V from the underlying IR. |
835 | std::unique_ptr<Value> detach(Value *V); |
836 | friend void Instruction::eraseFromParent(); // For detach(). |
837 | /// Take ownership of VPtr and store it in `LLVMValueToValueMap`. |
838 | Value *registerValue(std::unique_ptr<Value> &&VPtr); |
839 | friend class EraseFromParent; // For registerValue(). |
840 | /// This is the actual function that creates sandboxir values for \p V, |
841 | /// and among others handles all instruction types. |
842 | Value *getOrCreateValueInternal(llvm::Value *V, llvm::User *U = nullptr); |
843 | /// Get or create a sandboxir::Argument for an existing LLVM IR \p LLVMArg. |
844 | Argument *getOrCreateArgument(llvm::Argument *LLVMArg) { |
845 | auto Pair = LLVMValueToValueMap.insert(KV: {LLVMArg, nullptr}); |
846 | auto It = Pair.first; |
847 | if (Pair.second) { |
848 | It->second = std::unique_ptr<Argument>(new Argument(LLVMArg, *this)); |
849 | return cast<Argument>(Val: It->second.get()); |
850 | } |
851 | return cast<Argument>(Val: It->second.get()); |
852 | } |
853 | /// Get or create a sandboxir::Value for an existing LLVM IR \p LLVMV. |
854 | Value *getOrCreateValue(llvm::Value *LLVMV) { |
855 | return getOrCreateValueInternal(V: LLVMV, U: 0); |
856 | } |
857 | /// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC. |
858 | Constant *getOrCreateConstant(llvm::Constant *LLVMC) { |
859 | return cast<Constant>(Val: getOrCreateValueInternal(V: LLVMC, U: 0)); |
860 | } |
861 | friend class Constant; // For getOrCreateConstant(). |
862 | /// Create a sandboxir::BasicBlock for an existing LLVM IR \p BB. This will |
863 | /// also create all contents of the block. |
864 | BasicBlock *createBasicBlock(llvm::BasicBlock *BB); |
865 | |
866 | friend class BasicBlock; // For getOrCreateValue(). |
867 | |
868 | IRBuilder<ConstantFolder> LLVMIRBuilder; |
869 | auto &getLLVMIRBuilder() { return LLVMIRBuilder; } |
870 | |
871 | SelectInst *createSelectInst(llvm::SelectInst *SI); |
872 | friend SelectInst; // For createSelectInst() |
873 | LoadInst *createLoadInst(llvm::LoadInst *LI); |
874 | friend LoadInst; // For createLoadInst() |
875 | StoreInst *createStoreInst(llvm::StoreInst *SI); |
876 | friend StoreInst; // For createStoreInst() |
877 | ReturnInst *createReturnInst(llvm::ReturnInst *I); |
878 | friend ReturnInst; // For createReturnInst() |
879 | |
880 | public: |
881 | Context(LLVMContext &LLVMCtx) |
882 | : LLVMCtx(LLVMCtx), IRTracker(*this), |
883 | LLVMIRBuilder(LLVMCtx, ConstantFolder()) {} |
884 | |
885 | Tracker &getTracker() { return IRTracker; } |
886 | /// Convenience function for `getTracker().save()` |
887 | void save() { IRTracker.save(); } |
888 | /// Convenience function for `getTracker().revert()` |
889 | void revert() { IRTracker.revert(); } |
890 | /// Convenience function for `getTracker().accept()` |
891 | void accept() { IRTracker.accept(); } |
892 | |
893 | sandboxir::Value *getValue(llvm::Value *V) const; |
894 | const sandboxir::Value *getValue(const llvm::Value *V) const { |
895 | return getValue(V: const_cast<llvm::Value *>(V)); |
896 | } |
897 | /// Create a sandboxir::Function for an existing LLVM IR \p F, including all |
898 | /// blocks and instructions. |
899 | /// This is the main API function for creating Sandbox IR. |
900 | Function *createFunction(llvm::Function *F); |
901 | |
902 | /// \Returns the number of values registered with Context. |
903 | size_t getNumValues() const { return LLVMValueToValueMap.size(); } |
904 | }; |
905 | |
906 | class Function : public sandboxir::Value { |
907 | /// Helper for mapped_iterator. |
908 | struct LLVMBBToBB { |
909 | Context &Ctx; |
910 | LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {} |
911 | BasicBlock &operator()(llvm::BasicBlock &LLVMBB) const { |
912 | return *cast<BasicBlock>(Val: Ctx.getValue(V: &LLVMBB)); |
913 | } |
914 | }; |
915 | /// Use Context::createFunction() instead. |
916 | Function(llvm::Function *F, sandboxir::Context &Ctx) |
917 | : sandboxir::Value(ClassID::Function, F, Ctx) {} |
918 | friend class Context; // For constructor. |
919 | |
920 | public: |
921 | /// For isa/dyn_cast. |
922 | static bool classof(const sandboxir::Value *From) { |
923 | return From->getSubclassID() == ClassID::Function; |
924 | } |
925 | |
926 | Argument *getArg(unsigned Idx) const { |
927 | llvm::Argument *Arg = cast<llvm::Function>(Val)->getArg(i: Idx); |
928 | return cast<Argument>(Val: Ctx.getValue(V: Arg)); |
929 | } |
930 | |
931 | size_t arg_size() const { return cast<llvm::Function>(Val)->arg_size(); } |
932 | bool arg_empty() const { return cast<llvm::Function>(Val)->arg_empty(); } |
933 | |
934 | using iterator = mapped_iterator<llvm::Function::iterator, LLVMBBToBB>; |
935 | iterator begin() const { |
936 | LLVMBBToBB BBGetter(Ctx); |
937 | return iterator(cast<llvm::Function>(Val)->begin(), BBGetter); |
938 | } |
939 | iterator end() const { |
940 | LLVMBBToBB BBGetter(Ctx); |
941 | return iterator(cast<llvm::Function>(Val)->end(), BBGetter); |
942 | } |
943 | |
944 | #ifndef NDEBUG |
945 | void verify() const final { |
946 | assert(isa<llvm::Function>(Val) && "Expected Function!" ); |
947 | } |
948 | void dumpNameAndArgs(raw_ostream &OS) const; |
949 | void dump(raw_ostream &OS) const final; |
950 | LLVM_DUMP_METHOD void dump() const final; |
951 | #endif |
952 | }; |
953 | |
954 | } // namespace sandboxir |
955 | } // namespace llvm |
956 | |
957 | #endif // LLVM_SANDBOXIR_SANDBOXIR_H |
958 | |