diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-12 01:07:48 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-12 01:07:48 +0800 |
| commit | 7819df7189a54fa5b8df657d10285f1873628d25 (patch) | |
| tree | d2f3d851aa00656e20df861a6f29e6423eeca944 /backend | |
| parent | deb6a9e08397083a8d23cac4cfba94345419b443 (diff) | |
| download | rcc-project-7819df7189a54fa5b8df657d10285f1873628d25.tar.gz rcc-project-7819df7189a54fa5b8df657d10285f1873628d25.tar.xz | |
[RISCV] Model FFLAGS accesses
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/lib/CodeGen/PostRAScheduler.cpp | 11 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCV.rccdesc | 39 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp | 51 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVLateCodeGenTest.cpp | 20 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVTargetTest.cpp | 15 |
5 files changed, 129 insertions, 7 deletions
diff --git a/backend/lib/CodeGen/PostRAScheduler.cpp b/backend/lib/CodeGen/PostRAScheduler.cpp index 026f763..204f05e 100644 --- a/backend/lib/CodeGen/PostRAScheduler.cpp +++ b/backend/lib/CodeGen/PostRAScheduler.cpp @@ -130,6 +130,13 @@ void removeUnits(RegisterUnitLaneSet &Live, const std::vector<PhysicalUnitAccess Live.remove(Unit.Unit, Unit.Lanes); } +[[nodiscard]] bool isReservedPhysicalRegister(Register Reg, const MachineFunction &Function, + const TargetDescription &Target) noexcept { + const std::optional<PhysicalRegister> Physical = Reg.physicalRegister(); + return Physical && (Function.registerInfo().isReserved(*Physical) || + Target.registers().isReservedRegister(*Physical)); +} + [[nodiscard]] OperandFlagUpdate &getFlagUpdate(std::vector<OperandFlagUpdate> &Updates, MachineOperand &Operand) { const auto Position = std::ranges::find_if( @@ -175,7 +182,7 @@ buildBlockLivenessRepairPlan(MachineBasicBlock &Block, const TargetDescription & auto Units = physicalOperandUnits(*Operand, Target); if (!Units) return std::unexpected(Units.error()); - if (!intersects(Live, *Units)) + if (!isReservedPhysicalRegister(*Reg, Block.function(), Target) && !intersects(Live, *Units)) Update.Flags.set(RegisterOperandFlag::Dead); } @@ -218,6 +225,8 @@ buildBlockLivenessRepairPlan(MachineBasicBlock &Block, const TargetDescription & const Register *Reg = Operand->getIf<Register>(); if (Reg == nullptr || Reg->isNoRegister()) continue; + if (isReservedPhysicalRegister(*Reg, Block.function(), Target)) + continue; auto Units = physicalOperandUnits(*Operand, Target); if (!Units) return std::unexpected(Units.error()); diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index 9943724..c589424 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -75,6 +75,7 @@ register_units: - { id: 62, symbol: U_F29, name: f29.unit } - { id: 63, symbol: U_F30, name: f30.unit } - { id: 64, symbol: U_F31, name: f31.unit } + - { id: 65, symbol: U_FFLAGS, name: fflags.unit } registers: - { id: 1, symbol: X0, name: x0, encoding: 0, dwarf_register: 0, units: [{ unit: U_X0, lanes: 1 }], constant: true, reserved: true, aliases: [zero] } @@ -173,10 +174,12 @@ registers: - { id: 94, symbol: F29_F, name: f29_f, encoding: 29, dwarf_register: 61, units: [{ unit: U_F29, lanes: 1 }] } - { id: 95, symbol: F30_F, name: f30_f, encoding: 30, dwarf_register: 62, units: [{ unit: U_F30, lanes: 1 }] } - { id: 96, symbol: F31_F, name: f31_f, encoding: 31, dwarf_register: 63, units: [{ unit: U_F31, lanes: 1 }] } + - { id: 97, symbol: FFLAGS, name: fflags, encoding: 0, dwarf_register: 65, units: [{ unit: U_FFLAGS, lanes: 1 }], artificial: true, reserved: true } register_banks: - { id: 1, symbol: GPR, name: GPRB, maximum_size_bits: 64 } - { id: 2, symbol: FPR, name: FPRB, maximum_size_bits: 64 } + - { id: 3, symbol: CSR, name: CSRB, maximum_size_bits: 32 } register_classes: - @@ -267,6 +270,18 @@ register_classes: lanes: 1 registers: [X1, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31] allocation_order: [X5, X6, X7, X28, X29, X30, X31, X10, X11, X12, X13, X14, X15, X16, X17, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X1] + - + id: 9 + symbol: FFLAGS + name: FFLAGS + bank: CSR + size_bits: 32 + spill_size_bits: 32 + spill_alignment_bits: 32 + lanes: 1 + registers: [FFLAGS] + allocation_order: [] + allocatable: false register_masks: - @@ -1007,6 +1022,7 @@ instructions: - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } num_explicit_defs: 1 + allow_extra_implicit_operands: true flags: [has_side_effects, produces_code] scheduling_class: SYSTEM encoding_category: SYSTEM @@ -1022,6 +1038,7 @@ instructions: - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } num_explicit_defs: 1 + allow_extra_implicit_operands: true flags: [has_side_effects, produces_code] scheduling_class: SYSTEM encoding_category: SYSTEM @@ -3520,6 +3537,28 @@ instructions: owner: instruction_select deadline: selected - + id: 1245 + symbol: ReadFFLAGS + name: ReadFFLAGS + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR } + num_explicit_defs: 1 + implicit_uses: [{ register: FFLAGS }] + flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects] + owner: post_ra_expansion + deadline: post_ra_finalized + - + id: 1246 + symbol: WriteFFLAGS + name: WriteFFLAGS + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR } + num_explicit_defs: 0 + implicit_defs: [{ register: FFLAGS }] + flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects] + owner: post_ra_expansion + deadline: post_ra_finalized + - id: 1216 symbol: PseudoCC_COPY name: PseudoCC_COPY diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp index ae5e51d..d0de28e 100644 --- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp +++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp @@ -334,6 +334,53 @@ copyRegisters(const MachineInstr &Instruction) { return {}; } +[[nodiscard]] Expected<bool> expandFFLAGSAccess(MachineInstr &Instruction, + MachineFunction &Function, + const TargetDescription &Target, bool IsRead) { + const MachineOperand *ValueOperand = Instruction.operandAt(0); + const Register *Value = ValueOperand == nullptr ? nullptr : ValueOperand->getIf<Register>(); + if (Value == nullptr || !Value->isPhysical()) { + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V FFLAGS pseudo retains a nonphysical value register"); + } + auto Zero = physical(PhysicalRegisterID::X0); + if (!Zero) + return std::unexpected(Zero.error()); + + MachineIRBuilder Builder(Function, Target); + auto Point = Builder.setInsertPointBefore(Instruction); + if (!Point) + return std::unexpected(Point.error()); + auto Pending = Builder.buildInstr( + targetOpcode(IsRead ? InstructionOpcode::CSRRS : InstructionOpcode::CSRRW)); + if (!Pending) + return std::unexpected(Pending.error()); + Expected<void> Added = IsRead ? Pending->addOperand(ValueOperand->cloneDetached()) + : Pending->addDef(Register::fromPhysical(*Zero)); + if (!Added) + return std::unexpected(Added.error()); + Added = Pending->addImmediate(1); + if (!Added) + return std::unexpected(Added.error()); + Added = IsRead ? Pending->addUse(Register::fromPhysical(*Zero)) + : Pending->addOperand(ValueOperand->cloneDetached()); + if (!Added) + return std::unexpected(Added.error()); + auto Implicit = copyExtraImplicitOperands(Instruction, 1, *Pending, std::nullopt, std::nullopt); + if (!Implicit) + return std::unexpected(Implicit.error()); + auto Replacement = Pending->build(); + if (!Replacement) + return std::unexpected(Replacement.error()); + auto Decoration = copyCommonDecoration(Instruction, **Replacement, true, true, true); + if (!Decoration) + return std::unexpected(Decoration.error()); + auto Removed = removeOldInstruction(Instruction); + if (!Removed) + return std::unexpected(Removed.error()); + return true; +} + [[nodiscard]] Expected<bool> expandCall(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, bool IsTail) { MachineBasicBlock *Block = Instruction.parent(); @@ -534,6 +581,10 @@ public: return expandReturn(Instruction, Function, Target); if (Instruction.opcode() == targetOpcode(InstructionOpcode::PseudoBR)) return expandBranch(Instruction, Function, Target); + if (Instruction.opcode() == targetOpcode(InstructionOpcode::ReadFFLAGS)) + return expandFFLAGSAccess(Instruction, Function, Target, true); + if (Instruction.opcode() == targetOpcode(InstructionOpcode::WriteFFLAGS)) + return expandFFLAGSAccess(Instruction, Function, Target, false); return false; } }; diff --git a/backend/unittests/Target/RISCVLateCodeGenTest.cpp b/backend/unittests/Target/RISCVLateCodeGenTest.cpp index e8ac9de..4b11140 100644 --- a/backend/unittests/Target/RISCVLateCodeGenTest.cpp +++ b/backend/unittests/Target/RISCVLateCodeGenTest.cpp @@ -1129,6 +1129,18 @@ void testPostRAPseudoExpansionAndFinalization(TestContext &Context, Context.expect(false, "post-RA cross-bank copy construction must succeed"); return; } + auto ReadFFLAGS = Builder.buildInstr(opcode(rcc::riscv::InstructionOpcode::ReadFFLAGS)); + if (!ReadFFLAGS || !ReadFFLAGS->addDef(physical(rcc::riscv::PhysicalRegisterID::X12)) || + !ReadFFLAGS->build()) { + Context.expect(false, "ReadFFLAGS pseudo construction must succeed"); + return; + } + auto WriteFFLAGS = Builder.buildInstr(opcode(rcc::riscv::InstructionOpcode::WriteFFLAGS)); + if (!WriteFFLAGS || !WriteFFLAGS->addUse(physical(rcc::riscv::PhysicalRegisterID::X12)) || + !WriteFFLAGS->build()) { + Context.expect(false, "WriteFFLAGS pseudo construction must succeed"); + return; + } auto Call = Builder.buildInstr(opcode(rcc::riscv::InstructionOpcode::PseudoCALL)); auto Preserved = rcc::riscv::createCallPreservedMask(rcc::riscv::CallingConvention::LP64D); if (!Call || !Call->addExternalSymbol("callee", 0, 1) || !Call->addRegisterMask(Preserved) || @@ -1154,16 +1166,20 @@ void testPostRAPseudoExpansionAndFinalization(TestContext &Context, std::size_t CrossMoveCount = 0; std::size_t CallCount = 0; std::size_t ReturnCount = 0; + std::size_t CSRRSCount = 0; + std::size_t CSRRWCount = 0; for (rcc::MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; Instruction = Instruction->next()) { ADDICount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::ADDI); CrossMoveCount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::FMV_D_X); CallCount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::JALR_CALL); ReturnCount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::JALR_RET); + CSRRSCount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::CSRRS); + CSRRWCount += Instruction->opcode() == opcode(rcc::riscv::InstructionOpcode::CSRRW); } Context.expect(Expanded && Expanded->Changed && ADDICount == 1 && CrossMoveCount == 1 && - CallCount == 1 && ReturnCount == 1, - "post-RA expansion must lower copies, calls, and returns to real RV64GC code"); + CallCount == 1 && ReturnCount == 1 && CSRRSCount == 1 && CSRRWCount == 1, + "post-RA expansion must lower copies, calls, returns, and FFLAGS accesses"); if (!Expanded) return; diff --git a/backend/unittests/Target/RISCVTargetTest.cpp b/backend/unittests/Target/RISCVTargetTest.cpp index 680d606..b4b3648 100644 --- a/backend/unittests/Target/RISCVTargetTest.cpp +++ b/backend/unittests/Target/RISCVTargetTest.cpp @@ -49,11 +49,12 @@ void testRegisterFacts(TestContext &Context) { const rcc::PhysicalRegister X8 = registerID(rcc::riscv::PhysicalRegisterID::X8); const rcc::PhysicalRegister F31D = registerID(rcc::riscv::PhysicalRegisterID::F31_D); const rcc::PhysicalRegister F31F = registerID(rcc::riscv::PhysicalRegisterID::F31_F); + const rcc::PhysicalRegister FFLAGS = registerID(rcc::riscv::PhysicalRegisterID::FFLAGS); Context.expect( - Registers->physicalRegisters().size() == 96 && Registers->registerUnits().size() == 64 && - Registers->registerClasses().size() == 8 && Registers->registerBanks().size() == 2, - "RV64GC must expose the complete scalar, compressed, and restricted register classes"); + Registers->physicalRegisters().size() == 97 && Registers->registerUnits().size() == 65 && + Registers->registerClasses().size() == 9 && Registers->registerBanks().size() == 3, + "RV64GC must expose scalar, compressed, restricted, and status register classes"); Context.expect(Registers->physicalRegister("x0") != nullptr && Registers->physicalRegister("zero") == nullptr && Registers->physicalRegisterByAlternativeName("ZERO") != nullptr && @@ -77,6 +78,12 @@ void testRegisterFacts(TestContext &Context) { Registers->regsOverlap(F31D, F31F) && Registers->subRegister(F31D, rcc::SubRegIndex::fromValue(1)) == F31F, "FPR32 and FPR64 MIR views must retain encoding, overlap, and subregister facts"); + Context.expect(Registers->physicalRegister("fflags") != nullptr && + Registers->physicalRegister("fflags")->Reg == FFLAGS && + Registers->isReservedRegister(FFLAGS) && + Registers->registerClass("fflags") != nullptr && + !Registers->registerClass("fflags")->Allocatable, + "FFLAGS must be a reserved nonallocatable status register"); const auto *GPR = Registers->registerClass("gpr"); Context.expect( @@ -149,7 +156,7 @@ void testABIAndDebugFacts(TestContext &Context) { void testInstructionFacts(TestContext &Context) { constexpr std::size_t TargetInstructionCount = - static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::Select_GPR_Using_CC_GPR) - + static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::WriteFFLAGS) - static_cast<std::uint32_t>(rcc::riscv::InstructionOpcode::LUI) + 1U; auto Target = rcc::riscv::createTargetDescription(); Context.expect(Target.has_value(), "RV64GC target description must be structurally valid"); |
