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(Function
*F
, DenseMap
<Value
*,unsigned> &Numbering
){
23 // Arguments get the first numbers.
24 for (Function::arg_iterator
25 AI
= F
->arg_begin(), AE
= F
->arg_end(); AI
!= AE
; ++AI
)
27 Numbering
[&*AI
] = IN
++;
29 // Walk the basic blocks in order.
30 for (Function::iterator FI
= F
->begin(), FE
= F
->end(); FI
!= FE
; ++FI
) {
32 Numbering
[&*FI
] = IN
++;
34 // Walk the instructions in order.
35 for (BasicBlock::iterator BI
= FI
->begin(), BE
= FI
->end(); BI
!= BE
; ++BI
)
36 // void instructions don't get numbers.
37 if (!BI
->hasName() && !BI
->getType()->isVoidTy())
38 Numbering
[&*BI
] = IN
++;
41 assert(!Numbering
.empty() && "asked for numbering but numbering was no-op");
45 void Consumer::anchor() { }
47 void DiffConsumer::printValue(Value
*V
, bool isL
) {
49 out
<< (isa
<GlobalValue
>(V
) ? '@' : '%') << V
->getName();
52 if (V
->getType()->isVoidTy()) {
53 if (isa
<StoreInst
>(V
)) {
55 printValue(cast
<StoreInst
>(V
)->getPointerOperand(), isL
);
56 } else if (isa
<CallInst
>(V
)) {
58 printValue(cast
<CallInst
>(V
)->getCalledValue(), isL
);
59 } else if (isa
<InvokeInst
>(V
)) {
61 printValue(cast
<InvokeInst
>(V
)->getCalledValue(), isL
);
67 if (isa
<Constant
>(V
)) {
72 unsigned N
= contexts
.size();
75 DiffContext
&ctxt
= contexts
[N
];
76 if (!ctxt
.IsFunction
) continue;
78 if (ctxt
.LNumbering
.empty())
79 ComputeNumbering(cast
<Function
>(ctxt
.L
), ctxt
.LNumbering
);
80 out
<< '%' << ctxt
.LNumbering
[V
];
83 if (ctxt
.RNumbering
.empty())
84 ComputeNumbering(cast
<Function
>(ctxt
.R
), ctxt
.RNumbering
);
85 out
<< '%' << ctxt
.RNumbering
[V
];
93 void DiffConsumer::header() {
94 if (contexts
.empty()) return;
95 for (SmallVectorImpl
<DiffContext
>::iterator
96 I
= contexts
.begin(), E
= contexts
.end(); I
!= E
; ++I
) {
97 if (I
->Differences
) continue;
98 if (isa
<Function
>(I
->L
)) {
99 // Extra newline between functions.
100 if (Differences
) out
<< "\n";
102 Function
*L
= cast
<Function
>(I
->L
);
103 Function
*R
= cast
<Function
>(I
->R
);
104 if (L
->getName() != R
->getName())
105 out
<< "in function " << L
->getName()
106 << " / " << R
->getName() << ":\n";
108 out
<< "in function " << L
->getName() << ":\n";
109 } else if (isa
<BasicBlock
>(I
->L
)) {
110 BasicBlock
*L
= cast
<BasicBlock
>(I
->L
);
111 BasicBlock
*R
= cast
<BasicBlock
>(I
->R
);
112 if (L
->hasName() && R
->hasName() && L
->getName() == R
->getName())
113 out
<< " in block %" << L
->getName() << ":\n";
118 printValue(R
, false);
121 } else if (isa
<Instruction
>(I
->L
)) {
122 out
<< " in instruction ";
123 printValue(I
->L
, true);
125 printValue(I
->R
, false);
129 I
->Differences
= true;
133 void DiffConsumer::indent() {
135 while (N
--) out
<< ' ';
138 bool DiffConsumer::hadDifferences() const {
142 void DiffConsumer::enterContext(Value
*L
, Value
*R
) {
143 contexts
.push_back(DiffContext(L
, R
));
147 void DiffConsumer::exitContext() {
148 Differences
|= contexts
.back().Differences
;
153 void DiffConsumer::log(StringRef text
) {
159 void DiffConsumer::logf(const LogBuilder
&Log
) {
165 StringRef format
= Log
.getFormat();
167 size_t percent
= format
.find('%');
168 if (percent
== StringRef::npos
) {
172 assert(format
[percent
] == '%');
174 if (percent
> 0) out
<< format
.substr(0, percent
);
176 switch (format
[percent
+1]) {
177 case '%': out
<< '%'; break;
178 case 'l': printValue(Log
.getArgument(arg
++), true); break;
179 case 'r': printValue(Log
.getArgument(arg
++), false); break;
180 default: llvm_unreachable("unknown format character");
183 format
= format
.substr(percent
+2);
189 void DiffConsumer::logd(const DiffLogBuilder
&Log
) {
192 for (unsigned I
= 0, E
= Log
.getNumLines(); I
!= E
; ++I
) {
194 switch (Log
.getLineKind(I
)) {
197 Log
.getLeft(I
)->print(dbgs()); dbgs() << '\n';
198 //printValue(Log.getLeft(I), true);
202 Log
.getLeft(I
)->print(dbgs()); dbgs() << '\n';
203 //printValue(Log.getLeft(I), true);
207 Log
.getRight(I
)->print(dbgs()); dbgs() << '\n';
208 //printValue(Log.getRight(I), false);