Skip to content

Commit 9c8da3c

Browse files
committed
[EVM] Support for spilling constants to memory
1 parent 50ed21a commit 9c8da3c

File tree

7 files changed

+369
-19
lines changed

7 files changed

+369
-19
lines changed

llvm/lib/Target/EVM/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_llvm_target(EVMCodeGen
2424
EVMAsmPrinter.cpp
2525
EVMBackwardPropagationStackification.cpp
2626
EVMCalculateModuleSize.cpp
27+
EVMConstantSpiller.cpp
2728
EVMConstantUnfolding.cpp
2829
EVMCodegenPrepare.cpp
2930
EVMFinalizeStackFrames.cpp
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===----- EVMConstantSpiller.cpp - Spill constants to memory --*- C++ -*--===//
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+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
#include "EVMConstantSpiller.h"
13+
#include "EVMInstrInfo.h"
14+
#include "EVMSubtarget.h"
15+
#include "MCTargetDesc/EVMMCTargetDesc.h"
16+
#include "TargetInfo/EVMTargetInfo.h"
17+
#include "llvm/CodeGen/MachineFrameInfo.h"
18+
#include "llvm/CodeGen/MachineModuleInfo.h"
19+
#include "llvm/CodeGen/Passes.h"
20+
#include "llvm/CodeGen/TargetInstrInfo.h"
21+
#include "llvm/CodeGen/TargetSubtargetInfo.h"
22+
#include "llvm/IR/Module.h"
23+
#include "llvm/Support/Debug.h"
24+
25+
using namespace llvm;
26+
27+
#define DEBUG_TYPE "evm-spill-constants"
28+
29+
constexpr uint64_t SpillSlotSize = 32;
30+
31+
static MachineInstr *emitPush(MachineBasicBlock &MBB,
32+
MachineBasicBlock::iterator InsertBefore,
33+
const EVMInstrInfo *TII, const APInt &Imm,
34+
LLVMContext &Ctx, const DebugLoc &DL) {
35+
unsigned Opc = EVM::getPUSHOpcode(Imm);
36+
auto MI = BuildMI(MBB, InsertBefore, DL, TII->get(EVM::getStackOpcode(Opc)));
37+
if (Opc != EVM::PUSH0)
38+
MI.addCImm(ConstantInt::get(Ctx, Imm));
39+
return MI;
40+
}
41+
42+
uint64_t EVMConstantSpiller::getSpillSize() const {
43+
return ConstantToUseCount.size() * SpillSlotSize;
44+
}
45+
46+
void EVMConstantSpiller::emitSpills(uint64_t SpillOffset,
47+
MachineFunction &EntryMF) {
48+
LLVMContext &Ctx = EntryMF.getFunction().getContext();
49+
const EVMInstrInfo *TII = EntryMF.getSubtarget<EVMSubtarget>().getInstrInfo();
50+
51+
DenseMap<APInt, uint64_t> ConstantToSpillOffset;
52+
for (const auto &KV : ConstantToUseCount) {
53+
ConstantToSpillOffset[KV.first] = SpillOffset;
54+
SpillOffset += SpillSlotSize;
55+
}
56+
57+
// Emit constant stores in prologue of the '__entry' function.
58+
MachineBasicBlock &SpillMBB = EntryMF.front();
59+
for (const auto &[Imm, Offset] : ConstantToSpillOffset) {
60+
LLVM_DEBUG({
61+
dbgs() << "Spilling constant: " << Imm
62+
<< ", number of uses: " << ConstantToUseCount.at(Imm)
63+
<< ", at offset: " << Offset << '\n';
64+
});
65+
66+
BuildMI(SpillMBB, SpillMBB.begin(), DebugLoc(), TII->get(EVM::MSTORE_S));
67+
emitPush(SpillMBB, SpillMBB.begin(), TII, APInt(256, Offset), Ctx,
68+
DebugLoc());
69+
emitPush(SpillMBB, SpillMBB.begin(), TII, Imm, Ctx, DebugLoc());
70+
}
71+
72+
// Reload spilled constants.
73+
for (MachineInstr *MI : Reloads) {
74+
const APInt Imm = MI->getOperand(0).getCImm()->getValue().zext(256);
75+
uint64_t Offset = ConstantToSpillOffset.at(Imm);
76+
77+
MachineBasicBlock *MBB = MI->getParent();
78+
emitPush(*MBB, MI, TII, APInt(256, Offset), Ctx, MI->getDebugLoc());
79+
auto Load = BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(EVM::MLOAD_S));
80+
Load->setAsmPrinterFlag(MachineInstr::ReloadReuse);
81+
MI->eraseFromParent();
82+
}
83+
}
84+
85+
EVMConstantSpiller::EVMConstantSpiller(SmallVector<MachineFunction *> &MFs) {
86+
for (MachineFunction *MF : MFs) {
87+
for (MachineBasicBlock &MBB : *MF) {
88+
for (MachineInstr &MI : MBB) {
89+
if (MI.getOpcode() != EVM::IMM_RELOAD)
90+
continue;
91+
92+
const APInt Imm = MI.getOperand(0).getCImm()->getValue().zext(256);
93+
ConstantToUseCount[Imm]++;
94+
Reloads.push_back(&MI);
95+
}
96+
}
97+
}
98+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===----- EVMConstantSpiller.h - Spill constants to memory ----*- C++ -*--===//
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+
// This file identifies frequently used large constants across the module.
10+
// If a constant’s usage exceeds the threshold and its bit-width is sufficient,
11+
// it is spilled at the beginning of the __entry function and reloaded at use
12+
// sites.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H
17+
#define LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H
18+
19+
#include "llvm/IR/Module.h"
20+
21+
namespace llvm {
22+
23+
class MachineInstr;
24+
class MachineFunction;
25+
26+
class EVMConstantSpiller {
27+
public:
28+
explicit EVMConstantSpiller(SmallVector<MachineFunction *> &MFs);
29+
30+
void emitSpills(uint64_t SpillOffset, MachineFunction &EntryMF);
31+
32+
uint64_t getSpillSize() const;
33+
34+
private:
35+
/// Maps each APInt constant to the number of times it appears across all
36+
/// functions in the module
37+
SmallDenseMap<APInt, unsigned> ConstantToUseCount;
38+
39+
/// PUSH instructions that need to be reloaded
40+
SmallVector<MachineInstr *> Reloads;
41+
};
42+
} // namespace llvm
43+
44+
#endif // LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H

0 commit comments

Comments
 (0)