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