1 #include "MCTargetDesc/X86MCTargetDesc.h"
2 #include "Views/SummaryView.h"
3 #include "X86TestBase.h"
4 #include "llvm/ADT/SmallPtrSet.h"
5 #include "llvm/MC/MCInstBuilder.h"
6 #include "llvm/MCA/CustomBehaviour.h"
7 #include "llvm/MCA/IncrementalSourceMgr.h"
8 #include "llvm/MCA/InstrBuilder.h"
9 #include "llvm/MCA/Pipeline.h"
10 #include "llvm/Support/Format.h"
11 #include "llvm/Support/JSON.h"
12 #include "llvm/Support/raw_ostream.h"
14 #include <unordered_map>
19 TEST_F(X86TestBase
, TestResumablePipeline
) {
20 mca::Context
MCA(*MRI
, *STI
);
22 mca::IncrementalSourceMgr ISM
;
23 // Empty CustomBehaviour.
24 auto CB
= std::make_unique
<mca::CustomBehaviour
>(*STI
, ISM
, *MCII
);
26 auto PO
= getDefaultPipelineOptions();
27 auto P
= MCA
.createDefaultPipeline(PO
, ISM
, *CB
);
30 SmallVector
<MCInst
> MCIs
;
31 getSimpleInsts(MCIs
, /*Repeats=*/100);
34 auto SV
= std::make_unique
<SummaryView
>(STI
->getSchedModel(), MCIs
,
36 P
->addEventListener(SV
.get());
38 auto IM
= std::make_unique
<mca::InstrumentManager
>(*STI
, *MCII
);
39 mca::InstrBuilder
IB(*STI
, *MCII
, *MRI
, MCIA
.get(), *IM
, /*CallLatency=*/100);
41 const SmallVector
<mca::Instrument
*> Instruments
;
43 for (unsigned i
= 0U, E
= MCIs
.size(); i
< E
;) {
44 for (unsigned TE
= i
+ 7; i
< TE
&& i
< E
; ++i
) {
45 Expected
<std::unique_ptr
<mca::Instruction
>> InstOrErr
=
46 IB
.createInstruction(MCIs
[i
], Instruments
);
47 ASSERT_TRUE(bool(InstOrErr
));
48 ISM
.addInst(std::move(InstOrErr
.get()));
52 Expected
<unsigned> Cycles
= P
->run();
54 // Should be a stream pause error.
55 ASSERT_TRUE(Cycles
.errorIsA
<mca::InstStreamPause
>());
56 llvm::consumeError(Cycles
.takeError());
61 // Has to terminate properly.
62 Expected
<unsigned> Cycles
= P
->run();
63 ASSERT_TRUE(bool(Cycles
));
65 json::Value Result
= SV
->toJSON();
66 auto *ResultObj
= Result
.getAsObject();
67 ASSERT_TRUE(ResultObj
);
70 json::Object BaselineResult
;
71 auto E
= runBaselineMCA(BaselineResult
, MCIs
);
72 ASSERT_FALSE(bool(E
)) << "Failed to run baseline";
73 auto *BaselineObj
= BaselineResult
.getObject(SV
->getNameAsString());
74 ASSERT_TRUE(BaselineObj
) << "Does not contain SummaryView result";
76 // Compare the results.
77 constexpr const char *Fields
[] = {"Instructions", "TotalCycles", "TotaluOps",
79 for (const auto *F
: Fields
) {
80 auto V
= ResultObj
->getInteger(F
);
81 auto BV
= BaselineObj
->getInteger(F
);
83 ASSERT_EQ(*BV
, *V
) << "Value of '" << F
<< "' does not match";
87 TEST_F(X86TestBase
, TestInstructionRecycling
) {
88 mca::Context
MCA(*MRI
, *STI
);
90 std::unordered_map
<const mca::InstrDesc
*, SmallPtrSet
<mca::Instruction
*, 2>>
92 auto GetRecycledInst
= [&](const mca::InstrDesc
&Desc
) -> mca::Instruction
* {
93 auto It
= RecycledInsts
.find(&Desc
);
94 if (It
!= RecycledInsts
.end()) {
95 auto &Insts
= It
->second
;
97 mca::Instruction
*I
= *Insts
.begin();
104 auto AddRecycledInst
= [&](mca::Instruction
*I
) {
105 const mca::InstrDesc
&D
= I
->getDesc();
106 RecycledInsts
[&D
].insert(I
);
109 mca::IncrementalSourceMgr ISM
;
110 ISM
.setOnInstFreedCallback(AddRecycledInst
);
112 // Empty CustomBehaviour.
113 auto CB
= std::make_unique
<mca::CustomBehaviour
>(*STI
, ISM
, *MCII
);
115 auto PO
= getDefaultPipelineOptions();
116 auto P
= MCA
.createDefaultPipeline(PO
, ISM
, *CB
);
119 SmallVector
<MCInst
> MCIs
;
120 getSimpleInsts(MCIs
, /*Repeats=*/100);
123 auto SV
= std::make_unique
<SummaryView
>(STI
->getSchedModel(), MCIs
,
125 P
->addEventListener(SV
.get());
127 // Default InstrumentManager
128 auto IM
= std::make_unique
<mca::InstrumentManager
>(*STI
, *MCII
);
130 mca::InstrBuilder
IB(*STI
, *MCII
, *MRI
, MCIA
.get(), *IM
, /*CallLatency=*/100);
131 IB
.setInstRecycleCallback(GetRecycledInst
);
133 const SmallVector
<mca::Instrument
*> Instruments
;
135 for (unsigned i
= 0U, E
= MCIs
.size(); i
< E
;) {
136 for (unsigned TE
= i
+ 7; i
< TE
&& i
< E
; ++i
) {
137 Expected
<std::unique_ptr
<mca::Instruction
>> InstOrErr
=
138 IB
.createInstruction(MCIs
[i
], Instruments
);
141 mca::Instruction
*RecycledInst
= nullptr;
142 // Check if the returned instruction is a recycled
144 auto RemainingE
= handleErrors(InstOrErr
.takeError(),
145 [&](const mca::RecycledInstErr
&RC
) {
146 RecycledInst
= RC
.getInst();
148 ASSERT_FALSE(bool(RemainingE
));
149 ASSERT_TRUE(RecycledInst
);
150 ISM
.addRecycledInst(RecycledInst
);
152 ISM
.addInst(std::move(InstOrErr
.get()));
157 Expected
<unsigned> Cycles
= P
->run();
159 // Should be a stream pause error.
160 ASSERT_TRUE(Cycles
.errorIsA
<mca::InstStreamPause
>());
161 llvm::consumeError(Cycles
.takeError());
166 // Has to terminate properly.
167 Expected
<unsigned> Cycles
= P
->run();
168 ASSERT_TRUE(bool(Cycles
));
170 json::Value Result
= SV
->toJSON();
171 auto *ResultObj
= Result
.getAsObject();
172 ASSERT_TRUE(ResultObj
);
175 json::Object BaselineResult
;
176 auto E
= runBaselineMCA(BaselineResult
, MCIs
);
177 ASSERT_FALSE(bool(E
)) << "Failed to run baseline";
178 auto *BaselineObj
= BaselineResult
.getObject(SV
->getNameAsString());
179 ASSERT_TRUE(BaselineObj
) << "Does not contain SummaryView result";
181 // Compare the results.
182 constexpr const char *Fields
[] = {"Instructions", "TotalCycles", "TotaluOps",
184 for (const auto *F
: Fields
) {
185 auto V
= ResultObj
->getInteger(F
);
186 auto BV
= BaselineObj
->getInteger(F
);
187 ASSERT_TRUE(V
&& BV
);
188 ASSERT_EQ(*BV
, *V
) << "Value of '" << F
<< "' does not match";
192 // Test that we do not depend upon the MCInst address for variant description
193 // construction. This test creates two instructions that will use variant
194 // description as they are both zeroing idioms, but write to different
195 // registers. If the key used to access the variant instruction description is
196 // the same between the descriptions (like the MCInst pointer), we will run into
197 // an assertion failure due to the different writes.
198 TEST_F(X86TestBase
, TestVariantInstructionsSameAddress
) {
199 mca::Context
MCA(*MRI
, *STI
);
201 mca::IncrementalSourceMgr ISM
;
202 // Empty CustomBehaviour.
203 auto CB
= std::make_unique
<mca::CustomBehaviour
>(*STI
, ISM
, *MCII
);
205 auto PO
= getDefaultPipelineOptions();
206 auto P
= MCA
.createDefaultPipeline(PO
, ISM
, *CB
);
209 auto IM
= std::make_unique
<mca::InstrumentManager
>(*STI
, *MCII
);
210 mca::InstrBuilder
IB(*STI
, *MCII
, *MRI
, MCIA
.get(), *IM
, 100);
212 const SmallVector
<mca::Instrument
*> Instruments
;
214 MCInst InstructionToAdd
;
215 InstructionToAdd
= MCInstBuilder(X86::XOR64rr
)
219 Expected
<std::unique_ptr
<mca::Instruction
>> Instruction1OrErr
=
220 IB
.createInstruction(InstructionToAdd
, Instruments
);
221 ASSERT_TRUE(static_cast<bool>(Instruction1OrErr
));
222 ISM
.addInst(std::move(Instruction1OrErr
.get()));
224 InstructionToAdd
= MCInstBuilder(X86::XORPSrr
)
228 Expected
<std::unique_ptr
<mca::Instruction
>> Instruction2OrErr
=
229 IB
.createInstruction(InstructionToAdd
, Instruments
);
230 ASSERT_TRUE(static_cast<bool>(Instruction2OrErr
));
231 ISM
.addInst(std::move(Instruction2OrErr
.get()));
234 Expected
<unsigned> Cycles
= P
->run();
235 ASSERT_TRUE(static_cast<bool>(Cycles
));