-
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 2 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,100 @@ | ||
| //===----- 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 IMM_RELOAD instructions representing spilled constants | ||
| // throughout the module. It spills constants at the start of the entry function | ||
| // and replaces IMM_RELOAD with the corresponding reload instructions. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "EVMConstantSpiller.h" | ||
| #include "EVMInstrInfo.h" | ||
| #include "EVMSubtarget.h" | ||
| #include "MCTargetDesc/EVMMCTargetDesc.h" | ||
| #include "TargetInfo/EVMTargetInfo.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/CodeGen/MachineModuleInfo.h" | ||
| #include "llvm/CodeGen/Passes.h" | ||
| #include "llvm/CodeGen/TargetSubtargetInfo.h" | ||
| #include "llvm/IR/Module.h" | ||
| #include "llvm/Support/Debug.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "evm-spill-constants" | ||
|
|
||
| constexpr uint64_t SpillSlotSize = 32; | ||
|
|
||
| static MachineInstr *emitPush(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator InsertBefore, | ||
| const EVMInstrInfo *TII, const APInt &Imm, | ||
| LLVMContext &Ctx, const DebugLoc &DL) { | ||
| unsigned Opc = EVM::getPUSHOpcode(Imm); | ||
|
||
| auto MI = BuildMI(MBB, InsertBefore, DL, TII->get(EVM::getStackOpcode(Opc))); | ||
| if (Opc != EVM::PUSH0) | ||
| MI.addCImm(ConstantInt::get(Ctx, Imm)); | ||
| return MI; | ||
| } | ||
|
|
||
| uint64_t EVMConstantSpiller::getSpillSize() const { | ||
| return ConstantToUseCount.size() * SpillSlotSize; | ||
| } | ||
|
|
||
| void EVMConstantSpiller::emitSpills(uint64_t SpillOffset, | ||
| MachineFunction &EntryMF) { | ||
| LLVMContext &Ctx = EntryMF.getFunction().getContext(); | ||
| const EVMInstrInfo *TII = EntryMF.getSubtarget<EVMSubtarget>().getInstrInfo(); | ||
|
|
||
| DenseMap<APInt, uint64_t> ConstantToSpillOffset; | ||
|
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. Maintainability: Spill offset == Num of const in ConstantToUseCount map * 32. Do we need a separate map for it?
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. 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. |
||
| 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. |
||
| 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'; | ||
| }); | ||
|
|
||
| BuildMI(SpillMBB, SpillMBB.begin(), DebugLoc(), TII->get(EVM::MSTORE_S)); | ||
|
||
| emitPush(SpillMBB, SpillMBB.begin(), TII, APInt(256, Offset), Ctx, | ||
| DebugLoc()); | ||
| emitPush(SpillMBB, SpillMBB.begin(), TII, Imm, Ctx, DebugLoc()); | ||
| } | ||
|
|
||
| // 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(); | ||
| emitPush(*MBB, MI, TII, APInt(256, Offset), Ctx, 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::IMM_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,50 @@ | ||
| //===----- 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 IMM_RELOAD instructions representing spilled constants | ||
| // throughout the module. It spills constants at the start of the entry function | ||
| // and replaces IMM_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 IMM_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; | ||
|
|
||
| /// IMM_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.
Why
IMM_RELOADif term constant is also use and constant is the correct term?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.
Changed to CONSTANT_RELOAD.