aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp')
-rw-r--r--backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp123
1 files changed, 123 insertions, 0 deletions
diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
index df3e5ad..257fa3a 100644
--- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
+++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
@@ -28,6 +28,7 @@ constexpr std::uint32_t PCRelativeHighFlag = 2;
constexpr std::uint32_t PCRelativeLowFlag = 4;
constexpr std::uint32_t CopyF32Flag = 8;
constexpr std::uint32_t CopyF64Flag = 16;
+constexpr std::uint32_t GOTPCRelativeHighFlag = 128;
[[nodiscard]] std::optional<RegisterBankID>
registerBank(Register Reg, const MachineFunction &Function, const TargetDescription &Target) {
@@ -300,6 +301,121 @@ copyRegisters(const MachineInstr &Instruction) {
"RISC-V direct call pseudo has no symbol target");
}
+[[nodiscard]] Expected<Register> createGPRScratchRegister(MachineFunction &Function,
+ const TargetDescription &Target) {
+ const RegisterBankID GPRBank =
+ RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::GPR));
+ const RegisterClassID GPRClass =
+ RegisterClassID::fromValue(static_cast<std::uint32_t>(RegisterClass::GPR));
+ if (Target.registers().registerBank(GPRBank) == nullptr ||
+ Target.registers().registerClass(GPRClass) == nullptr) {
+ return makeUnexpected(ErrorCode::InternalError,
+ "RISC-V pre-RA address expansion requires the GPR register class");
+ }
+ auto Scratch = Function.registerInfo().createVirtualRegister();
+ if (!Scratch)
+ return std::unexpected(Scratch.error());
+ auto SetBank = Function.registerInfo().setRegisterBank(*Scratch, GPRBank);
+ if (!SetBank)
+ return std::unexpected(SetBank.error());
+ auto SetClass = Function.registerInfo().setRegisterClass(*Scratch, GPRClass);
+ if (!SetClass)
+ return std::unexpected(SetClass.error());
+ return *Scratch;
+}
+
+[[nodiscard]] Expected<bool> expandAddressPseudo(MachineInstr &Instruction,
+ MachineFunction &Function,
+ const TargetDescription &Target,
+ bool LoadFromGOT) {
+ const MachineOperand *Destination = Instruction.operandAt(0);
+ const MachineOperand *Symbol = Instruction.operandAt(1);
+ const Register *DestinationRegister =
+ Destination == nullptr ? nullptr : Destination->getIf<Register>();
+ if (DestinationRegister == nullptr || Symbol == nullptr || Instruction.operandCount() != 2) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V address pseudo has malformed explicit operands");
+ }
+ if (LoadFromGOT && Instruction.memOperands().size() != 1) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V global-address pseudo requires one GOT load memory operand");
+ }
+ if (!LoadFromGOT && !Instruction.memOperands().empty()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V local-address pseudo cannot carry memory operands");
+ }
+
+ auto Scratch = createGPRScratchRegister(Function, Target);
+ if (!Scratch)
+ return std::unexpected(Scratch.error());
+ MachineIRBuilder Builder(Function, Target);
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+
+ auto HighPending = Builder.buildInstr(instructionOpcode(InstructionOpcode::AUIPC));
+ if (!HighPending)
+ return std::unexpected(HighPending.error());
+ auto HighDef = HighPending->addDef(*Scratch);
+ if (!HighDef)
+ return std::unexpected(HighDef.error());
+ MachineOperand HighSymbol = Symbol->cloneDetached();
+ HighSymbol.setTargetFlags(LoadFromGOT ? GOTPCRelativeHighFlag : PCRelativeHighFlag);
+ auto HighTarget = HighPending->addOperand(std::move(HighSymbol));
+ if (!HighTarget)
+ return std::unexpected(HighTarget.error());
+ auto High = HighPending->build();
+ if (!High)
+ return std::unexpected(High.error());
+ const std::string Anchor = Instruction.preInstrSymbol()
+ ? std::string(*Instruction.preInstrSymbol())
+ : ".Lrcc_pcrel_hi_" + std::to_string(Function.stableID().value()) +
+ "_" + std::to_string((*High)->stableID().value());
+ auto HighAnchor = (*High)->setPreInstrSymbol(Anchor);
+ if (!HighAnchor)
+ return std::unexpected(HighAnchor.error());
+ auto HighDecoration = copyCommonDecoration(Instruction, **High, false, false, false);
+ if (!HighDecoration)
+ return std::unexpected(HighDecoration.error());
+
+ const InstructionOpcode LowOpcode = LoadFromGOT ? InstructionOpcode::LD : InstructionOpcode::ADDI;
+ auto LowPending = Builder.buildInstr(instructionOpcode(LowOpcode));
+ if (!LowPending)
+ return std::unexpected(LowPending.error());
+ auto LowDef = LowPending->addOperand(Destination->cloneDetached());
+ if (!LowDef)
+ return std::unexpected(LowDef.error());
+ auto LowBase = LowPending->addUse(*Scratch);
+ if (!LowBase)
+ return std::unexpected(LowBase.error());
+ auto LowOffset = LowPending->addMCSymbol(Anchor, 0, PCRelativeLowFlag);
+ if (!LowOffset)
+ return std::unexpected(LowOffset.error());
+ if (LoadFromGOT) {
+ const MachineMemOperand *Memory = Instruction.memOperands().front();
+ if (Memory == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V global-address pseudo has a null memory operand");
+ auto AddedMemory = LowPending->addMemOperand(*Memory);
+ if (!AddedMemory)
+ return std::unexpected(AddedMemory.error());
+ }
+ auto Low = LowPending->build();
+ if (!Low)
+ return std::unexpected(Low.error());
+ auto LowDecoration = copyCommonDecoration(Instruction, **Low, false, true, true);
+ if (!LowDecoration)
+ return std::unexpected(LowDecoration.error());
+ auto Records =
+ Function.records().replaceInstructionReference(Instruction.stableID(), (*Low)->stableID());
+ if (!Records)
+ return std::unexpected(Records.error());
+ auto Removed = removeOldInstruction(Instruction);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ return true;
+}
+
[[nodiscard]] bool isRegister(const MachineOperand &Operand, PhysicalRegister Reg) noexcept {
const Register *Value = Operand.getIf<Register>();
return Value != nullptr && Value->physicalRegister() == Reg;
@@ -601,6 +717,13 @@ public:
MachinePseudoExpansionPhase Phase,
MachineFunction &Function,
const TargetDescription &Target) const override {
+ if (Phase == MachinePseudoExpansionPhase::PreRA) {
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoLLA))
+ return expandAddressPseudo(Instruction, Function, Target, false);
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoLGA))
+ return expandAddressPseudo(Instruction, Function, Target, true);
+ return false;
+ }
if (Phase != MachinePseudoExpansionPhase::PostRA)
return false;
if (Instruction.opcode() == opcode(GenericOpcode::COPY))