1 //===-- DiffConsumer.cpp - Difference Consumer ------------------*- 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 // This files implements the LLVM difference Consumer 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "DiffConsumer.h" 14 #include "llvm/IR/Instructions.h" 15 #include "llvm/Support/Debug.h" 16 #include "llvm/Support/ErrorHandling.h" 17 18 using namespace llvm; 19 20 static void ComputeNumbering(const Function *F, 21 DenseMap<const Value *, unsigned> &Numbering) { 22 unsigned IN = 0; 23 24 // Arguments get the first numbers. 25 for (const auto &Arg : F->args()) 26 if (!Arg.hasName()) 27 Numbering[&Arg] = IN++; 28 29 // Walk the basic blocks in order. 30 for (const auto &Func : *F) { 31 if (!Func.hasName()) 32 Numbering[&Func] = IN++; 33 34 // Walk the instructions in order. 35 for (const auto &BB : Func) 36 // void instructions don't get numbers. 37 if (!BB.hasName() && !BB.getType()->isVoidTy()) 38 Numbering[&BB] = IN++; 39 } 40 41 assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); 42 } 43 44 void Consumer::anchor() { } 45 46 void DiffConsumer::printValue(const Value *V, bool isL) { 47 if (V->hasName()) { 48 out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName(); 49 return; 50 } 51 if (V->getType()->isVoidTy()) { 52 if (auto *SI = dyn_cast<StoreInst>(V)) { 53 out << "store to "; 54 printValue(SI->getPointerOperand(), isL); 55 } else if (auto *CI = dyn_cast<CallInst>(V)) { 56 out << "call to "; 57 printValue(CI->getCalledOperand(), isL); 58 } else if (auto *II = dyn_cast<InvokeInst>(V)) { 59 out << "invoke to "; 60 printValue(II->getCalledOperand(), isL); 61 } else { 62 out << *V; 63 } 64 return; 65 } 66 if (isa<Constant>(V)) { 67 out << *V; 68 return; 69 } 70 71 unsigned N = contexts.size(); 72 while (N > 0) { 73 --N; 74 DiffContext &ctxt = contexts[N]; 75 if (!ctxt.IsFunction) continue; 76 if (isL) { 77 if (ctxt.LNumbering.empty()) 78 ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering); 79 out << '%' << ctxt.LNumbering[V]; 80 return; 81 } else { 82 if (ctxt.RNumbering.empty()) 83 ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering); 84 out << '%' << ctxt.RNumbering[V]; 85 return; 86 } 87 } 88 89 out << "<anonymous>"; 90 } 91 92 void DiffConsumer::header() { 93 if (contexts.empty()) return; 94 for (SmallVectorImpl<DiffContext>::iterator 95 I = contexts.begin(), E = contexts.end(); I != E; ++I) { 96 if (I->Differences) continue; 97 if (isa<Function>(I->L)) { 98 // Extra newline between functions. 99 if (Differences) out << "\n"; 100 101 const Function *L = cast<Function>(I->L); 102 const Function *R = cast<Function>(I->R); 103 if (L->getName() != R->getName()) 104 out << "in function " << L->getName() 105 << " / " << R->getName() << ":\n"; 106 else 107 out << "in function " << L->getName() << ":\n"; 108 } else if (isa<BasicBlock>(I->L)) { 109 const BasicBlock *L = cast<BasicBlock>(I->L); 110 const BasicBlock *R = cast<BasicBlock>(I->R); 111 if (L->hasName() && R->hasName() && L->getName() == R->getName()) 112 out << " in block %" << L->getName() << ":\n"; 113 else { 114 out << " in block "; 115 printValue(L, true); 116 out << " / "; 117 printValue(R, false); 118 out << ":\n"; 119 } 120 } else if (isa<Instruction>(I->L)) { 121 out << " in instruction "; 122 printValue(I->L, true); 123 out << " / "; 124 printValue(I->R, false); 125 out << ":\n"; 126 } 127 128 I->Differences = true; 129 } 130 } 131 132 void DiffConsumer::indent() { 133 unsigned N = Indent; 134 while (N--) out << ' '; 135 } 136 137 void DiffConsumer::reset() { 138 contexts.clear(); 139 Differences = false; 140 Indent = 0; 141 } 142 143 bool DiffConsumer::hadDifferences() const { 144 return Differences; 145 } 146 147 void DiffConsumer::enterContext(const Value *L, const Value *R) { 148 contexts.push_back(DiffContext(L, R)); 149 Indent += 2; 150 } 151 152 void DiffConsumer::exitContext() { 153 Differences |= contexts.back().Differences; 154 contexts.pop_back(); 155 Indent -= 2; 156 } 157 158 void DiffConsumer::log(StringRef text) { 159 header(); 160 indent(); 161 out << text << '\n'; 162 } 163 164 void DiffConsumer::logf(const LogBuilder &Log) { 165 header(); 166 indent(); 167 168 unsigned arg = 0; 169 170 StringRef format = Log.getFormat(); 171 while (true) { 172 size_t percent = format.find('%'); 173 if (percent == StringRef::npos) { 174 out << format; 175 break; 176 } 177 assert(format[percent] == '%'); 178 179 if (percent > 0) out << format.substr(0, percent); 180 181 switch (format[percent+1]) { 182 case '%': out << '%'; break; 183 case 'l': printValue(Log.getArgument(arg++), true); break; 184 case 'r': printValue(Log.getArgument(arg++), false); break; 185 default: llvm_unreachable("unknown format character"); 186 } 187 188 format = format.substr(percent+2); 189 } 190 191 out << '\n'; 192 } 193 194 void DiffConsumer::logd(const DiffLogBuilder &Log) { 195 header(); 196 197 for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { 198 indent(); 199 switch (Log.getLineKind(I)) { 200 case DC_match: 201 out << " "; 202 Log.getLeft(I)->print(dbgs()); dbgs() << '\n'; 203 //printValue(Log.getLeft(I), true); 204 break; 205 case DC_left: 206 out << "< "; 207 Log.getLeft(I)->print(dbgs()); dbgs() << '\n'; 208 //printValue(Log.getLeft(I), true); 209 break; 210 case DC_right: 211 out << "> "; 212 Log.getRight(I)->print(dbgs()); dbgs() << '\n'; 213 //printValue(Log.getRight(I), false); 214 break; 215 } 216 //out << "\n"; 217 } 218 } 219