From 4fe5ee649927d54d6fb74904d7b97ad0f63fd587 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Tue, 11 Aug 2026 17:38:11 +0800 Subject: [RISCV] Legalize fixed-baseline RV64 MachineIR --- backend/lib/CodeGen/GenericOpcodes.cpp | 30 +++++++---- backend/lib/CodeGen/MachinePipelinePasses.cpp | 72 +++++++++++++++++++++------ 2 files changed, 76 insertions(+), 26 deletions(-) (limited to 'backend/lib/CodeGen') diff --git a/backend/lib/CodeGen/GenericOpcodes.cpp b/backend/lib/CodeGen/GenericOpcodes.cpp index 1394507..0ffb26a 100644 --- a/backend/lib/CodeGen/GenericOpcodes.cpp +++ b/backend/lib/CodeGen/GenericOpcodes.cpp @@ -47,6 +47,10 @@ using GO = GenericOpcode; return {LLT::Kind::AnyScalar, LLT::Kind::Integer}; } +[[nodiscard]] LLTKindSet scalarIntegerOrPointerKinds() { + return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Pointer}; +} + [[nodiscard]] LLTKindSet scalarValueKinds() { return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Float, LLT::Kind::Pointer}; } @@ -278,10 +282,6 @@ private: Left.minimumElementCount() == Right.minimumElementCount(); } -[[nodiscard]] bool isI1(LLT Type) noexcept { - return Type.isIntegerOrIntegerVector() && Type.scalarBitWidth() == 1; -} - [[nodiscard]] Expected requireSameShape(LLT Left, LLT Right, std::string_view Message) { if (!hasSameShape(Left, Right)) return semanticError(Message); @@ -290,8 +290,10 @@ private: [[nodiscard]] Expected requireI1WithShape(LLT Condition, LLT Value, bool AllowScalarCondition) { - if (!isI1(Condition)) - return semanticError("generic condition or status result must use an i1 LLT"); + const bool IsScalarInteger = Condition.isAnyScalar() || Condition.isInteger(); + const bool IsVectorInteger = Condition.isAnyVector() || Condition.isIntegerVector(); + if ((!IsScalarInteger && !IsVectorInteger) || Condition.scalarBitWidth() == 0) + return semanticError("generic condition or status result must use an integer LLT"); if (AllowScalarCondition && !Condition.isVector()) return {}; return requireSameShape(Condition, Value, @@ -388,8 +390,15 @@ private: } case GO::G_FCONSTANT: { const auto *Payload = Operands[1].getIf(); - if (Payload == nullptr || Payload->Bits.semantics() != TypeAt(0).floatSemantics()) + if (Payload == nullptr) + return semanticError("G_FCONSTANT requires a floating-point immediate"); + const LLT DestinationType = TypeAt(0); + const std::optional DestinationSemantics = + DestinationType.floatSemantics(); + if ((DestinationSemantics && Payload->Bits.semantics() != *DestinationSemantics) || + (!DestinationSemantics && Payload->Bits.bitWidth() != DestinationType.scalarBitWidth())) { return semanticError("G_FCONSTANT semantics must match its destination LLT"); + } return {}; } case GO::G_BITCAST: { @@ -695,8 +704,8 @@ private: return semanticError("generic bit-field extraction only supports scalar operands"); return {}; case GO::G_BRCOND: - if (!isI1(TypeAt(0)) || TypeAt(0).isVector()) - return semanticError("G_BRCOND condition must be a scalar i1 virtual register"); + if (!TypeAt(0).isScalarValue()) + return semanticError("G_BRCOND condition must be a scalar value"); return {}; case GO::G_BRJT: if (TypeAt(0).isVector() || TypeAt(2).isVector()) @@ -1130,6 +1139,7 @@ void configureGenericOpcodes(DescriptorRegistry &Registry) { const LLTKindSet IntTypes = integerKinds(); const LLTKindSet ScalarValues = scalarValueKinds(); const LLTKindSet ScalarInts = scalarIntegerKinds(); + const LLTKindSet ScalarIntegerOrPointers = scalarIntegerOrPointerKinds(); const LLTKindSet FloatTypes = floatingKinds(); const LLTKindSet ScalarFloats = scalarFloatingKinds(); const LLTKindSet PointerTypes = pointerKinds(); @@ -1290,7 +1300,7 @@ void configureGenericOpcodes(DescriptorRegistry &Registry) { {IntDef0, IntUse1}, 1); Registry.configure( {GO::G_CONSTANT}, - {typedRegister(RegisterOperandRole::Def, ScalarInts, 0), + {typedRegister(RegisterOperandRole::Def, ScalarIntegerOrPointers, 0), operand({MachineOperand::Kind::Immediate, MachineOperand::Kind::IntegerImmediate})}, 1); Registry.configure({GO::G_FCONSTANT}, diff --git a/backend/lib/CodeGen/MachinePipelinePasses.cpp b/backend/lib/CodeGen/MachinePipelinePasses.cpp index c7c5dc3..9c42bdb 100644 --- a/backend/lib/CodeGen/MachinePipelinePasses.cpp +++ b/backend/lib/CodeGen/MachinePipelinePasses.cpp @@ -25,7 +25,9 @@ namespace { [[nodiscard]] const MachinePassContract &legalizerContract() { static const MachinePassContract Contract{ .Name = "Legalizer", - .Requires = {MachineFunctionProperty::IsSSA, MachineFunctionProperty::TracksLiveness}, + // LLVM's GlobalISel legalizer operates on SSA form and does not require + // the optional register-liveness tracking property. + .Requires = {MachineFunctionProperty::IsSSA}, .Sets = {MachineFunctionProperty::Legalized}, .Clears = {}, .RequiredAnalyses = {}, @@ -277,6 +279,34 @@ registerConfigurationFingerprint(const MachineRegisterInfo &RegInfo) noexcept { return {}; } +[[nodiscard]] Expected clearTrackedLivenessFlags(MachineFunction &Function, + MachinePassResult &Result) { + if (!Result.Changed || + !Function.properties().has(MachineFunctionProperty::TracksLiveness)) + return {}; + bool Changed = false; + for (MachineInstr *Instruction : layoutInstructions(Function)) { + for (std::size_t Index = 0; Index < Instruction->operandCount(); ++Index) { + MachineOperand &Operand = *Instruction->operandAt(Index); + if (!Operand.isRegister()) + continue; + RegisterOperandFlags Flags = Operand.registerFlags(); + if (!Flags.has(RegisterOperandFlag::Kill) && + !Flags.has(RegisterOperandFlag::Dead)) + continue; + Flags.clear(RegisterOperandFlag::Kill); + Flags.clear(RegisterOperandFlag::Dead); + auto Updated = Operand.setRegisterFlags(Flags); + if (!Updated) + return std::unexpected(Updated.error()); + Changed = true; + } + } + if (Changed) + Result.Changes.add(MachinePassChange::Operands); + return {}; +} + } // namespace const MachinePassContract &LegalizerPass::contract() const noexcept { @@ -377,22 +407,26 @@ Expected LegalizerPass::runImplementation(MachineFunction &Fu auto Lowered = Info->lower(*Instruction, Function, Target, *Action); if (!Lowered) return std::unexpected(Lowered.error()); - if (Instruction->parent() == nullptr) - return std::unexpected(passFailure("legalizer detached the instruction it was lowering")); - const OpcodeState After = stateOf(*Instruction); - if (After == Before) - return std::unexpected( - passFailure("target legalizer made no observable progress for '" + Descriptor->Name + "'", - ErrorCode::InternalError)); + const bool InstructionWasErased = Instruction->parent() == nullptr; + if (!InstructionWasErased) { + const OpcodeState After = stateOf(*Instruction); + if (After == Before) + return std::unexpected(passFailure( + "target legalizer made no observable progress for '" + Descriptor->Name + "'", + ErrorCode::InternalError)); + } Result.Changed = true; Result.Changes.add(MachinePassChange::Instructions); - const InstructionDescriptor *LoweredDescriptor = - Target.instructionDescriptor(Instruction->opcode()); - if (LoweredDescriptor == nullptr) - return std::unexpected(passFailure("legalizer produced an unknown instruction descriptor")); - if (LoweredDescriptor->Flags.has(InstructionFlag::Generic)) - Worklist.push_back(Instruction); + if (!InstructionWasErased) { + const InstructionDescriptor *LoweredDescriptor = + Target.instructionDescriptor(Instruction->opcode()); + if (LoweredDescriptor == nullptr) + return std::unexpected( + passFailure("legalizer produced an unknown instruction descriptor")); + if (LoweredDescriptor->Flags.has(InstructionFlag::Generic)) + Worklist.push_back(Instruction); + } const std::vector Current = layoutInstructions(Function); for (MachineInstr *Candidate : Current) { if (DiscoveredInstructions.insert(Candidate->stableID()).second) @@ -420,9 +454,10 @@ Expected LegalizerPass::runImplementation(MachineFunction &Fu return std::unexpected( prefixedError(FinalValidation.error(), "legalizer produced invalid MachineIR: ")); } - auto Liveness = repairTrackedLiveness(Function, Target, Result); + auto Liveness = clearTrackedLivenessFlags(Function, Result); if (!Liveness) - return std::unexpected(prefixedError(Liveness.error(), "legalizer liveness repair failed: ")); + return std::unexpected( + prefixedError(Liveness.error(), "legalizer liveness-flag invalidation failed: ")); Result.Preserved = Result.Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); return Result; } @@ -647,6 +682,11 @@ InstructionSelectPass::runImplementation(MachineFunction &Function, const Target if (Selected == nullptr) return std::unexpected( passFailure("instruction selector produced an unknown instruction descriptor")); + auto Constraint = Info->constrainSelectedInstruction(*Instruction, Function, Target); + if (!Constraint) { + return std::unexpected(prefixedError( + Constraint.error(), "instruction selector could not constrain selected registers: ")); + } auto Validation = Target.validateInstruction(*Instruction, Function.registerInfo()); if (!Validation) return std::unexpected( -- cgit v1.2.3