diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/include/rcc/CodeGen/GlobalISel/Legalizer.h | 18 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/GlobalISel/LegalizerHelper.h | 6 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/TargetCallLowering.h | 5 | ||||
| -rw-r--r-- | backend/lib/CodeGen/GlobalISel/Legalizer.cpp | 4 | ||||
| -rw-r--r-- | backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 218 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 11 |
6 files changed, 249 insertions, 13 deletions
diff --git a/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h b/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h index 358ed1a..2ba0012 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h +++ b/backend/include/rcc/CodeGen/GlobalISel/Legalizer.h @@ -6,6 +6,7 @@ #include "rcc/CodeGen/CommandFlags.h" #include "rcc/CodeGen/GlobalISel/LegalizerInfo.h" #include "rcc/CodeGen/MachinePassManager.h" +#include "rcc/CodeGen/TargetCallLowering.h" #include <memory> @@ -13,12 +14,16 @@ namespace rcc { class Legalizer final : public MachineFunctionPass { public: - Legalizer(const LegalizerInfo *Info, OptimizationLevel Optimization) - : Info(Info), Optimization(Optimization) {} - Legalizer(const LegalizerInfo &Info, OptimizationLevel Optimization) - : Info(&Info), Optimization(Optimization) {} - Legalizer(std::unique_ptr<LegalizerInfo> Info, OptimizationLevel Optimization) - : OwnedInfo(std::move(Info)), Info(OwnedInfo.get()), Optimization(Optimization) {} + Legalizer(const LegalizerInfo *Info, OptimizationLevel Optimization, + LibcallLoweringInfo Libcalls = {}) + : Info(Info), Optimization(Optimization), Libcalls(Libcalls) {} + Legalizer(const LegalizerInfo &Info, OptimizationLevel Optimization, + LibcallLoweringInfo Libcalls = {}) + : Info(&Info), Optimization(Optimization), Libcalls(Libcalls) {} + Legalizer(std::unique_ptr<LegalizerInfo> Info, OptimizationLevel Optimization, + LibcallLoweringInfo Libcalls = {}) + : OwnedInfo(std::move(Info)), Info(OwnedInfo.get()), Optimization(Optimization), + Libcalls(Libcalls) {} [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, @@ -33,6 +38,7 @@ private: std::unique_ptr<LegalizerInfo> OwnedInfo; const LegalizerInfo *Info = nullptr; OptimizationLevel Optimization; + LibcallLoweringInfo Libcalls; }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/GlobalISel/LegalizerHelper.h b/backend/include/rcc/CodeGen/GlobalISel/LegalizerHelper.h index 9ad66a2..39304ba 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/LegalizerHelper.h +++ b/backend/include/rcc/CodeGen/GlobalISel/LegalizerHelper.h @@ -15,6 +15,7 @@ namespace rcc { class MachineFunction; class MachineInstr; class GISelChangeObserver; +struct LibcallLoweringInfo; class LegalizerHelper final { public: @@ -22,7 +23,8 @@ public: GISelChangeObserver &Observer; LegalizerHelper(MachineFunction &Function, const LegalizerInfo &Info, - GISelChangeObserver &Observer, MachineIRBuilder &MIRBuilder); + GISelChangeObserver &Observer, MachineIRBuilder &MIRBuilder, + const LibcallLoweringInfo *Libcalls = nullptr); [[nodiscard]] Expected<void> legalize(MachineInstr &Instruction, const LegalizationDecision &Decision); @@ -35,6 +37,7 @@ public: [[nodiscard]] Expected<void> lowerThreewayCompare(MachineInstr &Instruction); [[nodiscard]] Expected<void> lowerRotate(MachineInstr &Instruction); [[nodiscard]] Expected<void> lowerVAArg(MachineInstr &Instruction); + [[nodiscard]] Expected<void> libcall(MachineInstr &Instruction); [[nodiscard]] Expected<void> widenScalar(MachineInstr &Instruction, std::size_t TypeIndex, LowLevelType WideType); [[nodiscard]] Expected<void> widenScalarSrc(MachineInstr &Instruction, LowLevelType WideType, @@ -118,6 +121,7 @@ private: MachineFunction &Function; MachineRegisterInfo &MRI; const LegalizerInfo &Info; + const LibcallLoweringInfo *Libcalls = nullptr; }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/TargetCallLowering.h b/backend/include/rcc/CodeGen/TargetCallLowering.h index 21b5407..576ec39 100644 --- a/backend/include/rcc/CodeGen/TargetCallLowering.h +++ b/backend/include/rcc/CodeGen/TargetCallLowering.h @@ -402,6 +402,11 @@ public: const CallLoweringPlan &Plan) const = 0; }; +struct LibcallLoweringInfo final { + const TargetCallLowering *CallLowering = nullptr; + CallingConventionID Convention; +}; + } // namespace rcc #endif // RCC_CODEGEN_TARGETCALLLOWERING_H diff --git a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp index 77c1b0c..877777e 100644 --- a/backend/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/backend/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -320,7 +320,9 @@ Expected<MachinePassResult> Legalizer::runImplementation(MachineFunction &Functi MachineFunctionDelegateInstaller ObserverInstaller(Function, Observer); CSEMIRBuilder Builder(Function, Target); Builder.setCSEInfo(&CSEInfo); - LegalizerHelper Helper(Function, *Info, Observer, Builder); + const LibcallLoweringInfo *ActiveLibcalls = + Libcalls.CallLowering == nullptr ? nullptr : &Libcalls; + LegalizerHelper Helper(Function, *Info, Observer, Builder, ActiveLibcalls); GISelValueTracking ValueTracking(Function, Target); LegalizationArtifactCombiner ArtifactCombiner(Builder, Function.registerInfo(), *Info, &ValueTracking); diff --git a/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 4ac88ed..84513e6 100644 --- a/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/backend/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -10,6 +10,7 @@ #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineRegisterInfo.h" +#include "rcc/CodeGen/TargetCallLowering.h" #include <algorithm> #include <bit> @@ -19,7 +20,10 @@ #include <numeric> #include <optional> #include <span> +#include <string> +#include <string_view> #include <utility> +#include <vector> namespace rcc { namespace { @@ -175,12 +179,90 @@ struct ScalarLayout final { return *Result; } +[[nodiscard]] Expected<std::string> integerLibcallName(GenericOpcode Generic, + std::uint32_t BitWidth) { + std::string_view Prefix; + switch (Generic) { + case GenericOpcode::G_MUL: + Prefix = "__mul"; + break; + case GenericOpcode::G_SDIV: + Prefix = "__div"; + break; + case GenericOpcode::G_UDIV: + Prefix = "__udiv"; + break; + case GenericOpcode::G_SREM: + Prefix = "__mod"; + break; + case GenericOpcode::G_UREM: + Prefix = "__umod"; + break; + default: + return makeUnexpected(ErrorCode::Unsupported, + "integer libcall has no runtime function mapping"); + } + + std::string_view Suffix; + switch (BitWidth) { + case 32: + Suffix = "si3"; + break; + case 64: + Suffix = "di3"; + break; + case 128: + Suffix = "ti3"; + break; + default: + return makeUnexpected(ErrorCode::Unsupported, + "integer libcall requires a 32, 64, or 128-bit scalar"); + } + return std::string(Prefix) + std::string(Suffix); +} + +[[nodiscard]] ABIExtensionKind integerLibcallExtension(GenericOpcode Generic, + std::uint32_t BitWidth) noexcept { + if (BitWidth >= 64) + return ABIExtensionKind::None; + if (Generic == GenericOpcode::G_SDIV || Generic == GenericOpcode::G_SREM) + return ABIExtensionKind::SignExtend; + if (Generic == GenericOpcode::G_UDIV || Generic == GenericOpcode::G_UREM) + return ABIExtensionKind::ZeroExtend; + return ABIExtensionKind::AnyExtend; +} + +[[nodiscard]] Expected<ABIValue> +integerABIValue(Register Value, LowLevelType Type, std::uint32_t OriginalValue, + std::uint16_t FragmentIndex, std::uint16_t FragmentCount, + std::uint32_t FragmentOffsetBytes, Alignment OriginalAlignment, + ABIExtensionKind Extension) { + auto OneByte = Alignment::create(1); + if (!OneByte) + return std::unexpected(OneByte.error()); + return ABIValue{ + .Value = Value, + .Type = Type, + .Category = ABIValueCategory::Integer, + .OriginalValue = OriginalValue, + .FragmentIndex = FragmentIndex, + .FragmentCount = FragmentCount, + .FragmentOffsetBytes = FragmentOffsetBytes, + .OriginalAlignment = OriginalAlignment, + .Extension = Extension, + .Flags = {}, + .ByValSizeBytes = 0, + .ByValAlignment = *OneByte, + }; +} + } // namespace LegalizerHelper::LegalizerHelper(MachineFunction &Function, const LegalizerInfo &Info, - GISelChangeObserver &Observer, MachineIRBuilder &MIRBuilder) + GISelChangeObserver &Observer, MachineIRBuilder &MIRBuilder, + const LibcallLoweringInfo *Libcalls) : MIRBuilder(MIRBuilder), Observer(Observer), Function(Function), MRI(Function.registerInfo()), - Info(Info) {} + Info(Info), Libcalls(Libcalls) {} Expected<void> LegalizerHelper::widenScalarMergeValues(MachineInstr &Instruction, std::size_t TypeIndex, @@ -3445,6 +3527,135 @@ Expected<void> LegalizerHelper::lowerRotate(MachineInstr &Instruction) { return Block->removeInstruction(Instruction); } +Expected<void> LegalizerHelper::libcall(MachineInstr &Instruction) { + if (Libcalls == nullptr || Libcalls->CallLowering == nullptr) { + return makeUnexpected(ErrorCode::Unsupported, + "libcall legalization requires target call lowering information"); + } + + const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value()); + auto DestinationOperand = Instruction.operandAt(0); + const Register *Destination = + DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); + if (Destination == nullptr || !DestinationOperand->isDef()) { + return makeUnexpected(ErrorCode::VerificationError, + "integer libcall requires a register destination"); + } + auto Type = MRI.getType(*Destination); + if (!Type) + return std::unexpected(Type.error()); + if (!Type->isCategoryNeutralScalar()) { + return makeUnexpected(ErrorCode::Unsupported, + "integer libcall requires a category-neutral scalar type"); + } + + const std::uint32_t BitWidth = Type->scalarBitWidth(); + auto Name = integerLibcallName(Generic, BitWidth); + if (!Name) + return std::unexpected(Name.error()); + auto OriginalAlignment = Alignment::create(BitWidth == 128 ? 16 : BitWidth / 8U); + if (!OriginalAlignment) + return std::unexpected(OriginalAlignment.error()); + auto FragmentType = LowLevelType::makeCategoryNeutralScalar(64); + if (!FragmentType) + return std::unexpected(FragmentType.error()); + if (auto Point = MIRBuilder.setInsertPointBefore(Instruction); !Point) + return std::unexpected(Point.error()); + + const ABIExtensionKind Extension = integerLibcallExtension(Generic, BitWidth); + auto AppendValue = [&](Register Value, std::uint32_t OriginalValue, bool IsResult, + std::vector<ABIValue> &Values, + std::vector<Register> *Fragments) -> Expected<void> { + if (BitWidth != 128) { + auto ABI = + integerABIValue(Value, *Type, OriginalValue, 0, 1, 0, *OriginalAlignment, Extension); + if (!ABI) + return std::unexpected(ABI.error()); + Values.push_back(*ABI); + if (Fragments != nullptr) + Fragments->push_back(Value); + return {}; + } + + std::vector<Register> PartRegisters; + PartRegisters.reserve(2); + for (std::size_t Index = 0; Index != 2; ++Index) { + auto Part = MRI.createVirtualRegister(*FragmentType); + if (!Part) + return std::unexpected(Part.error()); + PartRegisters.push_back(*Part); + } + if (!IsResult) { + auto Unmerged = MIRBuilder.buildUnmergeValues(PartRegisters, Value); + if (!Unmerged) + return std::unexpected(Unmerged.error()); + } + for (std::uint16_t Index = 0; Index != 2; ++Index) { + auto ABI = integerABIValue(PartRegisters[Index], *FragmentType, OriginalValue, Index, 2, + static_cast<std::uint32_t>(Index) * 8U, *OriginalAlignment, + ABIExtensionKind::None); + if (!ABI) + return std::unexpected(ABI.error()); + Values.push_back(*ABI); + } + if (Fragments != nullptr) + *Fragments = std::move(PartRegisters); + return {}; + }; + + std::vector<ABIValue> Arguments; + Arguments.reserve((Instruction.operandCount() - 1U) * (BitWidth == 128 ? 2U : 1U)); + std::uint32_t OriginalArgument = 0; + for (std::size_t Index = 1; Index != Instruction.operandCount(); ++Index) { + const MachineOperand *Operand = Instruction.operandAt(Index); + const Register *Source = Operand == nullptr ? nullptr : Operand->getIf<Register>(); + if (Source == nullptr || !Operand->isUse()) { + return makeUnexpected(ErrorCode::VerificationError, + "integer libcall requires register source operands"); + } + auto SourceType = MRI.getType(*Source); + if (!SourceType) + return std::unexpected(SourceType.error()); + if (*SourceType != *Type) { + return makeUnexpected(ErrorCode::VerificationError, + "integer libcall source and destination types must match"); + } + if (auto Appended = AppendValue(*Source, OriginalArgument++, false, Arguments, nullptr); + !Appended) { + return std::unexpected(Appended.error()); + } + } + + std::vector<ABIValue> Results; + std::vector<Register> ResultFragments; + if (auto Appended = AppendValue(*Destination, 0, true, Results, &ResultFragments); !Appended) + return std::unexpected(Appended.error()); + + auto Callee = MachineCallTarget::externalSymbol(std::move(*Name)); + if (!Callee) + return std::unexpected(Callee.error()); + CallLoweringRequest Request; + Request.Convention = Libcalls->Convention; + Request.Callee = std::move(*Callee); + Request.Arguments = std::move(Arguments); + Request.Results = std::move(Results); + Request.FixedArgumentCount = OriginalArgument; + if (auto Lowered = Libcalls->CallLowering->lowerCall(MIRBuilder, Request); !Lowered) + return std::unexpected(Lowered.error()); + + if (BitWidth == 128) { + auto Merged = MIRBuilder.buildMergeLikeInstr(*Destination, ResultFragments); + if (!Merged) + return std::unexpected(Merged.error()); + } + + MachineBasicBlock *Block = Instruction.parent(); + if (Block == nullptr) + return makeUnexpected(ErrorCode::InternalError, + "integer libcall became detached during legalization"); + return Block->removeInstruction(Instruction); +} + Expected<void> LegalizerHelper::lowerSignedAddSubOverflow(MachineInstr &Instruction) { const bool IsAdd = Instruction.opcode() == opcode(GenericOpcode::G_SADDO); const Register Destination = *Instruction.operandAt(0)->getIf<Register>(); @@ -3529,10 +3740,11 @@ Expected<void> LegalizerHelper::legalize(MachineInstr &Instruction, return Info.legalizeCustom(*this, Instruction, Decision); case LegalizationAction::Lower: return lower(Instruction, Decision); + case LegalizationAction::Libcall: + return libcall(Instruction); case LegalizationAction::Legal: return {}; case LegalizationAction::Unsupported: - case LegalizationAction::Libcall: case LegalizationAction::MoreElements: case LegalizationAction::FewerElements: case LegalizationAction::Bitcast: diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index 62b77f0..a8d0a20 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -2,6 +2,7 @@ #include "rcc/Target/RISCV/RISCVPipeline.h" +#include "GISel/RISCVCallLowering.h" #include "GISel/RISCVRegisterBankInfo.h" #include "RISCV.h" #include "RISCVInstrInfo.h" @@ -26,6 +27,10 @@ namespace rcc::riscv { namespace { +[[nodiscard]] LibcallLoweringInfo libcallLoweringInfo(const RISCVSubtarget &Subtarget) { + return {Subtarget.getCallLowering(), callingConventionID(CallingConvention::LP64)}; +} + template <typename PassT, typename... ArgumentT> [[nodiscard]] Expected<void> addPass(MachineFunctionPassManager &Pipeline, ArgumentT &&...Arguments) { @@ -39,7 +44,8 @@ template <typename PassT, typename... ArgumentT> MachineCombinerStage::PreLegalizer); if (!Added) return std::unexpected(Added.error()); - Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization); + Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization, + libcallLoweringInfo(Subtarget)); if (!Added) return std::unexpected(Added.error()); Added = addPass<RegBankSelect>(Pipeline, Subtarget.getRegBankInfo()); @@ -93,7 +99,8 @@ Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline, MachineCombinerStage::PreLegalizer); if (!Added) return std::unexpected(Added.error()); - Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization); + Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization, + libcallLoweringInfo(Subtarget)); if (!Added) return std::unexpected(Added.error()); } |
