1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/IR/IR.h"
18#include "glow/Graph/FXIRWrapper.h"
19#include "glow/Graph/Graph.h"
20#include "glow/IR/IRUtils.h"
21#include "glow/IR/Instrs.h"
22#include "glow/Support/Support.h"
23
24#include "llvm/ADT/StringSet.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/raw_ostream.h"
28
29#include <fstream>
30#include <iostream>
31#include <sstream>
32#include <unordered_set>
33
34using namespace glow;
35using llvm::cast;
36using llvm::dyn_cast;
37using llvm::isa;
38
39//===----------------------------------------------------------------------===//
40// General IR operations
41//===----------------------------------------------------------------------===//
42
43bool Instruction::classof(const Value *V) {
44#define DEF_VALUE(CLASS, NAME)
45#define DEF_INSTR(CLASS, NAME)
46#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME)
47#define DEF_INSTR_RANGE(CLASS, FIRST, LAST) \
48 constexpr auto First_##CLASS = Kinded::Kind::FIRST##Kind; \
49 constexpr auto Last_##CLASS = Kinded::Kind::LAST##Kind;
50#include "glow/AutoGenInstr.def"
51 return V->getKind() >= First_Instruction && V->getKind() <= Last_Instruction;
52}
53
54void Use::setOperand(Value *other) { use_->setOperand(idx_, other); }
55
56InstructionOperand Use::getOperand() { return use_->getOperand(idx_); }
57
58ConstInstructionOperand Use::getOperand() const {
59 return use_->getOperand(idx_);
60}
61
62Value *Instruction::getPredicate() const {
63 assert(hasPredicate() && "No predicate is set");
64 return getOperand(predicateIndex_).first;
65}
66
67void Instruction::setPredicate(Value *p) {
68 // Push a new predicate.
69 if (!hasPredicate()) {
70 predicateIndex_ = getNumOperands();
71 pushOperand({p, OperandKind::In});
72 }
73
74 setOperand(predicateIndex_, p);
75}
76
77bool Instruction::hasPredicate() const { return predicateIndex_ > 0; }
78
79void Instruction::pushOperand(Operand op) {
80 ops_.emplace_back(nullptr, op.second);
81 setOperand(ops_.size() - 1, op.first);
82}
83
84void Instruction::setOperand(unsigned idx, Value *v) {
85 auto *currVal = ops_[idx].first;
86
87 if (currVal == v) {
88 return;
89 }
90
91 if (currVal) {
92 currVal->removeUse(Use(idx, this));
93 }
94
95 if (v) {
96 ops_[idx].first = v;
97 v->addUse(Use(idx, this));
98 }
99}
100
101Instruction::Operand Instruction::getOperand(unsigned idx) const {
102 assert(ops_.size() > idx && "Invalid operand");
103 return ops_[idx];
104}
105
106unsigned Instruction::getNumInputs() const {
107 unsigned numInputs = 0;
108 for (const auto &op : ops_) {
109 if (op.second != OperandKind::Out) {
110 numInputs++;
111 }
112 }
113 return numInputs;
114}
115
116unsigned Instruction::getNumOutputs() const {
117 unsigned numOutputs = 0;
118 for (const auto &op : ops_) {
119 if (op.second != OperandKind::In) {
120 numOutputs++;
121 }
122 }
123 return numOutputs;
124}
125
126llvm::StringRef Instruction::getOperandName(unsigned idx) const {
127 switch (getKind()) {
128#define DEF_INSTR(CLASS, NAME) \
129 case glow::Kinded::Kind::CLASS##Kind: \
130 return static_cast<const CLASS *>(this)->getOperandName(idx);
131#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
132#define DEF_VALUE(CLASS, NAME)
133#include "glow/AutoGenInstr.def"
134 default:
135 llvm_unreachable("Unhandled instruction");
136 }
137}
138
139void Instruction::eraseFromParent() { getParent()->eraseInstruction(this); }
140
141bool Instruction::verifyUseList(
142 const InstructionNumbering &InstrNumbering) const {
143 for (const auto &op : ops_) {
144 auto *v = op.first;
145 (void)v;
146 assert(v && "Instruction operand must be a real value");
147 assert(v->hasUser(this) && "Invalid use-list");
148 v->verifyUseList(InstrNumbering);
149 }
150 return true;
151}
152
153bool Instruction::verify() const {
154 // All operands of instructions must be either memory (AllocActivation or
155 // WeightVar), or a TensorView of such.
156 for (const auto &opPair : getOperands()) {
157 const Value *op = opPair.first;
158 (void)op;
159 assert((isa<AllocActivationInst>(op) || isa<WeightVar>(op) ||
160 isa<TensorViewInst>(op)) &&
161 "Operands must be one of {AllocActivation, WeightVar, TensorView}");
162 }
163
164 // Perform Instruction-specific verification.
165#define DEF_INSTR(CLASS, NAME) \
166 if (auto *X = dyn_cast<const CLASS>(this)) \
167 X->verify();
168#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
169#define DEF_VALUE(CLASS, NAME)
170#include "glow/AutoGenInstr.def"
171 return true;
172}
173
174bool Value::verify(const IRFunction &M) const { return true; }
175
176bool Value::verifyUseList(const InstructionNumbering &InstrNumbering) const {
177 auto users = getUsers();
178 for (const auto &use : users) {
179 auto *I = use.get();
180 (void)I;
181 // Every instruction using this value should be in the instruction list.
182 assert(InstrNumbering.getInstrNumber(I) != -1);
183 // All uses must come after defs.
184 assert(!isa<Instruction>(this) ||
185 InstrNumbering.getInstrNumber(I) >
186 InstrNumbering.getInstrNumber(cast<Instruction>(this)));
187 }
188 return true;
189}
190
191void Instruction::destroyInstruction(Instruction *I) {
192 switch (I->getKind()) {
193 default:
194 llvm_unreachable("Unknown value kind");
195 break;
196#define DEF_INSTR(CLASS, NAME) \
197 case Kinded::Kind::CLASS##Kind: { \
198 delete llvm::cast<CLASS>(I); \
199 break; \
200 }
201#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
202#define DEF_VALUE(CLASS, NAME)
203#include "glow/AutoGenInstr.def"
204 }
205}
206
207void IRFunction::eraseInstruction(glow::Instruction *I) {
208 assert(I->getParent() == this &&
209 "Cannot erase an instruction not belonging to a function");
210 instrs_.erase(I);
211}
212
213InstrIterator IRFunction::removeInstruction(glow::Instruction *I) {
214 assert(I->getParent() == this &&
215 "Cannot erase an instruction not beloning to a function");
216 auto result = I->getIterator();
217 ++result;
218 instrs_.remove(I);
219 return result;
220}
221
222void IRFunction::insertInstruction(glow::Instruction *I) {
223 instrs_.push_back(I);
224}
225
226InstrIterator IRFunction::insertInstruction(glow::Instruction *where,
227 glow::Instruction *I) {
228 return instrs_.insert(where->getIterator(), I);
229}
230
231InstrIterator IRFunction::moveInstruction(Instruction *where,
232 glow::Instruction *I) {
233 I->getParent()->removeInstruction(I);
234 return insertInstruction(where, I);
235}
236
237IRFunction::~IRFunction() { clear(); }
238
239void IRFunction::clear() {
240 // Remove the mapping between the graph nodes and the IR that we are deleting.
241 variableMap_.clear();
242
243 // Delete all of the instructions, in reverse order, to make sure that
244 // we delete the users before the instructions.
245 for (auto it = instrs_.rbegin(), e = instrs_.rend(); it != e;) {
246 auto *curI = &*it;
247 ++it;
248 Instruction::destroyInstruction(curI);
249 }
250
251 // Delete all of the weights.
252 for (auto &I : weights_) {
253 delete I;
254 }
255 // TaggedList's destructor is going to destroy the InstList.
256 instrs_.clearAndLeakNodesUnsafely();
257 weights_.clear();
258
259 G_ = nullptr;
260}
261
262static void LLVM_ATTRIBUTE_UNUSED verifyOperandsAccess(const Instruction *I) {
263 if (llvm::isa<CopyInst>(I))
264 return;
265 for (size_t opIdx = 0, e = I->getNumOperands(); opIdx < e; ++opIdx) {
266 auto op = I->getOperand(opIdx);
267 auto opKind = op.second;
268 auto opValue = op.first;
269 // Check that an instruction never tries to update a constant argument.
270 if (opKind != OperandKind::In) {
271 if (auto *W = llvm::dyn_cast<WeightVar>(opValue)) {
272 assert(W->getMutability() != WeightVar::MutabilityKind::Constant &&
273 "Constant weights cannot be updated");
274 (void)W;
275 }
276 }
277 // If the same operand is used multiple times by an instruction,
278 // check that it is a valid access pattern.
279 for (size_t nextOpIdx = opIdx + 1; nextOpIdx < e; ++nextOpIdx) {
280 auto nextOp = I->getOperand(nextOpIdx);
281 auto nextOpKind = nextOp.second;
282 auto nextOpValue = nextOp.first;
283 // Bail if it is a different value.
284 if (opValue != nextOpValue)
285 continue;
286 // It is OK to write into the same buffer if the instruction permits such
287 // an inplace update.
288 if (opKind == OperandKind::In && nextOpKind != OperandKind::In &&
289 Instruction::isInplaceOp(I, nextOpIdx, opIdx))
290 continue;
291 if (opKind != OperandKind::In && nextOpKind == OperandKind::In &&
292 Instruction::isInplaceOp(I, opIdx, nextOpIdx))
293 continue;
294 // If an operand is used as @out or @inout it cannot be used
295 // for anything else.
296 // It is OK to use the same operand as input multiple times.
297 assert(opKind == OperandKind::In && nextOpKind == OperandKind::In &&
298 "Conflicting uses of the same operand by the same instruction");
299 }
300 }
301}
302
303/// Verify that liveness constraints are satisfied.
304/// There should be no uses of an allocation after
305/// it was deallocated or before it is allocated.
306static void verifyLiveness(const IRFunction &M) {
307 // The live set stores allocations that are known to be live.
308 std::unordered_map<const Value *, bool> liveBuffers;
309 for (const auto &I : M.getInstrs()) {
310 if (auto *AI = dyn_cast<AllocActivationInst>(&I)) {
311 assert(liveBuffers.find(AI) == liveBuffers.end() &&
312 "Redefinition of an existing allocation");
313 liveBuffers.insert({AI, false});
314 continue;
315 }
316 if (auto *DI = dyn_cast<DeallocActivationInst>(&I)) {
317 assert(llvm::isa<AllocActivationInst>(DI->getSrc()) &&
318 "Only allocations can be deallocated");
319 assert(liveBuffers.find(DI->getSrc()) != liveBuffers.end() &&
320 "Deallocation of an allocation that is not alive");
321 liveBuffers.erase(DI->getSrc());
322 continue;
323 }
324 // Do not consider tensorview definitions to be real uses of any
325 // allocations.
326 if (llvm::isa<TensorViewInst>(&I))
327 continue;
328
329 for (const auto &Op : I.getOperands()) {
330 if (auto *AI = dyn_cast<AllocActivationInst>(getOrigin(Op.first))) {
331 auto entry = liveBuffers.find(AI);
332 assert(entry != liveBuffers.end() &&
333 "Allocation should be alive when it is used");
334 assert((Op.second == OperandKind::Out || entry->second) &&
335 "@in and @inout operands should be initialized before their "
336 "first use");
337 // Remember that an allocation was initialized.
338 if (Op.second != OperandKind::In)
339 entry->second = true;
340 }
341 }
342 }
343}
344
345bool IRFunction::verify() const {
346 InstructionNumbering InstrNumbering(*this);
347 assert(!instrs_.empty() && "Instruction list is empty!");
348 llvm::StringSet<> nameSet;
349 for (const auto &I : instrs_) {
350 I.verifyUseList(InstrNumbering);
351 verifyOperandsAccess(&I);
352 I.verify();
353 auto it = nameSet.insert(I.getName());
354 (void)it;
355 assert(it.second && "All Instruction and WeightVar names must be unique.");
356 }
357
358 verifyLiveness(*this);
359
360 for (auto p : variableMap_) {
361 (void)p;
362 assert(p.first->getType() == p.second->getType() &&
363 "Weight and variable must have the same type");
364 p.second->verify(*this);
365 p.second->verifyUseList(InstrNumbering);
366 auto it = nameSet.insert(p.second->getName());
367 (void)it;
368 assert(it.second && "All Instruction and WeightVar names must be unique.");
369 }
370 return true;
371}
372
373Value *IRFunction::getWeightForNode(const Storage *V) const {
374 auto it = variableMap_.find(V);
375 if (it == variableMap_.end()) {
376 return nullptr;
377 }
378
379 return it->second;
380}
381
382bool Instruction::isCanonical() const {
383 switch (getKind()) {
384 default:
385 llvm_unreachable("Unknown value kind");
386 break;
387#define DEF_INSTR(CLASS, NAME) \
388 case Kinded::Kind::CLASS##Kind: { \
389 auto *X = llvm::cast<const CLASS>(this); \
390 return X->isCanonical(); \
391 break; \
392 }
393#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
394#define DEF_VALUE(CLASS, NAME)
395#include "glow/AutoGenInstr.def"
396 }
397 return false;
398}
399
400bool Instruction::isDataParallel() const {
401 switch (getKind()) {
402 default:
403 llvm_unreachable("Unknown value kind");
404 break;
405#define DEF_INSTR(CLASS, NAME) \
406 case Kinded::Kind::CLASS##Kind: { \
407 auto *X = llvm::cast<const CLASS>(this); \
408 return X->isDataParallel(); \
409 break; \
410 }
411#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
412#define DEF_VALUE(CLASS, NAME)
413#include "glow/AutoGenInstr.def"
414 }
415 return false;
416}
417
418Instruction *Instruction::clone() const {
419 switch (getKind()) {
420 default:
421 llvm_unreachable("Unknown value kind");
422 break;
423#define DEF_INSTR(CLASS, NAME) \
424 case Kinded::Kind::CLASS##Kind: { \
425 auto *X = llvm::cast<const CLASS>(this); \
426 return X->clone(); \
427 break; \
428 }
429#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
430#define DEF_VALUE(CLASS, NAME)
431#include "glow/AutoGenInstr.def"
432 }
433 return nullptr;
434}
435
436//===----------------------------------------------------------------------===//
437// Instruction numbering
438//===----------------------------------------------------------------------===//
439
440InstructionNumbering::InstructionNumbering(const IRFunction &M) {
441 auto &instrs = M.getInstrs();
442 size_t instIdx = 0;
443 for (const auto &I : instrs) {
444 numToInstr_.push_back(&I);
445 instrToNum_[&I] = instIdx;
446 ++instIdx;
447 }
448}
449
450int64_t InstructionNumbering::getInstrNumber(const Instruction *I) const {
451 auto Result = instrToNum_.find(I);
452 if (Result == instrToNum_.end())
453 return -1;
454 return (int64_t)Result->second;
455}
456
457const Instruction *InstructionNumbering::getInstr(size_t instrNumber) const {
458 assert(instrNumber < numToInstr_.size());
459 return numToInstr_[instrNumber];
460}
461
462//===----------------------------------------------------------------------===//
463// IR printing and visualizing
464//===----------------------------------------------------------------------===//
465
466static void dumpIR(const Value *V, llvm::raw_ostream &out) {
467 switch (V->getKind()) {
468 default:
469 llvm_unreachable("Unknown value kind");
470 break;
471#define DEF_INSTR(CLASS, NAME) \
472 case Kinded::Kind::CLASS##Kind: { \
473 auto *X = llvm::cast<const CLASS>(V); \
474 X->dump(out); \
475 break; \
476 }
477#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
478#define DEF_VALUE(CLASS, NAME) DEF_INSTR(CLASS, NAME)
479#include "glow/AutoGenInstr.def"
480 }
481}
482
483static void dumpIRInContext(const Value *V, llvm::raw_ostream &out) {
484 // Dump all operands.
485 if (const auto *I = dyn_cast<const Instruction>(V)) {
486 if (I->getNumOperands() > 0)
487 out << "Operands:\n";
488 for (const auto &Op : I->getOperands()) {
489 out << "\t";
490 Op.first->dump(out);
491 out << "\n";
492 }
493 }
494 out << "-> ";
495
496 dumpIR(V, out);
497
498 // Dump all uses.
499 out << "\n";
500 if (V->getNumUsers() > 0)
501 out << "Users:\n";
502 for (const Use &U : V->getUsers()) {
503 out << "\t";
504 U.get()->dump(out);
505 out << "\n";
506 }
507}
508
509std::vector<const Constant *> IRFunction::findConstants() const {
510 std::vector<const Constant *> constants;
511 for (auto &node : variableMap_) {
512 if (const Constant *constant = dyn_cast<const Constant>(node.first)) {
513 constants.push_back(constant);
514 }
515 }
516 return constants;
517}
518
519std::vector<const Placeholder *> IRFunction::findPlaceholders() const {
520 std::vector<const Placeholder *> placeholders;
521 for (auto &node : variableMap_) {
522 if (const Placeholder *PH = dyn_cast<const Placeholder>(node.first)) {
523 placeholders.push_back(PH);
524 }
525 }
526 return placeholders;
527}
528
529/// Dump the instruction numbers of all users of \p V.
530static void dumpUsers(const Value *V, llvm::raw_ostream &out,
531 InstructionNumbering &InstrNumbering) {
532 if (V->getNumUsers() == 0)
533 return;
534 out << " // Users: ";
535 bool isFirst = true;
536 for (auto U = V->getUsers().rbegin(), E = V->getUsers().rend(); U != E; ++U) {
537 auto *I = U->get();
538 if (!isFirst) {
539 out << ", ";
540 }
541
542 out << getOperandKindStr(U->getOperand().second) << " ";
543
544 auto instrNum = InstrNumbering.getInstrNumber(I);
545 assert(instrNum >= 0);
546 out << instrNum;
547 isFirst = false;
548 }
549}
550
551void Value::dump(llvm::raw_ostream &out) const { dumpIR(this, out); }
552
553void Value::dump() const { dumpIR(this, llvm::outs()); }
554
555std::string Value::toString() const {
556 std::string storage;
557 llvm::raw_string_ostream os(storage);
558 dump(os);
559 return os.str();
560}
561
562void Value::dumpInContext(llvm::raw_ostream &out) const {
563 dumpIRInContext(this, out);
564}
565
566void Value::dumpInContext() const { dumpInContext(llvm::outs()); }
567
568bool Instruction::isInplaceOp(const Instruction *I, unsigned dstIdx,
569 unsigned srcIdx) {
570#define DEF_INSTR(CLASS, NAME) \
571 if (const auto *X = dyn_cast<const CLASS>(I)) \
572 return X->isInplaceOp(dstIdx, srcIdx);
573#define DEF_BACKEND_SPECIFIC_INSTR(CLASS, NAME) DEF_INSTR(CLASS, NAME)
574#define DEF_VALUE(CLASS, NAME)
575#include "glow/AutoGenInstr.def"
576
577 llvm_unreachable("Invalid instruction kind.");
578}
579
580void Instruction::dumpOperands(llvm::raw_ostream &os) const {
581 // Dump the predicate of the instruction:
582 if (hasPredicate()) {
583 Value *pred = getPredicate();
584 os << "[ pred: " << pred->getName() << " ] ";
585 }
586
587 // Dump the operands of the instruction:
588 for (size_t i = 0, e = getNumOperands(); i < e; i++) {
589 auto op = getOperand(i);
590 auto cc = getOperandKindStr(op.second);
591 if (i) {
592 os << ", ";
593 }
594 os << cc << " %" << op.first->getName().str();
595 }
596}
597
598IRFunction::IRFunction(IRContainer *G)
599 : IRContainer(G ? G->getName() : llvm::StringRef{}), G_(G) {}
600
601#if FACEBOOK_INTERNAL
602/// \returns a reference to the glow FX graph.
603FXIRWrapper *IRFunction::getFXGraph() {
604 assert(llvm::isa<FXIRWrapper>(G_));
605 return llvm::cast<FXIRWrapper>(G_);
606}
607
608/// \returns a reference to the glow FX graph.
609const FXIRWrapper *IRFunction::getFXGraph() const {
610 assert(llvm::isa<FXIRWrapper>(G_));
611 return llvm::cast<FXIRWrapper>(G_);
612}
613#endif
614
615static bool hasResultValue(const Instruction *I) {
616 return I->getKind() == Instruction::Kind::AllocActivationInstKind ||
617 I->getKind() == Instruction::Kind::TensorViewInstKind;
618}
619
620void IRFunction::dump() const { dump(llvm::outs()); }
621
622void IRFunction::dump(llvm::raw_ostream &OS) const {
623 InstructionNumbering InstrNumbering(*this);
624 // Print all of the variables:
625 std::string s;
626 llvm::raw_string_ostream sb{s};
627 sb << "function " << getName().str() << "\n";
628
629 size_t sizeInBytes = 0;
630 sb << "declare {\n";
631 for (auto it : weights_) {
632 Value *V = it;
633 sb << " ";
634 dumpIR(V, sb);
635 sb << " // size: " << V->getSizeInBytes();
636 dumpUsers(V, sb, InstrNumbering);
637 sb << "\n";
638
639 auto *T = V->getType();
640 sizeInBytes += T->getElementSize() * T->size();
641 }
642
643 sb << "\n ; size = " << sizeInBytes << " bytes\n";
644
645 sb << "}\n\n";
646 sb << "code {\n";
647
648 // Print all of the instructions:
649 for (const auto &I : instrs_) {
650 sb << " ";
651 auto InstrNum = InstrNumbering.getInstrNumber(&I);
652 assert(InstrNum >= 0);
653 sb << InstrNum << " ";
654 dumpIR(&I, sb);
655 if (isa<AllocActivationInst>(&I))
656 sb << " // size: " << I.getSizeInBytes();
657 if (isa<DeallocActivationInst>(&I)) {
658 sb << " // size: "
659 << cast<DeallocActivationInst>(&I)
660 ->getSrc()
661 ->getType()
662 ->getSizeInBytes();
663 }
664 if (hasResultValue(&I))
665 dumpUsers(&I, sb, InstrNumbering);
666 sb << "\n";
667 }
668
669 sb << "}\n";
670
671 OS << sb.str();
672 OS.flush();
673}
674
675std::string IRFunction::toString() const {
676 std::string storage;
677 llvm::raw_string_ostream os(storage);
678 dump(os);
679 return os.str();
680}
681
682IRFunction *
683IRFunction::clone(llvm::StringRef newName,
684 llvm::DenseMap<const Value *, Value *> *map,
685 llvm::DenseMap<const Value *, Value *> *currToNewMap) {
686 // Create a new function.
687 auto *newF = new IRFunction(getRawGraph());
688 newF->setName(newName);
689 return clone(newF, map, currToNewMap);
690}
691
692IRFunction *
693IRFunction::clone(IRFunction *newF, llvm::DenseMap<const Value *, Value *> *map,
694 llvm::DenseMap<const Value *, Value *> *currToNewMap) const {
695
696 llvm::DenseMap<const Value *, Value *> currToNew;
697 // Initialize the map from a user-provided map.
698 if (currToNewMap) {
699 currToNew.insert(currToNewMap->begin(), currToNewMap->end());
700 }
701 // Clone weights.
702 for (auto &w : getWeights()) {
703 auto cloneWeight =
704 new WeightVar(w->getName(), w->getType(), w->getMutability());
705 newF->getWeights().emplace_back(cloneWeight);
706 currToNew[w] = cloneWeight;
707 }
708 // Clone the variable map.
709 for (auto &v : getVariableMap()) {
710 assert(v.second && "The value should have been cloned already");
711 newF->getVariableMap()[v.first] = currToNew[v.second];
712 }
713 // Clone instructions.
714 for (const auto &I : getInstrs()) {
715 auto *cloneI = I.clone();
716 currToNew[&I] = cloneI;
717 // Remap all operands.
718 for (unsigned idx = 0, e = cloneI->getNumOperands(); idx < e; ++idx) {
719 cloneI->setOperand(idx, currToNew[cloneI->getOperand(idx).first]);
720 }
721 newF->insertInstruction(cloneI);
722 }
723 // Record the node mapping into the external map.
724 if (map) {
725 assert(map->empty() && "The external map must be empty");
726 for (auto it : currToNew) {
727 map->insert(it);
728 }
729 }
730 assert(newF->getInstrs().size() == getInstrs().size() && "Invalid func size");
731 assert(newF->getWeights().size() == getWeights().size() &&
732 "Invalid func size");
733 newF->verify();
734 return newF;
735}
736
737//===----------------------------------------------------------------------===//
738// InstructionTraits<Instruction> Implementation
739//===----------------------------------------------------------------------===//
740
741// The trait object is embedded into a IRFunction. Use dirty hacks to
742// reconstruct the IRFunction from the 'self' pointer of the trait.
743IRFunction *InstructionTraits::getContainingFunction() {
744 size_t Offset(
745 size_t(&((IRFunction *)nullptr->*IRFunction::getInstrsMemberPtr())));
746 IRFunction::InstListTy *Anchor(static_cast<IRFunction::InstListTy *>(this));
747 return reinterpret_cast<IRFunction *>(reinterpret_cast<char *>(Anchor) -
748 Offset);
749}
750
751void InstructionTraits::addNodeToList(Instruction *I) {
752 assert(I->getParent() == nullptr && "Already in a list!");
753 I->setParent(getContainingFunction());
754}
755
756void InstructionTraits::removeNodeFromList(Instruction *I) {
757 // When an instruction is removed from a function, clear the parent pointer.
758 assert(I->getParent() && "Not in a list!");
759 I->setParent(nullptr);
760}
761
762namespace glow {
763
764llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Value &V) {
765 V.dump(os);
766 return os;
767}
768
769llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Value *V) {
770 assert(V != nullptr && "Null Pointer.");
771 V->dump(os);
772 return os;
773}
774
775llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const IRFunction &irf) {
776 irf.dump(os);
777 return os;
778}
779
780llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const IRFunction *irf) {
781 assert(irf != nullptr && "Null Pointer.");
782 irf->dump(os);
783 return os;
784}
785
786llvm::raw_ostream &operator<<(llvm::raw_ostream &os, InstrumentKind kind) {
787 switch (kind) {
788 case InstrumentKind::Before:
789 os << "Before";
790 break;
791 case InstrumentKind::After:
792 os << "After";
793 break;
794 default:
795 llvm_unreachable("Unknown instrumentation kind");
796 }
797 return os;
798}
799} // namespace glow
800