1 //===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This files implements the LLVM difference Consumer
11 //===----------------------------------------------------------------------===//
13 #include "DiffConsumer.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/Support/Debug.h"
16 #include "llvm/Support/ErrorHandling.h"
20 static void ComputeNumbering(const Function
*F
,
21 DenseMap
<const Value
*, unsigned> &Numbering
) {
24 // Arguments get the first numbers.
25 for (const auto &Arg
: F
->args())
27 Numbering
[&Arg
] = IN
++;
29 // Walk the basic blocks in order.
30 for (const auto &Func
: *F
) {
32 Numbering
[&Func
] = IN
++;
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
++;
41 assert(!Numbering
.empty() && "asked for numbering but numbering was no-op");
44 void Consumer::anchor() { }
46 void DiffConsumer::printValue(const Value
*V
, bool isL
) {
48 out
<< (isa
<GlobalValue
>(V
) ? '@' : '%') << V
->getName();
51 if (V
->getType()->isVoidTy()) {
52 if (auto *SI
= dyn_cast
<StoreInst
>(V
)) {
54 printValue(SI
->getPointerOperand(), isL
);
55 } else if (auto *CI
= dyn_cast
<CallInst
>(V
)) {
57 printValue(CI
->getCalledOperand(), isL
);
58 } else if (auto *II
= dyn_cast
<InvokeInst
>(V
)) {
60 printValue(II
->getCalledOperand(), isL
);
66 if (isa
<Constant
>(V
)) {
71 unsigned N
= contexts
.size();
74 DiffContext
&ctxt
= contexts
[N
];
75 if (!ctxt
.IsFunction
) continue;
77 if (ctxt
.LNumbering
.empty())
78 ComputeNumbering(cast
<Function
>(ctxt
.L
), ctxt
.LNumbering
);
79 out
<< '%' << ctxt
.LNumbering
[V
];
82 if (ctxt
.RNumbering
.empty())
83 ComputeNumbering(cast
<Function
>(ctxt
.R
), ctxt
.RNumbering
);
84 out
<< '%' << ctxt
.RNumbering
[V
];
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";
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";
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";
117 printValue(R
, false);
120 } else if (isa
<Instruction
>(I
->L
)) {
121 out
<< " in instruction ";
122 printValue(I
->L
, true);
124 printValue(I
->R
, false);
128 I
->Differences
= true;
132 void DiffConsumer::indent() {
134 while (N
--) out
<< ' ';
137 void DiffConsumer::reset() {
143 bool DiffConsumer::hadDifferences() const {
147 void DiffConsumer::enterContext(const Value
*L
, const Value
*R
) {
148 contexts
.push_back(DiffContext(L
, R
));
152 void DiffConsumer::exitContext() {
153 Differences
|= contexts
.back().Differences
;
158 void DiffConsumer::log(StringRef text
) {
164 void DiffConsumer::logf(const LogBuilder
&Log
) {
170 StringRef format
= Log
.getFormat();
172 size_t percent
= format
.find('%');
173 if (percent
== StringRef::npos
) {
177 assert(format
[percent
] == '%');
179 if (percent
> 0) out
<< format
.substr(0, percent
);
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");
188 format
= format
.substr(percent
+2);
194 void DiffConsumer::logd(const DiffLogBuilder
&Log
) {
197 for (unsigned I
= 0, E
= Log
.getNumLines(); I
!= E
; ++I
) {
199 switch (Log
.getLineKind(I
)) {
202 Log
.getLeft(I
)->print(dbgs()); dbgs() << '\n';
203 //printValue(Log.getLeft(I), true);
207 Log
.getLeft(I
)->print(dbgs()); dbgs() << '\n';
208 //printValue(Log.getLeft(I), true);
212 Log
.getRight(I
)->print(dbgs()); dbgs() << '\n';
213 //printValue(Log.getRight(I), false);