aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/include/rcc/TableGen/Record.h15
-rw-r--r--backend/lib/TableGen/Parser.cpp69
-rw-r--r--backend/lib/Target/RISCV/CMakeLists.txt10
-rw-r--r--backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc30
-rw-r--r--backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc35
-rw-r--r--backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp9
-rw-r--r--backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp187
-rw-r--r--backend/utils/TableGen/CMakeLists.txt2
-rw-r--r--backend/utils/TableGen/Common/CodeGenInstruction.cpp9
-rw-r--r--backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp121
-rw-r--r--backend/utils/TableGen/Common/CodeGenTarget.cpp3
-rw-r--r--backend/utils/TableGen/Common/CodeGenTarget.h20
-rw-r--r--backend/utils/TableGen/MCPseudoLoweringEmitter.cpp69
-rw-r--r--backend/utils/TableGen/TableGenBackends.h3
-rw-r--r--backend/utils/TableGen/rcc-tblgen.cpp17
15 files changed, 392 insertions, 207 deletions
diff --git a/backend/include/rcc/TableGen/Record.h b/backend/include/rcc/TableGen/Record.h
index 9ebfb7f..f3c7d12 100644
--- a/backend/include/rcc/TableGen/Record.h
+++ b/backend/include/rcc/TableGen/Record.h
@@ -189,6 +189,20 @@ struct SourceMacroFusionRule final {
TextRange Range;
};
+struct SourceMCPseudoOperand final {
+ std::optional<std::uint32_t> SourceOperandIndex;
+ std::string RegisterSymbol;
+ std::optional<std::int64_t> Immediate;
+ TextRange Range;
+};
+
+struct SourceMCPseudoExpansion final {
+ std::string PseudoOpcodeSymbol;
+ std::string ResultOpcodeSymbol;
+ std::vector<SourceMCPseudoOperand> Operands;
+ TextRange Range;
+};
+
struct SourceEncodingCategory final {
std::uint32_t ID = 0;
std::string Symbol;
@@ -441,6 +455,7 @@ struct DescriptionAST final {
std::vector<SourceSelectionRule> SelectionRules;
std::vector<SourceCombinerRule> CombinerRules;
std::vector<SourceMacroFusionRule> MacroFusionRules;
+ std::vector<SourceMCPseudoExpansion> MCPseudoExpansions;
};
[[nodiscard]] std::string lowerASCII(std::string_view Value);
diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp
index c383aed..67c7a43 100644
--- a/backend/lib/TableGen/Parser.cpp
+++ b/backend/lib/TableGen/Parser.cpp
@@ -41,7 +41,7 @@ public:
"register_classes", "register_masks", "mir_operand_flags", "named_operands",
"immediate_predicates", "scheduling_classes", "encoding_categories",
"assembly_formats", "calling_conventions", "instructions", "selection_rules",
- "combiner_rules", "macro_fusion_rules"},
+ "combiner_rules", "macro_fusion_rules", "mc_pseudo_expansions"},
"target description root")) {
return std::nullopt;
}
@@ -84,6 +84,7 @@ public:
const yaml::Node *SelectionRulesNode = optionalNode(*Root, "selection_rules");
const yaml::Node *CombinerRulesNode = optionalNode(*Root, "combiner_rules");
const yaml::Node *MacroFusionRulesNode = optionalNode(*Root, "macro_fusion_rules");
+ const yaml::Node *MCPseudoExpansionsNode = optionalNode(*Root, "mc_pseudo_expansions");
if (UnitsNode == nullptr || RegistersNode == nullptr || BanksNode == nullptr ||
ClassesNode == nullptr || MasksNode == nullptr || NamedOperandsNode == nullptr ||
ImmediatePredicatesNode == nullptr || SchedulingClassesNode == nullptr ||
@@ -108,7 +109,9 @@ public:
(CombinerRulesNode != nullptr &&
!parseCombinerRules(*CombinerRulesNode, Result.CombinerRules)) ||
(MacroFusionRulesNode != nullptr &&
- !parseMacroFusionRules(*MacroFusionRulesNode, Result.MacroFusionRules))) {
+ !parseMacroFusionRules(*MacroFusionRulesNode, Result.MacroFusionRules)) ||
+ (MCPseudoExpansionsNode != nullptr &&
+ !parseMCPseudoExpansions(*MCPseudoExpansionsNode, Result.MCPseudoExpansions))) {
return std::nullopt;
}
return Result;
@@ -2099,6 +2102,68 @@ private:
return true;
}
+ [[nodiscard]] bool parseMCPseudoOperands(const yaml::Node &Node,
+ std::vector<SourceMCPseudoOperand> &Result) {
+ if (!requireSequence(&Node, "MC pseudo expansion operands"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (!requireMapping(Element, "MC pseudo expansion operand") ||
+ !checkKeys(*Element, {"operand", "register", "immediate"},
+ "MC pseudo expansion operand")) {
+ return false;
+ }
+ SourceMCPseudoOperand Operand;
+ Operand.Range = Element->range();
+ if (const yaml::Node *SourceNode = optionalNode(*Element, "operand")) {
+ const auto Source = unsignedInteger32(*SourceNode, "MC pseudo source operand");
+ if (!Source)
+ return false;
+ Operand.SourceOperandIndex = *Source;
+ }
+ if (const yaml::Node *RegisterNode = optionalNode(*Element, "register")) {
+ const auto Register = scalar(*RegisterNode, "MC pseudo fixed register");
+ if (!Register)
+ return false;
+ Operand.RegisterSymbol = *Register;
+ }
+ if (const yaml::Node *ImmediateNode = optionalNode(*Element, "immediate")) {
+ const auto Immediate = signedInteger(*ImmediateNode, "MC pseudo fixed immediate");
+ if (!Immediate)
+ return false;
+ Operand.Immediate = *Immediate;
+ }
+ Result.push_back(std::move(Operand));
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool parseMCPseudoExpansions(const yaml::Node &Node,
+ std::vector<SourceMCPseudoExpansion> &Result) {
+ if (!requireSequence(&Node, "mc_pseudo_expansions"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (!requireMapping(Element, "MC pseudo expansion") ||
+ !checkKeys(*Element, {"pseudo", "opcode", "operands"}, "MC pseudo expansion")) {
+ return false;
+ }
+ const auto Pseudo = requiredScalar(*Element, "pseudo", "MC pseudo expansion");
+ const auto Opcode = requiredScalar(*Element, "opcode", "MC pseudo expansion");
+ const yaml::Node *OperandsNode = requiredNode(*Element, "operands", "MC pseudo expansion");
+ if (!Pseudo || !Opcode || OperandsNode == nullptr)
+ return false;
+ SourceMCPseudoExpansion Expansion;
+ Expansion.PseudoOpcodeSymbol = *Pseudo;
+ Expansion.ResultOpcodeSymbol = *Opcode;
+ Expansion.Range = Element->range();
+ if (!parseMCPseudoOperands(*OperandsNode, Expansion.Operands))
+ return false;
+ Result.push_back(std::move(Expansion));
+ }
+ return true;
+ }
+
[[nodiscard]] bool parseInstructions(const yaml::Node &Node,
std::vector<SourceInstruction> &Result) {
if (!requireSequence(&Node, "instructions"))
diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt
index 00de7bd..dccced9 100644
--- a/backend/lib/Target/RISCV/CMakeLists.txt
+++ b/backend/lib/Target/RISCV/CMakeLists.txt
@@ -21,6 +21,7 @@ set(
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelFloating.rccdesc"
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelCombiner.rccdesc"
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVMacroFusion.rccdesc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/RISCVMCPseudoLowering.rccdesc"
)
set(RCCBackendRISCVTableGenArguments)
foreach(RCCBackendRISCVDescriptionSource IN LISTS RCCBackendRISCVDescriptionSources)
@@ -50,6 +51,10 @@ set(
RCCBackendRISCVGeneratedMacroFusion
"${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenMacroFusion.inc"
)
+set(
+ RCCBackendRISCVGeneratedMCPseudoLowering
+ "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenMCPseudoLowering.inc"
+)
add_custom_command(
OUTPUT
@@ -59,6 +64,7 @@ add_custom_command(
"${RCCBackendRISCVGeneratedGlobalISel}"
"${RCCBackendRISCVGeneratedGlobalISelCombiner}"
"${RCCBackendRISCVGeneratedMacroFusion}"
+ "${RCCBackendRISCVGeneratedMCPseudoLowering}"
COMMAND
"$<TARGET_FILE:RCCBackendTableGenTool>"
${RCCBackendRISCVTableGenArguments}
@@ -68,6 +74,7 @@ add_custom_command(
--global-isel "${RCCBackendRISCVGeneratedGlobalISel}"
--global-isel-combiner "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
--macro-fusion "${RCCBackendRISCVGeneratedMacroFusion}"
+ --mc-pseudo-lowering "${RCCBackendRISCVGeneratedMCPseudoLowering}"
DEPENDS RCCBackendTableGenTool ${RCCBackendRISCVDescriptionSources}
COMMENT "Generating RCC RV64GC target tables"
VERBATIM
@@ -82,6 +89,7 @@ add_custom_target(
"${RCCBackendRISCVGeneratedGlobalISel}"
"${RCCBackendRISCVGeneratedGlobalISelCombiner}"
"${RCCBackendRISCVGeneratedMacroFusion}"
+ "${RCCBackendRISCVGeneratedMCPseudoLowering}"
)
set_source_files_properties(
@@ -91,6 +99,7 @@ set_source_files_properties(
"${RCCBackendRISCVGeneratedGlobalISel}"
"${RCCBackendRISCVGeneratedGlobalISelCombiner}"
"${RCCBackendRISCVGeneratedMacroFusion}"
+ "${RCCBackendRISCVGeneratedMCPseudoLowering}"
PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE
)
@@ -127,6 +136,7 @@ add_library(
"${RCCBackendRISCVGeneratedGlobalISel}"
"${RCCBackendRISCVGeneratedGlobalISelCombiner}"
"${RCCBackendRISCVGeneratedMacroFusion}"
+ "${RCCBackendRISCVGeneratedMCPseudoLowering}"
)
add_library(RCCBackend::RISCV ALIAS RCCBackendRISCV)
add_dependencies(RCCBackendRISCV RCCBackendRISCVGeneratedTablesTarget)
diff --git a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
index 14bcf26..3e458df 100644
--- a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc
@@ -227,9 +227,9 @@ instructions:
- { 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
+ flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects, terminal_emission]
+ owner: asm_printer
+ deadline: emission
-
id: 1246
@@ -239,9 +239,9 @@ instructions:
- { 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
+ flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects, terminal_emission]
+ owner: asm_printer
+ deadline: emission
-
id: 1217
symbol: PseudoLOAD_STACK_ARG
@@ -342,10 +342,10 @@ instructions:
operands: []
num_explicit_defs: 0
allow_extra_implicit_operands: true
- flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, return, barrier]
+ flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, return, barrier, terminal_emission]
size: 4
- owner: post_ra_expansion
- deadline: post_ra_finalized
+ owner: asm_printer
+ deadline: emission
-
id: 1225
@@ -404,10 +404,10 @@ instructions:
operands:
- { kinds: [basic_block], name: TARGET }
num_explicit_defs: 0
- flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, barrier]
+ flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, barrier, terminal_emission]
size: 4
- owner: post_ra_expansion
- deadline: post_ra_finalized
+ owner: asm_printer
+ deadline: emission
-
id: 1267
symbol: PseudoLLA
@@ -441,7 +441,7 @@ instructions:
- { kinds: [register], role: use, register_class: GPRJALRNonX7, register_bank: GPR, name: RS1 }
- { kinds: [immediate], immediate_predicate: SIMM12, name: IMM }
num_explicit_defs: 0
- flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, indirect_branch, barrier]
+ flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, indirect_branch, barrier, terminal_emission]
size: 4
- owner: post_ra_expansion
- deadline: post_ra_finalized
+ owner: asm_printer
+ deadline: emission
diff --git a/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc b/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc
new file mode 100644
index 0000000..a505281
--- /dev/null
+++ b/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc
@@ -0,0 +1,35 @@
+mc_pseudo_expansions:
+ -
+ pseudo: PseudoBR
+ opcode: JAL
+ operands:
+ - { register: X0 }
+ - { operand: 0 }
+ -
+ pseudo: PseudoBRIND
+ opcode: JALR
+ operands:
+ - { register: X0 }
+ - { operand: 0 }
+ - { operand: 1 }
+ -
+ pseudo: PseudoRET
+ opcode: JALR
+ operands:
+ - { register: X0 }
+ - { register: X1 }
+ - { immediate: 0 }
+ -
+ pseudo: ReadFFLAGS
+ opcode: CSRRS
+ operands:
+ - { operand: 0 }
+ - { immediate: 1 }
+ - { register: X0 }
+ -
+ pseudo: WriteFFLAGS
+ opcode: CSRRW
+ operands:
+ - { register: X0 }
+ - { immediate: 1 }
+ - { operand: 0 }
diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
index 61cb587..85c06ad 100644
--- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
@@ -240,6 +240,10 @@ constexpr std::uint32_t KnownTargetFlags = CallTargetFlag | PCRelativeHighTarget
"RISC-V MC lowering encountered a non-encoding operand");
}
+#define GET_MC_PSEUDO_LOWERING
+#include "RISCVGenMCPseudoLowering.inc"
+#undef GET_MC_PSEUDO_LOWERING
+
[[nodiscard]] const AssemblyFormatInfo *assemblyFormat(AssemblyFormatID ID) noexcept {
const auto Formats = assemblyFormats();
const auto Position = std::ranges::find(Formats, ID, &AssemblyFormatInfo::ID);
@@ -866,6 +870,11 @@ Expected<mc::MCInst> RISCVMCTargetLowering::lowerInstruction(const MachineInstr
Expected<void> RISCVMCTargetLowering::emitTerminalInstruction(const MachineInstr &Instruction,
MachineMCContext &Context,
mc::MCStreamer &Streamer) const {
+ auto Pseudo = lowerGeneratedMCPseudo(Instruction, Context);
+ if (!Pseudo)
+ return std::unexpected(Pseudo.error());
+ if (*Pseudo)
+ return Streamer.emitInstruction(**Pseudo);
if (Instruction.opcode() != opcode(GenericOpcode::INLINEASM) &&
Instruction.opcode() != opcode(GenericOpcode::INLINEASM_BR)) {
return TargetMCInstLowering::emitTerminalInstruction(Instruction, Context, Streamer);
diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
index 257fa3a..19e52d9 100644
--- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
+++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp
@@ -243,7 +243,15 @@ copyRegisters(const MachineInstr &Instruction) {
auto Def = Pending->addDef(Destination);
if (!Def)
return std::unexpected(Def.error());
- auto Use = Pending->addUse(Source);
+ RegisterOperandFlags SourceFlags;
+ const RegisterOperandFlags OriginalSourceFlags = Instruction.operandAt(1)->registerFlags();
+ if (OriginalSourceFlags.has(RegisterOperandFlag::Kill))
+ SourceFlags.set(RegisterOperandFlag::Kill);
+ if (*DestinationBank == GPR && *SourceBank == GPR &&
+ OriginalSourceFlags.has(RegisterOperandFlag::Renamable)) {
+ SourceFlags.set(RegisterOperandFlag::Renamable);
+ }
+ auto Use = Pending->addUse(Source, SourceFlags);
if (!Use)
return std::unexpected(Use.error());
if (DuplicateSource) {
@@ -440,53 +448,6 @@ 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 = physicalRegister(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(
- instructionOpcode(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();
@@ -585,126 +546,6 @@ copyRegisters(const MachineInstr &Instruction) {
return true;
}
-[[nodiscard]] Expected<bool> expandReturn(MachineInstr &Instruction, MachineFunction &Function,
- const TargetDescription &Target) {
- auto Zero = physicalRegister(PhysicalRegisterID::X0);
- auto Link = physicalRegister(PhysicalRegisterID::X1);
- if (!Zero || !Link)
- return makeUnexpected(ErrorCode::InternalError, "RISC-V return registers are unavailable");
- MachineIRBuilder Builder(Function, Target);
- auto Point = Builder.setInsertPointBefore(Instruction);
- if (!Point)
- return std::unexpected(Point.error());
- auto Pending = Builder.buildInstr(instructionOpcode(InstructionOpcode::JALR_RET));
- if (!Pending)
- return std::unexpected(Pending.error());
- auto Def = Pending->addDef(Register::fromPhysical(*Zero));
- if (!Def)
- return std::unexpected(Def.error());
- auto Use = Pending->addUse(Register::fromPhysical(*Link));
- if (!Use)
- return std::unexpected(Use.error());
- auto Immediate = Pending->addImmediate(0);
- if (!Immediate)
- return std::unexpected(Immediate.error());
- auto Implicit = copyExtraImplicitOperands(Instruction, 0, *Pending, std::nullopt, *Link);
- 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> expandBranch(MachineInstr &Instruction, MachineFunction &Function,
- const TargetDescription &Target) {
- const MachineOperand *TargetOperand = Instruction.operandAt(0);
- const BasicBlockOperand *TargetBlock =
- TargetOperand == nullptr ? nullptr : TargetOperand->getIf<BasicBlockOperand>();
- if (TargetBlock == nullptr || TargetBlock->Block == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V PseudoBR has no basic-block target");
- }
-
- auto Zero = physicalRegister(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(instructionOpcode(InstructionOpcode::JAL));
- if (!Pending)
- return std::unexpected(Pending.error());
- auto Def = Pending->addDef(Register::fromPhysical(*Zero));
- if (!Def)
- return std::unexpected(Def.error());
- auto Destination = Pending->addBasicBlock(*TargetBlock->Block);
- if (!Destination)
- return std::unexpected(Destination.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> expandIndirectBranch(MachineInstr &Instruction,
- MachineFunction &Function,
- const TargetDescription &Target) {
- const MachineOperand *Address = Instruction.operandAt(0);
- const MachineOperand *Offset = Instruction.operandAt(1);
- if (Address == nullptr || Address->getIf<Register>() == nullptr || Offset == nullptr ||
- Offset->getIf<std::int64_t>() == nullptr) {
- return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V PseudoBRIND has malformed operands");
- }
-
- auto Zero = physicalRegister(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(instructionOpcode(InstructionOpcode::JALR));
- if (!Pending)
- return std::unexpected(Pending.error());
- auto Added = Pending->addDef(Register::fromPhysical(*Zero));
- if (!Added)
- return std::unexpected(Added.error());
- Added = Pending->addOperand(Address->cloneDetached());
- if (!Added)
- return std::unexpected(Added.error());
- Added = Pending->addOperand(Offset->cloneDetached());
- if (!Added)
- return std::unexpected(Added.error());
- auto Implicit = copyExtraImplicitOperands(Instruction, 2, *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;
-}
-
class RISCVPseudoExpansionInfo final : public TargetPseudoExpansionInfo {
public:
[[nodiscard]] Expected<bool> preparePostRAPseudo(MachineInstr &Instruction,
@@ -735,16 +576,6 @@ public:
return expandCall(Instruction, Function, Target, false);
if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoTAIL))
return expandCall(Instruction, Function, Target, true);
- if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoRET))
- return expandReturn(Instruction, Function, Target);
- if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoBR))
- return expandBranch(Instruction, Function, Target);
- if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoBRIND))
- return expandIndirectBranch(Instruction, Function, Target);
- if (Instruction.opcode() == instructionOpcode(InstructionOpcode::ReadFFLAGS))
- return expandFFLAGSAccess(Instruction, Function, Target, true);
- if (Instruction.opcode() == instructionOpcode(InstructionOpcode::WriteFFLAGS))
- return expandFFLAGSAccess(Instruction, Function, Target, false);
return false;
}
};
diff --git a/backend/utils/TableGen/CMakeLists.txt b/backend/utils/TableGen/CMakeLists.txt
index ff6f8c8..48c1632 100644
--- a/backend/utils/TableGen/CMakeLists.txt
+++ b/backend/utils/TableGen/CMakeLists.txt
@@ -8,8 +8,10 @@ set(
GlobalISelEmitter.cpp
GlobalISelCombinerEmitter.cpp
MacroFusionEmitter.cpp
+ MCPseudoLoweringEmitter.cpp
Common/CodeGenInstruction.cpp
Common/CodeGenMacroFusion.cpp
+ Common/CodeGenMCPseudoLowering.cpp
Common/CodeGenRegisters.cpp
Common/CodeGenSchedule.cpp
Common/CodeGenSelection.cpp
diff --git a/backend/utils/TableGen/Common/CodeGenInstruction.cpp b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
index 61c72a2..45b597c 100644
--- a/backend/utils/TableGen/Common/CodeGenInstruction.cpp
+++ b/backend/utils/TableGen/Common/CodeGenInstruction.cpp
@@ -388,13 +388,10 @@ CodeGenTarget::normalizeImplicitRegisters(const std::vector<SourceImplicitRegist
HasEncodingCategory || HasAssemblyFormat;
const bool IsPseudoSource =
std::ranges::find(Instruction.Flags, "pseudo") != Instruction.Flags.end();
- const bool IsTerminalEmissionSource =
- std::ranges::find(Instruction.Flags, "terminal_emission") != Instruction.Flags.end();
- if (HasAnyMachineFact != HasAllMachineFacts ||
- ((!IsPseudoSource || IsTerminalEmissionSource) && !HasAllMachineFacts)) {
+ if ((!IsPseudoSource && !HasAllMachineFacts) || HasAnyMachineFact != HasAllMachineFacts) {
fail(Instruction.Range,
- "encoded instructions and terminal-emission pseudos require complete scheduling, "
- "encoding, mnemonic, and assembly-format facts");
+ "encoded instructions require complete scheduling, encoding, mnemonic, and "
+ "assembly-format facts");
return false;
}
const auto SchedulingClass = SchedulingClassBySymbol.find(Instruction.SchedulingClassSymbol);
diff --git a/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp
new file mode 100644
index 0000000..49ec2a6
--- /dev/null
+++ b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "CodeGenTarget.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <ranges>
+#include <string_view>
+#include <unordered_set>
+
+namespace rcc::targetgen {
+namespace {
+
+[[nodiscard]] const NormalizedInstruction *findInstruction(const NormalizedTargetModel &Model,
+ std::string_view Symbol) noexcept {
+ const auto Position =
+ std::ranges::find(Model.Instructions, Symbol, &NormalizedInstruction::Symbol);
+ return Position == Model.Instructions.end() ? nullptr : &*Position;
+}
+
+[[nodiscard]] bool hasFlag(const NormalizedInstruction &Instruction,
+ std::string_view Flag) noexcept {
+ return std::ranges::contains(Instruction.Flags, Flag);
+}
+
+[[nodiscard]] bool hasCompatibleKind(const NormalizedOperand &Source,
+ const NormalizedOperand &Result) noexcept {
+ return std::ranges::any_of(Source.Kinds, [&Result](const std::string &Kind) {
+ return std::ranges::contains(Result.Kinds, Kind);
+ });
+}
+
+} // namespace
+
+bool CodeGenTarget::normalizeMCPseudoExpansions(NormalizedTargetModel &Result) {
+ std::unordered_set<std::uint32_t> PseudoOpcodes;
+ for (const SourceMCPseudoExpansion &Expansion : Input.MCPseudoExpansions) {
+ const NormalizedInstruction *Pseudo = findInstruction(Result, Expansion.PseudoOpcodeSymbol);
+ const NormalizedInstruction *ResultInstruction =
+ findInstruction(Result, Expansion.ResultOpcodeSymbol);
+ if (Pseudo == nullptr || ResultInstruction == nullptr ||
+ !PseudoOpcodes.insert(Pseudo == nullptr ? 0 : Pseudo->ID).second) {
+ fail(Expansion.Range,
+ "MC pseudo expansions require a unique declared pseudo and result instruction");
+ return false;
+ }
+ if (!hasFlag(*Pseudo, "Pseudo") || !hasFlag(*Pseudo, "TerminalEmission") ||
+ Pseudo->Owner != "AsmPrinter" || Pseudo->Deadline != "Emission" ||
+ hasFlag(*ResultInstruction, "Pseudo") || ResultInstruction->AssemblyMnemonic.empty()) {
+ fail(Expansion.Range,
+ "MC pseudo expansions require an AsmPrinter-owned terminal pseudo and encoded result");
+ return false;
+ }
+ if (Expansion.Operands.size() != ResultInstruction->Operands.size()) {
+ fail(Expansion.Range, "MC pseudo expansion operand count must match the result instruction");
+ return false;
+ }
+
+ NormalizedMCPseudoExpansion Normalized{
+ .PseudoOpcode = Pseudo->ID,
+ .ResultOpcode = ResultInstruction->ID,
+ .Operands = {},
+ };
+ Normalized.Operands.reserve(Expansion.Operands.size());
+ for (std::size_t Index = 0; Index < Expansion.Operands.size(); ++Index) {
+ const SourceMCPseudoOperand &Operand = Expansion.Operands[Index];
+ const unsigned SourceCount = static_cast<unsigned>(Operand.SourceOperandIndex.has_value()) +
+ static_cast<unsigned>(!Operand.RegisterSymbol.empty()) +
+ static_cast<unsigned>(Operand.Immediate.has_value());
+ if (SourceCount != 1) {
+ fail(Operand.Range,
+ "MC pseudo expansion operands require exactly one operand, register, or immediate");
+ return false;
+ }
+ const NormalizedOperand &ResultOperand = ResultInstruction->Operands[Index];
+ if (Operand.SourceOperandIndex) {
+ if (*Operand.SourceOperandIndex >= Pseudo->Operands.size() ||
+ !hasCompatibleKind(Pseudo->Operands[*Operand.SourceOperandIndex], ResultOperand)) {
+ fail(Operand.Range,
+ "MC pseudo source operand must exist and match the result operand kind");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::SourceOperand,
+ .Value = *Operand.SourceOperandIndex,
+ .Immediate = 0,
+ });
+ continue;
+ }
+ if (!Operand.RegisterSymbol.empty()) {
+ const auto Register = RegisterBySymbol.find(Operand.RegisterSymbol);
+ if (Register == RegisterBySymbol.end() ||
+ !std::ranges::contains(ResultOperand.Kinds, "Register")) {
+ fail(Operand.Range,
+ "MC pseudo fixed register must be declared and target a register operand");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::Register,
+ .Value = Register->second,
+ .Immediate = 0,
+ });
+ continue;
+ }
+ if (!std::ranges::contains(ResultOperand.Kinds, "Immediate")) {
+ fail(Operand.Range, "MC pseudo fixed immediate must target an immediate operand");
+ return false;
+ }
+ Normalized.Operands.push_back({
+ .Kind = NormalizedMCPseudoOperandKind::Immediate,
+ .Value = 0,
+ .Immediate = *Operand.Immediate,
+ });
+ }
+ Result.MCPseudoExpansions.push_back(std::move(Normalized));
+ }
+ std::ranges::sort(Result.MCPseudoExpansions, {}, &NormalizedMCPseudoExpansion::PseudoOpcode);
+ return true;
+}
+
+} // namespace rcc::targetgen
diff --git a/backend/utils/TableGen/Common/CodeGenTarget.cpp b/backend/utils/TableGen/Common/CodeGenTarget.cpp
index 9b96d2e..d4c9795 100644
--- a/backend/utils/TableGen/Common/CodeGenTarget.cpp
+++ b/backend/utils/TableGen/Common/CodeGenTarget.cpp
@@ -37,7 +37,7 @@ CodeGenTarget::CodeGenTarget(const DescriptionAST &Input, std::string SourceName
!normalizeSchedulingClasses(Result) || !normalizeEncodingCategories(Result) ||
!normalizeAssemblyFormats(Result) || !normalizeInstructions(Result) ||
!normalizeSelectionRules(Result) || !normalizeCombinerRules(Result) ||
- !normalizeMacroFusionRules(Result)) {
+ !normalizeMacroFusionRules(Result) || !normalizeMCPseudoExpansions(Result)) {
return std::nullopt;
}
std::ranges::sort(Result.RegisterUnits, {}, &SourceRegisterUnit::ID);
@@ -219,6 +219,7 @@ DescriptionGenerationResult generateDescription(const std::string &SourceName,
.GlobalISel = emitGlobalISel(*Model, DisplayName),
.GlobalISelCombiner = emitGlobalISelCombiner(*Model, DisplayName),
.MacroFusion = emitMacroFusion(*Model, DisplayName),
+ .MCPseudoLowering = emitMCPseudoLowering(*Model, DisplayName),
},
.Diagnostics = {},
};
diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h
index 6d3e185..43c7383 100644
--- a/backend/utils/TableGen/Common/CodeGenTarget.h
+++ b/backend/utils/TableGen/Common/CodeGenTarget.h
@@ -151,6 +151,24 @@ struct NormalizedMacroFusionRule final {
bool RequireSecondDestinationTie = false;
};
+enum class NormalizedMCPseudoOperandKind : std::uint8_t {
+ SourceOperand,
+ Register,
+ Immediate,
+};
+
+struct NormalizedMCPseudoOperand final {
+ NormalizedMCPseudoOperandKind Kind = NormalizedMCPseudoOperandKind::SourceOperand;
+ std::uint32_t Value = 0;
+ std::int64_t Immediate = 0;
+};
+
+struct NormalizedMCPseudoExpansion final {
+ std::uint32_t PseudoOpcode = 0;
+ std::uint32_t ResultOpcode = 0;
+ std::vector<NormalizedMCPseudoOperand> Operands;
+};
+
struct NormalizedEncodingCategory final {
std::uint32_t ID = 0;
std::string Symbol;
@@ -393,6 +411,7 @@ struct NormalizedTargetModel final {
std::vector<NormalizedSelectionRule> SelectionRules;
std::vector<NormalizedCombinerRule> CombinerRules;
std::vector<NormalizedMacroFusionRule> MacroFusionRules;
+ std::vector<NormalizedMCPseudoExpansion> MCPseudoExpansions;
};
[[nodiscard]] std::optional<std::string_view>
@@ -437,6 +456,7 @@ private:
[[nodiscard]] bool normalizeSelectionRules(NormalizedTargetModel &Result);
[[nodiscard]] bool normalizeCombinerRules(NormalizedTargetModel &Result);
[[nodiscard]] bool normalizeMacroFusionRules(NormalizedTargetModel &Result);
+ [[nodiscard]] bool normalizeMCPseudoExpansions(NormalizedTargetModel &Result);
const DescriptionAST &Input;
std::string SourceName;
diff --git a/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp b/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp
new file mode 100644
index 0000000..5afa911
--- /dev/null
+++ b/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "TableGenBackends.h"
+
+#include <cstddef>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <string_view>
+
+namespace rcc::targetgen {
+
+std::string emitMCPseudoLowering(const NormalizedTargetModel &Model, std::string_view SourceName) {
+ std::ostringstream Output;
+ Output << "// SPDX-License-Identifier: GPL-3.0-or-later\n\n";
+ Output << "// This file is generated by rcc-tblgen from ";
+ appendQuoted(Output, SourceName);
+ Output << ". Do not edit it manually.\n\n";
+ Output << "#ifdef GET_MC_PSEUDO_LOWERING\n\n";
+ Output << "[[nodiscard]] Expected<std::optional<mc::MCInst>>\n"
+ "lowerGeneratedMCPseudo(const MachineInstr &Instruction,\n"
+ " MachineMCContext &Context) {\n"
+ " switch (Instruction.opcode().value()) {\n"
+ " default:\n"
+ " return std::optional<mc::MCInst>{};\n";
+ for (const NormalizedMCPseudoExpansion &Expansion : Model.MCPseudoExpansions) {
+ Output << " case " << Expansion.PseudoOpcode << ": {\n"
+ << " mc::MCInst Result(mc::MCOpcode::fromValue(" << Expansion.ResultOpcode
+ << "));\n"
+ " Result.setFlags(Instruction.flags().rawValue());\n"
+ " Result.setSourceIdentity(Instruction.stableID().value());\n"
+ " Result.reserveOperands("
+ << Expansion.Operands.size() << ");\n";
+ for (std::size_t Index = 0; Index < Expansion.Operands.size(); ++Index) {
+ const NormalizedMCPseudoOperand &Operand = Expansion.Operands[Index];
+ switch (Operand.Kind) {
+ case NormalizedMCPseudoOperandKind::SourceOperand:
+ Output << " const MachineOperand *Operand" << Index << " = Instruction.operandAt("
+ << Operand.Value << ");\n"
+ << " if (Operand" << Index << " == nullptr)\n"
+ << " return makeUnexpected(ErrorCode::AssemblyLoweringFailed,\n"
+ " \"MC pseudo has too few operands\");\n"
+ << " auto Lowered" << Index << " =\n"
+ << " lowerOperand(*Operand" << Index
+ << ", Instruction.function(), Context);\n"
+ << " if (!Lowered" << Index << ")\n"
+ << " return std::unexpected(Lowered" << Index << ".error());\n"
+ << " Result.addOperand(std::move(*Lowered" << Index << "));\n";
+ break;
+ case NormalizedMCPseudoOperandKind::Register:
+ Output << " Result.addOperand(mc::MCOperand::registerOperand(\n"
+ " mc::MCRegister::fromValue("
+ << Operand.Value << ")));\n";
+ break;
+ case NormalizedMCPseudoOperandKind::Immediate:
+ Output << " Result.addOperand(mc::MCOperand::immediate(" << Operand.Immediate << "));\n";
+ break;
+ }
+ }
+ Output << " return std::optional<mc::MCInst>{std::move(Result)};\n"
+ " }\n";
+ }
+ Output << " }\n"
+ "}\n\n"
+ "#endif // GET_MC_PSEUDO_LOWERING\n";
+ return Output.str();
+}
+
+} // namespace rcc::targetgen
diff --git a/backend/utils/TableGen/TableGenBackends.h b/backend/utils/TableGen/TableGenBackends.h
index 6315a6c..dff0333 100644
--- a/backend/utils/TableGen/TableGenBackends.h
+++ b/backend/utils/TableGen/TableGenBackends.h
@@ -20,6 +20,7 @@ struct GeneratedDescription final {
std::string GlobalISel;
std::string GlobalISelCombiner;
std::string MacroFusion;
+ std::string MCPseudoLowering;
};
struct DescriptionGenerationResult final {
@@ -50,6 +51,8 @@ struct DescriptionGenerationResult final {
std::string_view SourceName);
[[nodiscard]] std::string emitMacroFusion(const NormalizedTargetModel &Model,
std::string_view SourceName);
+[[nodiscard]] std::string emitMCPseudoLowering(const NormalizedTargetModel &Model,
+ std::string_view SourceName);
[[nodiscard]] DescriptionGenerationResult generateDescription(const std::string &SourceName,
std::string SourceText);
diff --git a/backend/utils/TableGen/rcc-tblgen.cpp b/backend/utils/TableGen/rcc-tblgen.cpp
index 47f0de4..cf10665 100644
--- a/backend/utils/TableGen/rcc-tblgen.cpp
+++ b/backend/utils/TableGen/rcc-tblgen.cpp
@@ -24,6 +24,7 @@ struct CommandLine final {
std::string GlobalISelPath;
std::string GlobalISelCombinerPath;
std::string MacroFusionPath;
+ std::string MCPseudoLoweringPath;
};
[[nodiscard]] bool parseCommandLine(int ArgumentCount, char *Arguments[], CommandLine &Result) {
@@ -39,7 +40,8 @@ struct CommandLine final {
}
if (Argument == "--register-header" || Argument == "--instruction-header" ||
Argument == "--tables" || Argument == "--global-isel" ||
- Argument == "--global-isel-combiner" || Argument == "--macro-fusion") {
+ Argument == "--global-isel-combiner" || Argument == "--macro-fusion" ||
+ Argument == "--mc-pseudo-lowering") {
if (Index + 1 >= ArgumentCount) {
std::cerr << "rcc-tblgen: missing value for " << Argument << '\n';
return false;
@@ -55,6 +57,8 @@ struct CommandLine final {
Destination = &Result.GlobalISelCombinerPath;
else if (Argument == "--macro-fusion")
Destination = &Result.MacroFusionPath;
+ else if (Argument == "--mc-pseudo-lowering")
+ Destination = &Result.MCPseudoLoweringPath;
else
Destination = &Result.TablesPath;
*Destination = Arguments[++Index];
@@ -66,12 +70,13 @@ struct CommandLine final {
if (!Result.InputPaths.empty() && !Result.RegisterHeaderPath.empty() &&
!Result.InstructionHeaderPath.empty() && !Result.TablesPath.empty() &&
!Result.GlobalISelPath.empty() && !Result.GlobalISelCombinerPath.empty() &&
- !Result.MacroFusionPath.empty()) {
+ !Result.MacroFusionPath.empty() && !Result.MCPseudoLoweringPath.empty()) {
return true;
}
std::cerr << "usage: rcc-tblgen --input <file> [--input <fragment>]... --register-header <file> "
"--instruction-header <file> --tables <file> --global-isel <file> "
- "--global-isel-combiner <file> --macro-fusion <file>\n";
+ "--global-isel-combiner <file> --macro-fusion <file> "
+ "--mc-pseudo-lowering <file>\n";
return false;
}
@@ -176,7 +181,8 @@ combineDescriptionSources(const std::vector<std::string> &Paths,
continue;
}
if (Section.Name != "instructions" && Section.Name != "selection_rules" &&
- Section.Name != "combiner_rules") {
+ Section.Name != "combiner_rules" && Section.Name != "macro_fusion_rules" &&
+ Section.Name != "mc_pseudo_expansions") {
std::cerr << "rcc-tblgen: duplicate description section '" << Section.Name << "' in '"
<< Paths[Index] << "'\n";
return std::nullopt;
@@ -238,7 +244,8 @@ int main(int ArgumentCount, char *Arguments[]) {
writeFile(Command.TablesPath, Output.TargetTables) &&
writeFile(Command.GlobalISelPath, Output.GlobalISel) &&
writeFile(Command.GlobalISelCombinerPath, Output.GlobalISelCombiner) &&
- writeFile(Command.MacroFusionPath, Output.MacroFusion)
+ writeFile(Command.MacroFusionPath, Output.MacroFusion) &&
+ writeFile(Command.MCPseudoLoweringPath, Output.MCPseudoLowering)
? 0
: 1;
}