From 558485504773804d56f0552517dbe42722742741 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Fri, 14 Aug 2026 22:07:42 +0800 Subject: [RISCV] Legalize va_copy intrinsics --- .../lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 120 +++++++++++++++++++++ .../lib/Target/RISCV/GISel/RISCVLegalizerInfo.h | 2 + 2 files changed, 122 insertions(+) (limited to 'backend/lib/Target') diff --git a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp index f1d2fac..88ee56a 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp @@ -15,6 +15,7 @@ #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/TargetDescription.h" +#include "rcc/IR/DataLayout.h" #include "rcc/Target/RISCV/RISCVSubtarget.h" #include "rcc/Target/RISCV/RISCVTarget.h" @@ -1186,4 +1187,123 @@ Expected RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, "RISC-V legalizer has no lowering rule for this instruction"); } +Expected RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, + MachineInstr &Instruction) const { + const MachineOperand *IntrinsicMachineOperand = Instruction.operandAt(0); + const auto *Intrinsic = IntrinsicMachineOperand == nullptr + ? nullptr + : IntrinsicMachineOperand->getIf(); + if (Intrinsic == nullptr) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V intrinsic legalization requires an intrinsic operand"); + if (Intrinsic->ID != intrinsicID(GenericIntrinsic::VACopy)) + return false; + if (Instruction.operandCount() != 3) + return makeUnexpected(ErrorCode::VerificationError, + "llvm.va_copy requires destination and source operands"); + + const MachineOperand *DestinationOperand = Instruction.operandAt(1); + const MachineOperand *SourceOperand = Instruction.operandAt(2); + const Register *Destination = + DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf(); + const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf(); + if (Destination == nullptr || Source == nullptr || !Destination->isVirtual() || + !Source->isVirtual()) { + return makeUnexpected(ErrorCode::VerificationError, + "llvm.va_copy requires virtual-register pointer operands"); + } + + MachineFunction &Function = Helper.MIRBuilder.function(); + auto DestinationType = Function.registerInfo().getType(*Destination); + if (!DestinationType) + return std::unexpected(DestinationType.error()); + auto SourceType = Function.registerInfo().getType(*Source); + if (!SourceType) + return std::unexpected(SourceType.error()); + if (!DestinationType->isPointer() || !SourceType->isPointer() || + *DestinationType != *SourceType || DestinationType->scalarBitWidth() == 0) { + return makeUnexpected(ErrorCode::VerificationError, + "llvm.va_copy operands must have the same scalar pointer type"); + } + + const auto AddressSpace = DestinationType->addressSpace(); + if (!AddressSpace) + return makeUnexpected(ErrorCode::VerificationError, + "llvm.va_copy pointer type has no address space"); + auto Layout = DataLayout::parse(TargetDataLayout); + if (!Layout) + return std::unexpected(Layout.error()); + const GenericConstantType PointerType = GenericConstantType::pointer(*AddressSpace); + auto PointerWidth = Layout->getPointerSizeInBits(*AddressSpace); + if (!PointerWidth) + return std::unexpected(PointerWidth.error()); + if (*PointerWidth != DestinationType->scalarBitWidth()) + return makeUnexpected(ErrorCode::VerificationError, + "llvm.va_copy pointer type disagrees with the target data layout"); + auto ABIAlignment = Layout->getABITypeAlign(PointerType); + if (!ABIAlignment) + return std::unexpected(ABIAlignment.error()); + auto Size = MemorySize::fixed((static_cast(*PointerWidth) + 7U) / 8U); + auto Alignment = rcc::Alignment::create(*ABIAlignment); + if (!Size || !Alignment) + return makeUnexpected(ErrorCode::InternalError, + "llvm.va_copy pointer type has an invalid memory layout"); + + MachineMemOperandDesc LoadDescription; + LoadDescription.Accesses = {MemoryAccessFlag::Load}; + LoadDescription.Size = *Size; + LoadDescription.MemoryType = *DestinationType; + LoadDescription.Align = *Alignment; + auto LoadMemory = Function.createMemOperand(std::move(LoadDescription)); + if (!LoadMemory) + return std::unexpected(LoadMemory.error()); + + MachineMemOperandDesc StoreDescription; + StoreDescription.Accesses = {MemoryAccessFlag::Store}; + StoreDescription.Size = *Size; + StoreDescription.MemoryType = *DestinationType; + StoreDescription.Align = *Alignment; + auto StoreMemory = Function.createMemOperand(std::move(StoreDescription)); + if (!StoreMemory) + return std::unexpected(StoreMemory.error()); + + auto Temporary = Function.registerInfo().createVirtualRegister(*DestinationType); + if (!Temporary) + return std::unexpected(Temporary.error()); + + if (auto Point = Helper.MIRBuilder.setInsertPointBefore(Instruction); !Point) + return std::unexpected(Point.error()); + auto LoadBuilder = Helper.MIRBuilder.buildInstr(opcode(GenericOpcode::G_LOAD)); + if (!LoadBuilder) + return std::unexpected(LoadBuilder.error()); + if (auto Added = LoadBuilder->addDef(*Temporary); !Added) + return std::unexpected(Added.error()); + if (auto Added = LoadBuilder->addUse(*Source); !Added) + return std::unexpected(Added.error()); + if (auto Added = LoadBuilder->addMemOperand(**LoadMemory); !Added) + return std::unexpected(Added.error()); + if (auto Built = LoadBuilder->build(); !Built) + return std::unexpected(Built.error()); + + auto StoreBuilder = Helper.MIRBuilder.buildInstr(opcode(GenericOpcode::G_STORE)); + if (!StoreBuilder) + return std::unexpected(StoreBuilder.error()); + if (auto Added = StoreBuilder->addUse(*Temporary); !Added) + return std::unexpected(Added.error()); + if (auto Added = StoreBuilder->addUse(*Destination); !Added) + return std::unexpected(Added.error()); + if (auto Added = StoreBuilder->addMemOperand(**StoreMemory); !Added) + return std::unexpected(Added.error()); + if (auto Built = StoreBuilder->build(); !Built) + return std::unexpected(Built.error()); + + MachineBasicBlock *Block = Instruction.parent(); + if (Block == nullptr) + return makeUnexpected(ErrorCode::InternalError, + "llvm.va_copy intrinsic became detached during lowering"); + if (auto Removed = Block->removeInstruction(Instruction); !Removed) + return std::unexpected(Removed.error()); + return true; +} + } // namespace rcc::riscv diff --git a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h index d8e5e3e..b6625ea 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h +++ b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h @@ -14,6 +14,8 @@ public: explicit RISCVLegalizerInfo(const RISCVSubtarget &Subtarget); [[nodiscard]] Expected legalizeCustom(LegalizerHelper &Helper, MachineInstr &Instruction, const LegalizationDecision &Decision) const override; + [[nodiscard]] Expected legalizeIntrinsic(LegalizerHelper &Helper, + MachineInstr &Instruction) const override; private: }; -- cgit v1.2.3