aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/CodeGen
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 17:38:11 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 17:38:11 +0800
commit4fe5ee649927d54d6fb74904d7b97ad0f63fd587 (patch)
tree75f85f5e6cae3a871fe42d025dca04eeb7c31cfd /backend/lib/CodeGen
parent6a7b083f322f4ac47e58cbf9d4d5fd4d1f6fecd0 (diff)
downloadrcc-project-4fe5ee649927d54d6fb74904d7b97ad0f63fd587.tar.gz
rcc-project-4fe5ee649927d54d6fb74904d7b97ad0f63fd587.tar.xz
[RISCV] Legalize fixed-baseline RV64 MachineIR
Diffstat (limited to 'backend/lib/CodeGen')
-rw-r--r--backend/lib/CodeGen/GenericOpcodes.cpp30
-rw-r--r--backend/lib/CodeGen/MachinePipelinePasses.cpp72
2 files changed, 76 insertions, 26 deletions
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<void> requireSameShape(LLT Left, LLT Right, std::string_view Message) {
if (!hasSameShape(Left, Right))
return semanticError(Message);
@@ -290,8 +290,10 @@ private:
[[nodiscard]] Expected<void> 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<FloatingImmediateOperand>();
- 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<FloatSemantics> 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<void> 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<MachinePassResult> 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<MachineInstr *> Current = layoutInstructions(Function);
for (MachineInstr *Candidate : Current) {
if (DiscoveredInstructions.insert(Candidate->stableID()).second)
@@ -420,9 +454,10 @@ Expected<MachinePassResult> 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(