Skip to content

Commit 3a2fa00

Browse files
committed
[EVM] Support for spilling constants to memory
The constant spilling mechanism is divided between two components: - ConstantUnfolder Determines which constants are profitable to spill. For these constants, it emits codegen-only 'IMM_RELOAD Imm' instructions. - ConstantSpiller Inserts spills at the beginning of the entry machine function and replaces IMM_RELOAD instructions with the actual reloads. It also calculates the required size of the constants’ spill area in the heap. ConstantSpiller is called from EVMFinalizeStackFrames so that the actual offsets to the spill area can be computed.
1 parent 3ca86f7 commit 3a2fa00

File tree

7 files changed

+395
-19
lines changed

7 files changed

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

0 commit comments

Comments
 (0)