Skip to content

Commit 9d3038b

Browse files
committed
[EVM] Improve Operation implementation
1 parent fd6194b commit 9d3038b

File tree

6 files changed

+109
-122
lines changed

6 files changed

+109
-122
lines changed

llvm/lib/Target/EVM/EVMStackDebug.cpp

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919

2020
using namespace llvm;
2121

22-
template <class... Ts> struct Overload : Ts... {
23-
using Ts::operator()...;
24-
};
25-
template <class... Ts> Overload(Ts...) -> Overload<Ts...>;
26-
2722
std::string llvm::stackToString(const Stack &S) {
2823
std::string Result("[ ");
2924
for (const auto *Slot : S)
@@ -55,32 +50,14 @@ void StackLayoutPrinter::operator()() {
5550
void StackLayoutPrinter::printBlock(MachineBasicBlock const &Block) {
5651
OS << "Block" << getBlockId(Block) << " [\n";
5752
OS << stackToString(Layout.getMBBEntryLayout(&Block)) << "\n";
58-
for (auto const &Operation : StackModel.getOperations(&Block)) {
53+
for (auto const &Op : StackModel.getOperations(&Block)) {
5954
OS << "\n";
60-
Stack EntryLayout = Layout.getOperationEntryLayout(&Operation);
55+
Stack EntryLayout = Layout.getOperationEntryLayout(&Op);
6156
OS << stackToString(EntryLayout) << "\n";
62-
std::visit(Overload{[&](FunctionCall const &Call) {
63-
const MachineOperand *Callee =
64-
Call.MI->explicit_uses().begin();
65-
OS << Callee->getGlobal()->getName();
66-
},
67-
[&](BuiltinCall const &Call) {
68-
OS << getInstName(Call.MI);
69-
},
70-
[&](Assignment const &Assignment) {
71-
OS << "Assignment(";
72-
for (const auto *Var : Assignment.Variables)
73-
OS << printReg(Var->getReg(), nullptr, 0, nullptr)
74-
<< ", ";
75-
OS << ")";
76-
}},
77-
Operation.Operation);
78-
OS << "\n";
79-
80-
assert(Operation.Input.size() <= EntryLayout.size());
81-
for (size_t i = 0; i < Operation.Input.size(); ++i)
82-
EntryLayout.pop_back();
83-
EntryLayout.append(Operation.Output);
57+
OS << Op.toString() << "\n";
58+
assert(Op.getInput().size() <= EntryLayout.size());
59+
EntryLayout.resize(EntryLayout.size() - Op.getInput().size());
60+
EntryLayout.append(Op.getOutput());
8461
OS << stackToString(EntryLayout) << "\n";
8562
}
8663
OS << "\n";

llvm/lib/Target/EVM/EVMStackLayoutGenerator.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,9 @@ std::unique_ptr<EVMStackLayout> EVMStackLayoutGenerator::run() {
261261
}
262262

263263
Stack EVMStackLayoutGenerator::propagateStackThroughOperation(
264-
Stack ExitStack, const Operation &Operation,
265-
bool AggressiveStackCompression) {
264+
Stack ExitStack, const Operation &Op, bool AggressiveStackCompression) {
266265
// Enable aggressive stack compression for recursive calls.
267-
if (std::holds_alternative<FunctionCall>(Operation.Operation))
266+
if (Op.isFunctionCall())
268267
// TODO: compress stack for recursive functions.
269268
AggressiveStackCompression = false;
270269

@@ -277,25 +276,25 @@ Stack EVMStackLayoutGenerator::propagateStackThroughOperation(
277276
// operation outputs (and not to be generated on the fly), s.t. shuffling the
278277
// 'IdealStack + Operation.output' to ExitLayout is cheap.
279278
Stack IdealStack =
280-
createIdealLayout(Operation.Output, ExitStack, generateSlotOnTheFly);
279+
createIdealLayout(Op.getOutput(), ExitStack, generateSlotOnTheFly);
281280

282281
// Make sure the resulting previous slots do not overlap with any assignmed
283282
// variables.
284-
if (auto const *Assign = std::get_if<Assignment>(&Operation.Operation))
283+
if (Op.isAssignment())
285284
for (auto *StackSlot : IdealStack)
286285
if (const auto *VarSlot = dyn_cast<VariableSlot>(StackSlot))
287-
assert(!is_contained(Assign->Variables, VarSlot));
286+
assert(!is_contained(Op.getOutput(), VarSlot));
288287

289288
// Since stack+Operation.output can be easily shuffled to ExitLayout, the
290289
// desired layout before the operation is stack+Operation.input;
291-
IdealStack.append(Operation.Input);
290+
IdealStack.append(Op.getInput());
292291

293292
// Store the exact desired operation entry layout. The stored layout will be
294293
// recreated by the code transform before executing the operation. However,
295294
// this recreation can produce slots that can be freely generated or are
296295
// duplicated, i.e. we can compress the stack afterwards without causing
297296
// problems for code generation later.
298-
OperationEntryLayoutMap[&Operation] = IdealStack;
297+
OperationEntryLayoutMap[&Op] = IdealStack;
299298

300299
// Remove anything from the stack top that can be freely generated or dupped
301300
// from deeper on the stack.
@@ -751,10 +750,10 @@ void EVMStackLayoutGenerator::addJunksToStackBottom(
751750
EntryTmp.append(MBBEntryLayoutMap.at(MBB));
752751
MBBEntryLayoutMap[MBB] = std::move(EntryTmp);
753752

754-
for (const Operation &Operation : StackModel.getOperations(MBB)) {
753+
for (const Operation &Op : StackModel.getOperations(MBB)) {
755754
Stack OpEntryTmp(NumJunk, EVMStackModel::getJunkSlot());
756-
OpEntryTmp.append(OperationEntryLayoutMap.at(&Operation));
757-
OperationEntryLayoutMap[&Operation] = std::move(OpEntryTmp);
755+
OpEntryTmp.append(OperationEntryLayoutMap.at(&Op));
756+
OperationEntryLayoutMap[&Op] = std::move(OpEntryTmp);
758757
}
759758

760759
Stack ExitTmp(NumJunk, EVMStackModel::getJunkSlot());

llvm/lib/Target/EVM/EVMStackModel.cpp

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ static const Function *getCalledFunction(const MachineInstr &MI) {
2929
}
3030
return nullptr;
3131
}
32-
// TODO: make it static once Operation gets rid of std::variant.
33-
std::string llvm::getInstName(const MachineInstr *MI) {
32+
static std::string getInstName(const MachineInstr *MI) {
3433
const MachineFunction *MF = MI->getParent()->getParent();
3534
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
3635
return TII->getName(MI->getOpcode()).str();
@@ -48,6 +47,24 @@ std::string TemporarySlot::toString() const {
4847
OS << "TMP[" << getInstName(MI) << ", " << std::to_string(Index) + "]";
4948
return std::string(S.str());
5049
}
50+
std::string Operation::toString() const {
51+
if (isFunctionCall()) {
52+
const MachineOperand *Callee = MI->explicit_uses().begin();
53+
return Callee->getGlobal()->getName().str();
54+
}
55+
if (isBuiltinCall())
56+
return getInstName(MI);
57+
58+
assert(isAssignment());
59+
SmallString<128> S;
60+
raw_svector_ostream OS(S);
61+
OS << "Assignment(";
62+
for (const auto *S : Output)
63+
OS << printReg(cast<VariableSlot>(S)->getReg(), nullptr, 0, nullptr)
64+
<< ", ";
65+
OS << ")";
66+
return std::string(S);
67+
}
5168

5269
EVMStackModel::EVMStackModel(MachineFunction &MF, const LiveIntervals &LIS)
5370
: MF(MF), LIS(LIS) {
@@ -128,22 +145,18 @@ void EVMStackModel::createOperation(MachineInstr &MI,
128145
return;
129146
case EVM::FCALL: {
130147
Stack Input;
131-
bool IsNoReturn = false;
132148
for (const MachineOperand &MO : MI.operands()) {
133149
if (MO.isGlobal()) {
134-
const auto *Func = dyn_cast<Function>(MO.getGlobal());
135-
assert(Func);
136-
IsNoReturn = Func->hasFnAttribute(Attribute::NoReturn);
137-
if (!IsNoReturn)
150+
const auto *Func = cast<Function>(MO.getGlobal());
151+
if (!Func->hasFnAttribute(Attribute::NoReturn))
138152
Input.push_back(getFunctionCallReturnLabelSlot(&MI));
139153
break;
140154
}
141155
}
142156
const Stack &Tmp = getInstrInput(MI);
143157
Input.insert(Input.end(), Tmp.begin(), Tmp.end());
144-
size_t NumArgs = Input.size() - (IsNoReturn ? 0 : 1);
145-
Ops.emplace_back(Operation{std::move(Input), getInstrOutput(MI),
146-
FunctionCall{&MI, NumArgs}});
158+
Ops.emplace_back(Operation::FunctionCall, std::move(Input),
159+
getInstrOutput(MI), &MI);
147160
} break;
148161
case EVM::RET:
149162
case EVM::JUMP:
@@ -165,21 +178,19 @@ void EVMStackModel::createOperation(MachineInstr &MI,
165178
return;
166179
} break;
167180
default: {
168-
Ops.emplace_back(
169-
Operation{getInstrInput(MI), getInstrOutput(MI), BuiltinCall{&MI}});
181+
Ops.emplace_back(Operation::BuiltinCall, getInstrInput(MI),
182+
getInstrOutput(MI), &MI);
170183
} break;
171184
}
172185

173186
// Create CFG::Assignment object for the MI.
174187
Stack Input, Output;
175-
SmallVector<VariableSlot *> Variables;
176188
switch (MI.getOpcode()) {
177189
case EVM::CONST_I256: {
178190
const Register DefReg = MI.getOperand(0).getReg();
179191
const APInt Imm = MI.getOperand(1).getCImm()->getValue();
180192
Input.push_back(getLiteralSlot(std::move(Imm)));
181193
Output.push_back(getVariableSlot(DefReg));
182-
Variables.push_back(getVariableSlot(DefReg));
183194
} break;
184195
case EVM::DATASIZE:
185196
case EVM::DATAOFFSET:
@@ -188,15 +199,13 @@ void EVMStackModel::createOperation(MachineInstr &MI,
188199
MCSymbol *Sym = MI.getOperand(1).getMCSymbol();
189200
Input.push_back(getSymbolSlot(Sym, &MI));
190201
Output.push_back(getVariableSlot(DefReg));
191-
Variables.push_back(getVariableSlot(DefReg));
192202
} break;
193203
case EVM::COPY_I256: {
194204
// Copy instruction corresponds to the assignment operator, so
195205
// we do not need to create intermediate TmpSlots.
196206
Input = getInstrInput(MI);
197207
const Register DefReg = MI.getOperand(0).getReg();
198208
Output.push_back(getVariableSlot(DefReg));
199-
Variables.push_back(getVariableSlot(DefReg));
200209
} break;
201210
default: {
202211
unsigned ArgsNumber = 0;
@@ -205,15 +214,14 @@ void EVMStackModel::createOperation(MachineInstr &MI,
205214
const Register Reg = MO.getReg();
206215
Input.push_back(getTemporarySlot(&MI, ArgsNumber++));
207216
Output.push_back(getVariableSlot(Reg));
208-
Variables.push_back(getVariableSlot(Reg));
209217
}
210218
} break;
211219
}
212220
// We don't need an assignment part of the instructions that do not write
213221
// results.
214222
if (!Input.empty() || !Output.empty())
215-
Ops.emplace_back(Operation{std::move(Input), std::move(Output),
216-
Assignment{std::move(Variables)}});
223+
Ops.emplace_back(Operation::Assignment, std::move(Input), std::move(Output),
224+
&MI);
217225
}
218226

219227
Stack EVMStackModel::getReturnArguments(const MachineInstr &MI) const {

llvm/lib/Target/EVM/EVMStackModel.h

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ namespace llvm {
3636
class MachineFunction;
3737
class MachineBasicBlock;
3838

39-
std::string getInstName(const MachineInstr *MI);
40-
4139
class StackSlot {
4240
public:
4341
enum SlotKind {
@@ -203,28 +201,33 @@ class JunkSlot final : public StackSlot {
203201
/// The stack top is the last element of the vector.
204202
using Stack = SmallVector<StackSlot *>;
205203

206-
struct BuiltinCall {
204+
class Operation {
205+
public:
206+
enum OpType { BuiltinCall, FunctionCall, Assignment };
207+
208+
private:
209+
OpType Type;
210+
// Stack slots this operation expects at the top of the stack and consumes.
211+
Stack Input;
212+
// Stack slots this operation leaves on the stack as output.
213+
Stack Output;
214+
// The emulated machine instruction.
207215
MachineInstr *MI = nullptr;
208-
};
209216

210-
struct FunctionCall {
211-
const MachineInstr *MI;
212-
size_t NumArguments = 0;
213-
};
217+
public:
218+
Operation(OpType Type, Stack Input, Stack Output, MachineInstr *MI)
219+
: Type(Type), Input(std::move(Input)), Output(std::move(Output)), MI(MI) {
220+
}
214221

215-
struct Assignment {
216-
/// The variables being assigned to also occur as 'Output' in the
217-
/// 'Operation' containing the assignment, but are also stored here for
218-
/// convenience.
219-
SmallVector<VariableSlot *> Variables;
220-
};
222+
const Stack &getInput() const { return Input; }
223+
const Stack &getOutput() const { return Output; }
224+
MachineInstr *getMachineInstr() const { return MI; }
221225

222-
struct Operation {
223-
/// Stack slots this operation expects at the top of the stack and consumes.
224-
Stack Input;
225-
/// Stack slots this operation leaves on the stack as output.
226-
Stack Output;
227-
std::variant<FunctionCall, BuiltinCall, Assignment> Operation;
226+
bool isBuiltinCall() const { return Type == BuiltinCall; }
227+
bool isFunctionCall() const { return Type == FunctionCall; }
228+
bool isAssignment() const { return Type == Assignment; }
229+
230+
std::string toString() const;
228231
};
229232

230233
class EVMStackModel {

0 commit comments

Comments
 (0)