-
Notifications
You must be signed in to change notification settings - Fork 23
[EVM] Support for spilling constants to memory #885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
579ae55
78341c6
066d256
c65384a
579c8a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| //===----- EVMConstantSpiller.cpp - Spill constants to memory --*- C++ -*--===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file identifies CONSTANT_RELOAD instructions representing spilled | ||
| // constants throughout the module. It spills constants at the start of the | ||
| // entry function and replaces CONSTANT_RELOAD with the corresponding reload | ||
| // instructions. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "EVMConstantSpiller.h" | ||
| #include "EVMInstrInfo.h" | ||
| #include "EVMSubtarget.h" | ||
| #include "MCTargetDesc/EVMMCTargetDesc.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/CodeGen/MachineModuleInfo.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | ||
| #include "llvm/Support/Debug.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "evm-spill-constants" | ||
|
|
||
| constexpr uint64_t SpillSlotSize = 32; | ||
|
|
||
| uint64_t EVMConstantSpiller::getSpillSize() const { | ||
| return ConstantToUseCount.size() * SpillSlotSize; | ||
| } | ||
|
|
||
| void EVMConstantSpiller::emitSpills(uint64_t SpillOffset, | ||
| MachineFunction &EntryMF) { | ||
| const EVMInstrInfo *TII = EntryMF.getSubtarget<EVMSubtarget>().getInstrInfo(); | ||
|
|
||
| DenseMap<APInt, uint64_t> ConstantToSpillOffset; | ||
| for (const auto &KV : ConstantToUseCount) { | ||
| ConstantToSpillOffset[KV.first] = SpillOffset; | ||
| SpillOffset += SpillSlotSize; | ||
| } | ||
|
|
||
| // Emit constant stores in prologue of the entry function. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can probably elaborate this with a call graph and CFG analysis to make the pass more practical. Can we create a follow-up ticket + TODO?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, there could be several strategies. For example, we could compute the frequency of constants and perform spills at the machine function (MF) level. |
||
| // TODO: #925, elaborate analysis to determine the most suitable location | ||
| // for performing constant spilling. | ||
| MachineBasicBlock &SpillMBB = EntryMF.front(); | ||
| for (const auto &[Imm, Offset] : ConstantToSpillOffset) { | ||
| LLVM_DEBUG({ | ||
| dbgs() << "Spilling constant: " << Imm | ||
| << ", number of uses: " << ConstantToUseCount.at(Imm) | ||
| << ", at offset: " << Offset << '\n'; | ||
| }); | ||
|
|
||
| // Push the constant | ||
| TII->insertPush(Imm, SpillMBB, SpillMBB.begin(), DebugLoc()); | ||
| // Push the offset | ||
| TII->insertPush(APInt(256, Offset), SpillMBB, std::next(SpillMBB.begin()), | ||
| DebugLoc()); | ||
| BuildMI(SpillMBB, std::next(SpillMBB.begin(), 2), DebugLoc(), | ||
| TII->get(EVM::MSTORE_S)); | ||
| } | ||
|
|
||
| // Reload spilled constants. | ||
| for (MachineInstr *MI : Reloads) { | ||
| const APInt Imm = MI->getOperand(0).getCImm()->getValue().zext(256); | ||
| uint64_t Offset = ConstantToSpillOffset.at(Imm); | ||
|
|
||
| MachineBasicBlock *MBB = MI->getParent(); | ||
| TII->insertPush(APInt(256, Offset), *MBB, MI, MI->getDebugLoc()); | ||
| auto Load = BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(EVM::MLOAD_S)); | ||
| Load->setAsmPrinterFlag(MachineInstr::ReloadReuse); | ||
| MI->eraseFromParent(); | ||
| } | ||
| } | ||
|
|
||
| EVMConstantSpiller::EVMConstantSpiller(SmallVector<MachineFunction *> &MFs) { | ||
| for (MachineFunction *MF : MFs) { | ||
| for (MachineBasicBlock &MBB : *MF) { | ||
| for (MachineInstr &MI : MBB) { | ||
| if (MI.getOpcode() != EVM::CONSTANT_RELOAD) | ||
| continue; | ||
|
|
||
| const APInt Imm = MI.getOperand(0).getCImm()->getValue().zext(256); | ||
| ConstantToUseCount[Imm]++; | ||
| Reloads.push_back(&MI); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| //===----- EVMConstantSpiller.h - Spill constants to memory ----*- C++ -*--===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file identifies CONSTANT_RELOAD instructions representing spilled | ||
| // constants throughout the module. It spills constants at the start of the | ||
| // entry function and replaces CONSTANT_RELOAD with the corresponding reload | ||
| // instructions. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H | ||
| #define LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H | ||
|
|
||
| // #include "llvm/IR/Module.h" | ||
| #include "llvm/ADT/APInt.h" | ||
| #include "llvm/ADT/DenseMap.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class MachineInstr; | ||
| class MachineFunction; | ||
|
|
||
| class EVMConstantSpiller { | ||
| public: | ||
| explicit EVMConstantSpiller(SmallVector<MachineFunction *> &MFs); | ||
|
|
||
| /// Inserts constant spills into the first basic block of the entry | ||
| /// function and replaces CONSTANT_RELOAD with the corresponding reload | ||
| /// instructions at their use sites. | ||
| void emitSpills(uint64_t SpillOffset, MachineFunction &EntryMF); | ||
|
|
||
| /// Return the total size needed for the spill area. | ||
| uint64_t getSpillSize() const; | ||
|
|
||
| private: | ||
| /// Maps each APInt constant to the number of times it appears across all | ||
| /// functions in the module | ||
| SmallDenseMap<APInt, unsigned> ConstantToUseCount; | ||
|
|
||
| /// CONSTANT_RELOAD instructions that need to be converted into actuall | ||
| /// reloads. | ||
| SmallVector<MachineInstr *> Reloads; | ||
| }; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_EVM_EVMCONSTANTSPILLER_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintainability: Spill offset == Num of const in ConstantToUseCount map * 32. Do we need a separate map for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's convenient to have a map with final offsets because, as we refer to this info twice. The second time if when we walk over reloads.