Skip to content

Commit fd41738

Browse files
committed
Recommit "[llvm-reduce] Add MIR support"
(Second try. Need to link against CodeGen and MC libs.) The llvm-reduce tool has been extended to operate on MIR (import, clone and export). Current limitation is that only a single machine function is supported. A single reducer pass that operates on machine instructions (while on SSA-form) has been added. Additional MIR specific reducer passes can be added later as needed. Differential Revision: https://reviews.llvm.org/D110527
1 parent cd2e66e commit fd41738

File tree

13 files changed

+542
-44
lines changed

13 files changed

+542
-44
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# RUN: llvm-reduce -mtriple=riscv32 --test %python --test-arg %p/instr-reduce.py %s -o %t
2+
# RUN: cat %t | FileCheck --match-full-lines %s
3+
4+
# REQUIRES: riscv-registered-target
5+
6+
# Verify that after reduction the following instruction sequence remains. The
7+
# interestingness-test 'instr-reduce.py' matches a '%[0-9]+:gpr = ADDI %[0-9]+, 5'
8+
# pattern in the output and that combined with that the MIR has to be valid
9+
# (pass verify) results in the given sequence.
10+
11+
# CHECK: %0:gpr = COPY $x10
12+
# CHECK-NEXT: %2:gpr = ADDI %0, 5
13+
# CHECK-NEXT: PseudoRET implicit $x10
14+
15+
...
16+
---
17+
name: f
18+
tracksRegLiveness: true
19+
body: |
20+
bb.0:
21+
liveins: $x10
22+
23+
%10:gpr = COPY $x10
24+
%20:gpr = ADDI %10, 1
25+
%30:gpr = ADDI %20, 5
26+
%40:gpr = ADDI %30, 9
27+
$x10 = COPY %40
28+
PseudoRET implicit $x10
29+
...
30+
---
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from subprocess import run, PIPE
2+
import re
3+
import sys
4+
5+
llc = run( [ 'llc', '-disable-symbolication','-verify-machineinstrs', '-mtriple=riscv32', '-run-pass=none', '-o', '-', sys.argv[1]], stdout=PIPE, stderr=PIPE )
6+
7+
stdout = llc.stdout.decode()
8+
9+
p = re.compile(r'^\s*%[0-9]+:gpr = ADDI %[0-9]+, 5$', flags=re.MULTILINE)
10+
11+
if (llc.returncode == 0 and p.search(stdout)):
12+
print('This is interesting!')
13+
sys.exit(0)
14+
else:
15+
print('This is NOT interesting!')
16+
sys.exit(1)

llvm/tools/llvm-reduce/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ set(LLVM_LINK_COMPONENTS
33
AllTargetsCodeGens
44
AllTargetsDescs
55
AllTargetsInfos
6+
CodeGen
67
Core
78
IRReader
9+
MC
10+
MIRParser
811
Support
912
Target
1013
TransformUtils
1114
)
1215

1316
add_llvm_tool(llvm-reduce
1417
DeltaManager.cpp
18+
ReducerWorkItem.cpp
1519
TestRunner.cpp
1620
deltas/Delta.cpp
1721
deltas/ReduceAliases.cpp
@@ -30,6 +34,7 @@ add_llvm_tool(llvm-reduce
3034
deltas/ReduceSpecialGlobals.cpp
3135
deltas/ReduceOperands.cpp
3236
deltas/ReduceOperandsToArgs.cpp
37+
deltas/ReduceInstructionsMIR.cpp
3338
llvm-reduce.cpp
3439

3540
DEPENDS

llvm/tools/llvm-reduce/DeltaManager.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "deltas/ReduceGlobalVarInitializers.h"
2525
#include "deltas/ReduceGlobalVars.h"
2626
#include "deltas/ReduceInstructions.h"
27+
#include "deltas/ReduceInstructionsMIR.h"
2728
#include "deltas/ReduceMetadata.h"
2829
#include "deltas/ReduceModuleData.h"
2930
#include "deltas/ReduceOperandBundles.h"
@@ -59,9 +60,16 @@ static cl::opt<std::string>
5960
DELTA_PASS("attributes", reduceAttributesDeltaPass) \
6061
DELTA_PASS("module-data", reduceModuleDataDeltaPass)
6162

63+
#define DELTA_PASSES_MIR \
64+
DELTA_PASS("instructions", reduceInstructionsMIRDeltaPass)
65+
6266
static void runAllDeltaPasses(TestRunner &Tester) {
6367
#define DELTA_PASS(NAME, FUNC) FUNC(Tester);
64-
DELTA_PASSES
68+
if (Tester.getProgram().isMIR()) {
69+
DELTA_PASSES_MIR
70+
} else {
71+
DELTA_PASSES
72+
}
6573
#undef DELTA_PASS
6674
}
6775

@@ -71,7 +79,11 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
7179
FUNC(Tester); \
7280
return; \
7381
}
74-
DELTA_PASSES
82+
if (Tester.getProgram().isMIR()) {
83+
DELTA_PASSES_MIR
84+
} else {
85+
DELTA_PASSES
86+
}
7587
#undef DELTA_PASS
7688
errs() << "unknown pass \"" << PassName << "\"";
7789
exit(1);
@@ -80,7 +92,10 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
8092
void llvm::printDeltaPasses(raw_ostream &OS) {
8193
OS << "Delta passes (pass to `--delta-passes=` as a comma separated list):\n";
8294
#define DELTA_PASS(NAME, FUNC) OS << " " << NAME << "\n";
95+
OS << " IR:\n";
8396
DELTA_PASSES
97+
OS << " MIR:\n";
98+
DELTA_PASSES_MIR
8499
#undef DELTA_PASS
85100
}
86101

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//
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+
#include "ReducerWorkItem.h"
10+
#include "llvm/CodeGen/MIRParser/MIRParser.h"
11+
#include "llvm/CodeGen/MIRPrinter.h"
12+
#include "llvm/CodeGen/MachineDominators.h"
13+
#include "llvm/CodeGen/MachineFunction.h"
14+
#include "llvm/CodeGen/MachineFunctionPass.h"
15+
#include "llvm/CodeGen/MachineRegisterInfo.h"
16+
#include "llvm/CodeGen/TargetInstrInfo.h"
17+
#include "llvm/IR/Verifier.h"
18+
#include "llvm/IRReader/IRReader.h"
19+
#include "llvm/Target/TargetMachine.h"
20+
#include "llvm/Transforms/Utils/Cloning.h"
21+
22+
static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF) {
23+
auto DstMF = std::make_unique<MachineFunction>(
24+
SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
25+
SrcMF->getFunctionNumber(), SrcMF->getMMI());
26+
DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
27+
DenseMap<Register, Register> Src2DstReg;
28+
29+
auto *SrcMRI = &SrcMF->getRegInfo();
30+
auto *DstMRI = &DstMF->getRegInfo();
31+
32+
// Create vregs.
33+
for (auto &SrcMBB : *SrcMF) {
34+
for (auto &SrcMI : SrcMBB) {
35+
for (unsigned I = 0, E = SrcMI.getNumOperands(); I < E; ++I) {
36+
auto &DMO = SrcMI.getOperand(I);
37+
if (!DMO.isReg() || !DMO.isDef())
38+
continue;
39+
Register SrcReg = DMO.getReg();
40+
if (Register::isPhysicalRegister(SrcReg))
41+
continue;
42+
auto SrcRC = SrcMRI->getRegClass(SrcReg);
43+
auto DstReg = DstMRI->createVirtualRegister(SrcRC);
44+
Src2DstReg[SrcReg] = DstReg;
45+
}
46+
}
47+
}
48+
49+
// Clone blocks.
50+
for (auto &SrcMBB : *SrcMF)
51+
Src2DstMBB[&SrcMBB] = DstMF->CreateMachineBasicBlock();
52+
// Link blocks.
53+
for (auto &SrcMBB : *SrcMF) {
54+
auto *DstMBB = Src2DstMBB[&SrcMBB];
55+
DstMF->push_back(DstMBB);
56+
for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();
57+
It != IterEnd; ++It) {
58+
auto *SrcSuccMBB = *It;
59+
auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];
60+
DstMBB->addSuccessor(DstSuccMBB);
61+
}
62+
for (auto &LI : SrcMBB.liveins())
63+
DstMBB->addLiveIn(LI);
64+
}
65+
// Clone instructions.
66+
for (auto &SrcMBB : *SrcMF) {
67+
auto *DstMBB = Src2DstMBB[&SrcMBB];
68+
for (auto &SrcMI : SrcMBB) {
69+
const auto &MCID =
70+
DstMF->getSubtarget().getInstrInfo()->get(SrcMI.getOpcode());
71+
auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(),
72+
/*NoImplicit=*/true);
73+
DstMBB->push_back(DstMI);
74+
for (auto &SrcMO : SrcMI.operands()) {
75+
MachineOperand DstMO(SrcMO);
76+
DstMO.clearParent();
77+
// Update vreg.
78+
if (DstMO.isReg() && Src2DstReg.count(DstMO.getReg())) {
79+
DstMO.setReg(Src2DstReg[DstMO.getReg()]);
80+
}
81+
// Update MBB.
82+
if (DstMO.isMBB()) {
83+
DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);
84+
}
85+
DstMI->addOperand(DstMO);
86+
}
87+
DstMI->setMemRefs(*DstMF, SrcMI.memoperands());
88+
}
89+
}
90+
91+
DstMF->verify(nullptr, "", /*AbortOnErrors=*/true);
92+
return DstMF;
93+
}
94+
95+
std::unique_ptr<ReducerWorkItem> parseReducerWorkItem(StringRef Filename,
96+
LLVMContext &Ctxt,
97+
MachineModuleInfo *MMI) {
98+
auto MMM = std::make_unique<ReducerWorkItem>();
99+
if (MMI) {
100+
auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
101+
std::unique_ptr<MIRParser> MParser =
102+
createMIRParser(std::move(FileOrErr.get()), Ctxt);
103+
104+
auto SetDataLayout =
105+
[&](StringRef DataLayoutTargetTriple) -> Optional<std::string> {
106+
return MMI->getTarget().createDataLayout().getStringRepresentation();
107+
};
108+
109+
std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
110+
MParser->parseMachineFunctions(*M, *MMI);
111+
MachineFunction *MF = nullptr;
112+
for (auto &F : *M) {
113+
if (auto *MF4F = MMI->getMachineFunction(F)) {
114+
// XXX: Maybe it would not be a lot of effort to handle multiple MFs by
115+
// simply storing them in a ReducerWorkItem::SmallVector or similar. The
116+
// single MF use-case seems a lot more common though so that will do for
117+
// now.
118+
assert(!MF && "Only single MF supported!");
119+
MF = MF4F;
120+
}
121+
}
122+
assert(MF && "No MF found!");
123+
124+
MMM->M = std::move(M);
125+
MMM->MF = cloneMF(MF);
126+
} else {
127+
SMDiagnostic Err;
128+
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
129+
if (!Result) {
130+
Err.print("llvm-reduce", errs());
131+
return std::unique_ptr<ReducerWorkItem>();
132+
}
133+
MMM->M = std::move(Result);
134+
}
135+
if (verifyReducerWorkItem(*MMM, &errs())) {
136+
errs() << "Error: " << Filename << " - input module is broken!\n";
137+
return std::unique_ptr<ReducerWorkItem>();
138+
}
139+
return MMM;
140+
}
141+
142+
std::unique_ptr<ReducerWorkItem>
143+
cloneReducerWorkItem(const ReducerWorkItem &MMM) {
144+
auto CloneMMM = std::make_unique<ReducerWorkItem>();
145+
if (MMM.MF) {
146+
// Note that we cannot clone the Module as then we would need a way to
147+
// updated the cloned MachineFunction's IR references.
148+
// XXX: Actually have a look at
149+
// std::unique_ptr<Module> CloneModule(const Module &M, ValueToValueMapTy
150+
// &VMap);
151+
CloneMMM->M = MMM.M;
152+
CloneMMM->MF = cloneMF(MMM.MF.get());
153+
} else {
154+
CloneMMM->M = CloneModule(*MMM.M);
155+
}
156+
return CloneMMM;
157+
}
158+
159+
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
160+
if (verifyModule(*MMM.M, OS))
161+
return true;
162+
if (MMM.MF && !MMM.MF->verify(nullptr, "", /*AbortOnErrors=*/false))
163+
return true;
164+
return false;
165+
}
166+
167+
void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
168+
if (MF) {
169+
printMIR(ROS, *M);
170+
printMIR(ROS, *MF);
171+
} else {
172+
M->print(ROS, nullptr);
173+
}
174+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===- ReducerWorkItem.h - Wrapper for Module and MachineFunction ---------===//
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+
#ifndef LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
10+
#define LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
11+
12+
#include "llvm/CodeGen/MachineFunction.h"
13+
#include "llvm/CodeGen/MachineModuleInfo.h"
14+
#include "llvm/IR/Module.h"
15+
16+
using namespace llvm;
17+
18+
class ReducerWorkItem {
19+
public:
20+
std::shared_ptr<Module> M;
21+
std::unique_ptr<MachineFunction> MF;
22+
void print(raw_ostream &ROS, void *p = nullptr) const;
23+
bool isMIR() { return MF != nullptr; }
24+
operator Module &() const { return *M; }
25+
operator MachineFunction &() const { return *MF; }
26+
};
27+
28+
std::unique_ptr<ReducerWorkItem> parseReducerWorkItem(StringRef Filename,
29+
LLVMContext &Ctxt,
30+
MachineModuleInfo *MMI);
31+
32+
std::unique_ptr<ReducerWorkItem>
33+
cloneReducerWorkItem(const ReducerWorkItem &MMM);
34+
35+
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS);
36+
37+
#endif

llvm/tools/llvm-reduce/TestRunner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ using namespace llvm;
1212

1313
TestRunner::TestRunner(StringRef TestName,
1414
const std::vector<std::string> &TestArgs,
15-
std::unique_ptr<Module> Program)
15+
std::unique_ptr<ReducerWorkItem> Program)
1616
: TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) {
1717
assert(this->Program && "Initialized with null program?");
1818
}

llvm/tools/llvm-reduce/TestRunner.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
1010
#define LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
1111

12+
#include "ReducerWorkItem.h"
1213
#include "llvm/ADT/SmallString.h"
1314
#include "llvm/IR/Module.h"
1415
#include "llvm/Support/Error.h"
@@ -25,24 +26,24 @@ namespace llvm {
2526
class TestRunner {
2627
public:
2728
TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs,
28-
std::unique_ptr<Module> Program);
29+
std::unique_ptr<ReducerWorkItem> Program);
2930

3031
/// Runs the interesting-ness test for the specified file
3132
/// @returns 0 if test was successful, 1 if otherwise
3233
int run(StringRef Filename);
3334

3435
/// Returns the most reduced version of the original testcase
35-
Module &getProgram() const { return *Program; }
36+
ReducerWorkItem &getProgram() const { return *Program; }
3637

37-
void setProgram(std::unique_ptr<Module> P) {
38+
void setProgram(std::unique_ptr<ReducerWorkItem> P) {
3839
assert(P && "Setting null program?");
3940
Program = std::move(P);
4041
}
4142

4243
private:
4344
StringRef TestName;
4445
const std::vector<std::string> &TestArgs;
45-
std::unique_ptr<Module> Program;
46+
std::unique_ptr<ReducerWorkItem> Program;
4647
};
4748

4849
} // namespace llvm

0 commit comments

Comments
 (0)