aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/GlobalISel/Legalizer.cpp33
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp120
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h2
3 files changed, 155 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp
index c749039..dfa4523 100644
--- a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp
+++ b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp
@@ -70,6 +70,18 @@ namespace {
}
}
+[[nodiscard]] bool isIntrinsicOpcode(Opcode InstructionOpcode) noexcept {
+ switch (static_cast<GenericOpcode>(InstructionOpcode.value())) {
+ default:
+ return false;
+ case GenericOpcode::G_INTRINSIC:
+ case GenericOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
+ case GenericOpcode::G_INTRINSIC_CONVERGENT:
+ case GenericOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
+ return true;
+ }
+}
+
using InstList = GISelWorkList<256>;
using ArtifactList = GISelWorkList<128>;
@@ -329,6 +341,27 @@ Expected<MachinePassResult> Legalizer::runImplementation(MachineFunction &Functi
withErrorContext(Validation.error(), "legalizer input is invalid: "));
}
+ if (isIntrinsicOpcode(Instruction->opcode())) {
+ auto Accepted = Actions.request("legalize.intrinsic", Function, Instruction->stableID());
+ if (!Accepted)
+ return std::unexpected(Accepted.error());
+ if (!*Accepted)
+ return std::unexpected(passFailure("required intrinsic legalization action was rejected",
+ ErrorCode::VerificationError));
+ auto IntrinsicResult = Info->legalizeIntrinsic(Helper, *Instruction);
+ if (!IntrinsicResult)
+ return std::unexpected(IntrinsicResult.error());
+ if (!*IntrinsicResult) {
+ const std::string_view Name = Descriptor->Name;
+ return std::unexpected(passFailure("target legalizer rejected intrinsic instruction '" +
+ std::string(Name) + "'",
+ ErrorCode::Unsupported));
+ }
+ Result.Changed = true;
+ Result.Changes.add(MachinePassChange::Instructions);
+ continue;
+ }
+
auto Decision = Info->getDecision(*Instruction, Function, Target);
if (!Decision)
return std::unexpected(Decision.error());
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<void> RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
"RISC-V legalizer has no lowering rule for this instruction");
}
+Expected<bool> RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
+ MachineInstr &Instruction) const {
+ const MachineOperand *IntrinsicMachineOperand = Instruction.operandAt(0);
+ const auto *Intrinsic = IntrinsicMachineOperand == nullptr
+ ? nullptr
+ : IntrinsicMachineOperand->getIf<rcc::IntrinsicOperand>();
+ 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<Register>();
+ const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>();
+ 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<std::uint64_t>(*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<void> legalizeCustom(LegalizerHelper &Helper, MachineInstr &Instruction,
const LegalizationDecision &Decision) const override;
+ [[nodiscard]] Expected<bool> legalizeIntrinsic(LegalizerHelper &Helper,
+ MachineInstr &Instruction) const override;
private:
};