aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h6
-rw-r--r--backend/include/rcc/TableGen/Record.h27
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVSubtarget.h1
-rw-r--r--backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp107
-rw-r--r--backend/lib/TableGen/Parser.cpp129
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp137
-rw-r--r--backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc193
-rw-r--r--backend/lib/Target/RISCV/RISCVSubtarget.cpp1
-rw-r--r--backend/utils/TableGen/Common/CodeGenSelection.cpp134
-rw-r--r--backend/utils/TableGen/Common/CodeGenTarget.h19
-rw-r--r--backend/utils/TableGen/GlobalISelEmitter.cpp24
11 files changed, 516 insertions, 262 deletions
diff --git a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h
index fbbf68f..098f9d6 100644
--- a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -37,6 +37,8 @@ enum class GIMatchTableOpcode : std::uint8_t {
CheckOperandBank,
CheckOperandClass,
CheckIntegerPredicate,
+ CheckTargetPredicate,
+ CheckOperandImmediateRanges,
CheckOperandDefConstantRanges,
CheckOperandDefOpcode,
CheckOperandDefOperandConstantRanges,
@@ -108,6 +110,10 @@ public:
const TargetDescription &Target) const;
protected:
+ [[nodiscard]] virtual Expected<bool>
+ matchesTargetPredicate(std::string_view Name, const MachineInstr &Instruction,
+ const MachineFunction &Function, const TargetDescription &Target) const;
+
[[nodiscard]] virtual Expected<std::optional<GIMatchComplexOperand>>
renderComplexOperand(std::string_view Name, const MachineInstr &Instruction,
const MachineFunction &Function, const TargetDescription &Target,
diff --git a/backend/include/rcc/TableGen/Record.h b/backend/include/rcc/TableGen/Record.h
index 6575b82..1f9dea9 100644
--- a/backend/include/rcc/TableGen/Record.h
+++ b/backend/include/rcc/TableGen/Record.h
@@ -235,15 +235,26 @@ struct SourceSelectionIntegerPredicate final {
TextRange Range;
};
-struct SourceSelectionOperandDefConstantPredicate final {
+struct SourceSelectionTargetPredicate final {
+ std::string Symbol;
+ TextRange Range;
+};
+
+struct SourceSelectionConstantRange final {
+ std::int64_t Minimum = 0;
+ std::int64_t Maximum = 0;
+ TextRange SourceRange;
+};
+
+struct SourceSelectionOperandImmediatePredicate final {
std::uint32_t OperandIndex = 0;
- struct ConstantRange final {
- std::int64_t Minimum = 0;
- std::int64_t Maximum = 0;
- TextRange SourceRange;
- };
+ std::vector<SourceSelectionConstantRange> Ranges;
+ TextRange Range;
+};
- std::vector<ConstantRange> Ranges;
+struct SourceSelectionOperandDefConstantPredicate final {
+ std::uint32_t OperandIndex = 0;
+ std::vector<SourceSelectionConstantRange> Ranges;
TextRange Range;
};
@@ -294,9 +305,11 @@ struct SourceSelectionRule final {
std::string MatchOpcodeSymbol;
std::optional<SourceSelectionTypePredicate> ResultType;
std::optional<SourceSelectionIntegerPredicate> IntegerPredicate;
+ std::vector<SourceSelectionTargetPredicate> TargetPredicates;
std::vector<SourceSelectionOperandTypePredicate> OperandTypes;
std::vector<SourceSelectionOperandBankPredicate> OperandBanks;
std::vector<SourceSelectionOperandClassPredicate> OperandClasses;
+ std::vector<SourceSelectionOperandImmediatePredicate> OperandImmediates;
std::vector<SourceSelectionOperandDefConstantPredicate> OperandDefConstants;
std::vector<SourceSelectionDefUsePredicate> DefUsePredicates;
std::vector<SourceSelectionTemporary> Temporaries;
diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
index 34ed4bd..c590be6 100644
--- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
+++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
@@ -27,6 +27,7 @@ enum class RISCVExtension : std::uint8_t {
F,
D,
C,
+ Zba,
Zbb,
Zicsr,
Zifencei,
diff --git a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
index 97b6cfe..739f12b 100644
--- a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
+++ b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
@@ -146,21 +146,15 @@ operandOrDefConstantValue(const MachineInstr &Instruction, const MachineFunction
return operandDefConstantValue(Instruction, Function, OperandIndex);
}
-[[nodiscard]] Expected<bool> matchesOperandDefConstantRanges(const GIMatchTable &Table,
- const MachineInstr &Instruction,
- const MachineFunction &Function,
- const GIMatchTableInstruction &Step) {
- const std::size_t First = Step.Value;
- const std::size_t Count = Step.Auxiliary;
+[[nodiscard]] Expected<bool> matchesConstantRanges(const GIMatchTable &Table, std::size_t First,
+ std::size_t Count,
+ std::optional<std::int64_t> Value) {
if (Count == 0 || First > Table.ConstantRanges.size() ||
Count > Table.ConstantRanges.size() - First) {
return makeUnexpected(ErrorCode::VerificationError,
"generated match table has an invalid constant range");
}
- auto Value = operandDefConstantValue(Instruction, Function, Step.OperandIndex);
if (!Value)
- return std::unexpected(Value.error());
- if (!*Value)
return false;
for (std::size_t Index = First; Index < First + Count; ++Index) {
const GIMatchTableConstantRange &Range = Table.ConstantRanges[Index];
@@ -168,12 +162,31 @@ operandOrDefConstantValue(const MachineInstr &Instruction, const MachineFunction
return makeUnexpected(ErrorCode::VerificationError,
"generated match table has an inverted constant range");
}
- if (**Value >= Range.Minimum && **Value <= Range.Maximum)
+ if (*Value >= Range.Minimum && *Value <= Range.Maximum)
return true;
}
return false;
}
+[[nodiscard]] Expected<bool> matchesOperandImmediateRanges(const GIMatchTable &Table,
+ const MachineInstr &Instruction,
+ const GIMatchTableInstruction &Step) {
+ const MachineOperand *Operand = Instruction.operandAt(Step.OperandIndex);
+ const std::optional<std::int64_t> Value =
+ Operand == nullptr ? std::optional<std::int64_t>{} : immediateValue(*Operand);
+ return matchesConstantRanges(Table, Step.Value, Step.Auxiliary, Value);
+}
+
+[[nodiscard]] Expected<bool> matchesOperandDefConstantRanges(const GIMatchTable &Table,
+ const MachineInstr &Instruction,
+ const MachineFunction &Function,
+ const GIMatchTableInstruction &Step) {
+ auto Value = operandDefConstantValue(Instruction, Function, Step.OperandIndex);
+ if (!Value)
+ return std::unexpected(Value.error());
+ return matchesConstantRanges(Table, Step.Value, Step.Auxiliary, *Value);
+}
+
[[nodiscard]] const MachineInstr *operandDefinition(const MachineInstr &Instruction,
const MachineFunction &Function,
std::size_t OperandIndex) {
@@ -201,30 +214,14 @@ matchesOperandDefOperandConstantRanges(const GIMatchTable &Table, const MachineI
return makeUnexpected(ErrorCode::VerificationError,
"generated match table has an invalid def-use constant range count");
}
- const std::size_t First = Step.Value;
const std::size_t Count = static_cast<std::size_t>(Step.Immediate);
- if (First > Table.ConstantRanges.size() || Count > Table.ConstantRanges.size() - First) {
- return makeUnexpected(ErrorCode::VerificationError,
- "generated match table has an invalid def-use constant range");
- }
const MachineInstr *Definition = operandDefinition(Instruction, Function, Step.OperandIndex);
if (Definition == nullptr)
return false;
auto Value = operandOrDefConstantValue(*Definition, Function, Step.Auxiliary);
if (!Value)
return std::unexpected(Value.error());
- if (!*Value)
- return false;
- for (std::size_t Index = First; Index < First + Count; ++Index) {
- const GIMatchTableConstantRange &Range = Table.ConstantRanges[Index];
- if (Range.Minimum > Range.Maximum) {
- return makeUnexpected(ErrorCode::VerificationError,
- "generated match table has an inverted def-use constant range");
- }
- if (**Value >= Range.Minimum && **Value <= Range.Maximum)
- return true;
- }
- return false;
+ return matchesConstantRanges(Table, Step.Value, Count, *Value);
}
[[nodiscard]] Expected<RegisterOperandFlags> registerFlagsFromRaw(std::uint32_t Raw) {
@@ -303,10 +300,11 @@ findCapturedOperand(const std::vector<MatchedRule::CapturedOperand> &Captures, s
return Position == Captures.end() ? nullptr : &*Position;
}
-[[nodiscard]] Expected<std::optional<MatchedRule>> matchRule(const GIMatchTable &Table,
- const GIMatchTableRule &Rule,
- const MachineInstr &Instruction,
- const MachineFunction &Function) {
+template <typename TargetPredicateMatcher>
+[[nodiscard]] Expected<std::optional<MatchedRule>>
+matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const MachineInstr &Instruction,
+ const MachineFunction &Function, const TargetDescription &Target,
+ TargetPredicateMatcher &&MatchesTargetPredicate) {
const std::size_t First = Rule.FirstInstruction;
const std::size_t Count = Rule.InstructionCount;
if (First > Table.Instructions.size() || Count > Table.Instructions.size() - First) {
@@ -376,6 +374,30 @@ findCapturedOperand(const std::vector<MatchedRule::CapturedOperand> &Captures, s
return std::optional<MatchedRule>{};
break;
}
+ case GIMatchTableOpcode::CheckTargetPredicate: {
+ if (Applying || Step.Symbol.empty()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table has an invalid target predicate");
+ }
+ auto Matched = MatchesTargetPredicate(Step.Symbol, Instruction, Function, Target);
+ if (!Matched)
+ return std::unexpected(Matched.error());
+ if (!*Matched)
+ return std::optional<MatchedRule>{};
+ break;
+ }
+ case GIMatchTableOpcode::CheckOperandImmediateRanges: {
+ if (Applying) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table performs a predicate after an action");
+ }
+ auto Matched = matchesOperandImmediateRanges(Table, Instruction, Step);
+ if (!Matched)
+ return std::unexpected(Matched.error());
+ if (!*Matched)
+ return std::optional<MatchedRule>{};
+ break;
+ }
case GIMatchTableOpcode::CheckOperandDefConstantRanges: {
if (Applying) {
return makeUnexpected(ErrorCode::VerificationError,
@@ -1175,6 +1197,15 @@ Expected<void> GIMatchTableExecutor::finalizeGeneratedInstruction(MachineInstr &
return {};
}
+Expected<bool> GIMatchTableExecutor::matchesTargetPredicate(std::string_view Name,
+ const MachineInstr &,
+ const MachineFunction &,
+ const TargetDescription &) const {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table uses unknown target predicate '" +
+ std::string(Name) + "'");
+}
+
Expected<std::optional<GIMatchComplexOperand>>
GIMatchTableExecutor::renderComplexOperand(std::string_view, const MachineInstr &,
const MachineFunction &, const TargetDescription &,
@@ -1187,7 +1218,12 @@ Expected<bool> GIMatchTableExecutor::match(const GIMatchTable &Table,
const MachineFunction &Function,
const TargetDescription &Target) const {
for (const GIMatchTableRule &Rule : Table.Rules) {
- auto Match = matchRule(Table, Rule, Instruction, Function);
+ auto Match = matchRule(Table, Rule, Instruction, Function, Target,
+ [this](std::string_view Name, const MachineInstr &Input,
+ const MachineFunction &InputFunction,
+ const TargetDescription &InputTarget) {
+ return matchesTargetPredicate(Name, Input, InputFunction, InputTarget);
+ });
if (!Match)
return std::unexpected(Match.error());
if (!*Match)
@@ -1218,7 +1254,12 @@ Expected<bool> GIMatchTableExecutor::select(const GIMatchTable &Table, MachineIn
MachineFunction &Function,
const TargetDescription &Target) const {
for (const GIMatchTableRule &Rule : Table.Rules) {
- auto Match = matchRule(Table, Rule, Instruction, Function);
+ auto Match = matchRule(Table, Rule, Instruction, Function, Target,
+ [this](std::string_view Name, const MachineInstr &Input,
+ const MachineFunction &InputFunction,
+ const TargetDescription &InputTarget) {
+ return matchesTargetPredicate(Name, Input, InputFunction, InputTarget);
+ });
if (!Match)
return std::unexpected(Match.error());
if (!*Match)
diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp
index b4ff73c..7c6a8de 100644
--- a/backend/lib/TableGen/Parser.cpp
+++ b/backend/lib/TableGen/Parser.cpp
@@ -1173,6 +1173,92 @@ private:
return true;
}
+ [[nodiscard]] bool
+ parseSelectionTargetPredicates(const yaml::Node &Node,
+ std::vector<SourceSelectionTargetPredicate> &Result) {
+ if (!requireSequence(&Node, "selection target predicates"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (Element == nullptr)
+ return false;
+ const auto Symbol = scalar(*Element, "selection target predicate");
+ if (!Symbol)
+ return false;
+ Result.push_back({
+ .Symbol = *Symbol,
+ .Range = Element->range(),
+ });
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool parseSelectionConstantRanges(const yaml::Node &Node,
+ std::vector<SourceSelectionConstantRange> &Result,
+ std::string_view Context) {
+ if (!requireSequence(&Node, Context) || Node.sequence().empty())
+ return false;
+ for (const yaml::NodeID RangeID : Node.sequence()) {
+ const yaml::Node *Range = Input.node(RangeID);
+ const std::string RangeContext = std::string(Context) + " range";
+ if (!requireMapping(Range, RangeContext) ||
+ !checkKeys(*Range, {"min", "max"}, RangeContext)) {
+ return false;
+ }
+ const yaml::Node *MinimumNode = requiredNode(*Range, "min", RangeContext);
+ const yaml::Node *MaximumNode = requiredNode(*Range, "max", RangeContext);
+ if (MinimumNode == nullptr || MaximumNode == nullptr)
+ return false;
+ const auto Minimum = signedInteger(*MinimumNode, "selection constant range minimum");
+ const auto Maximum = signedInteger(*MaximumNode, "selection constant range maximum");
+ if (!Minimum || !Maximum || *Minimum > *Maximum) {
+ if (Minimum && Maximum)
+ fail(Range->range(), "selection constant range is invalid");
+ return false;
+ }
+ Result.push_back({
+ .Minimum = *Minimum,
+ .Maximum = *Maximum,
+ .SourceRange = Range->range(),
+ });
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool
+ parseSelectionOperandImmediates(const yaml::Node &Node,
+ std::vector<SourceSelectionOperandImmediatePredicate> &Result) {
+ if (!requireSequence(&Node, "selection operand immediates"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (!requireMapping(Element, "selection operand immediate") ||
+ !checkKeys(*Element, {"index", "ranges"}, "selection operand immediate")) {
+ return false;
+ }
+ const yaml::Node *IndexNode = requiredNode(*Element, "index", "selection operand immediate");
+ const yaml::Node *RangesNode =
+ requiredNode(*Element, "ranges", "selection operand immediate");
+ if (IndexNode == nullptr || RangesNode == nullptr)
+ return false;
+ const auto Index = unsignedInteger32(*IndexNode, "selection operand immediate index");
+ if (!Index)
+ return false;
+
+ SourceSelectionOperandImmediatePredicate Predicate{
+ .OperandIndex = *Index,
+ .Ranges = {},
+ .Range = Element->range(),
+ };
+ if (!parseSelectionConstantRanges(*RangesNode, Predicate.Ranges,
+ "selection operand immediate ranges")) {
+ return false;
+ }
+ Result.push_back(std::move(Predicate));
+ }
+ return true;
+ }
+
[[nodiscard]] bool parseSelectionOperandDefConstants(
const yaml::Node &Node, std::vector<SourceSelectionOperandDefConstantPredicate> &Result) {
if (!requireSequence(&Node, "selection operand definition constants"))
@@ -1191,8 +1277,7 @@ private:
return false;
const auto Index =
unsignedInteger32(*IndexNode, "selection operand definition constant index");
- if (!Index || !requireSequence(RangesNode, "selection operand definition constant ranges") ||
- RangesNode->sequence().empty()) {
+ if (!Index) {
return false;
}
@@ -1201,30 +1286,9 @@ private:
.Ranges = {},
.Range = Element->range(),
};
- for (const yaml::NodeID RangeID : RangesNode->sequence()) {
- const yaml::Node *Range = Input.node(RangeID);
- if (!requireMapping(Range, "selection operand definition constant range") ||
- !checkKeys(*Range, {"min", "max"}, "selection operand definition constant range")) {
- return false;
- }
- const yaml::Node *MinimumNode =
- requiredNode(*Range, "min", "selection operand definition constant range");
- const yaml::Node *MaximumNode =
- requiredNode(*Range, "max", "selection operand definition constant range");
- if (MinimumNode == nullptr || MaximumNode == nullptr)
- return false;
- const auto Minimum = signedInteger(*MinimumNode, "selection constant range minimum");
- const auto Maximum = signedInteger(*MaximumNode, "selection constant range maximum");
- if (!Minimum || !Maximum || *Minimum > *Maximum) {
- if (Minimum && Maximum)
- fail(Range->range(), "selection operand definition constant range is invalid");
- return false;
- }
- Predicate.Ranges.push_back({
- .Minimum = *Minimum,
- .Maximum = *Maximum,
- .SourceRange = Range->range(),
- });
+ if (!parseSelectionConstantRanges(*RangesNode, Predicate.Ranges,
+ "selection operand definition constant ranges")) {
+ return false;
}
Result.push_back(std::move(Predicate));
}
@@ -1472,8 +1536,9 @@ private:
[[nodiscard]] bool parseSelectionRuleMatch(const yaml::Node &Node, SourceSelectionRule &Result) {
if (!requireMapping(&Node, "selection rule match") ||
!checkKeys(Node,
- {"opcode", "result_type", "integer_predicate", "operand_types", "operand_banks",
- "operand_classes", "operand_def_constants", "def_use"},
+ {"opcode", "result_type", "integer_predicate", "target_predicates",
+ "operand_types", "operand_banks", "operand_classes", "operand_immediates",
+ "operand_def_constants", "def_use"},
"selection rule match")) {
return false;
}
@@ -1491,6 +1556,10 @@ private:
if (!parseSelectionIntegerPredicate(*Predicate, Result))
return false;
}
+ if (const yaml::Node *TargetPredicates = optionalNode(Node, "target_predicates")) {
+ if (!parseSelectionTargetPredicates(*TargetPredicates, Result.TargetPredicates))
+ return false;
+ }
if (const yaml::Node *OperandTypes = optionalNode(Node, "operand_types")) {
if (!parseSelectionOperandTypes(*OperandTypes, Result.OperandTypes))
return false;
@@ -1503,6 +1572,10 @@ private:
if (!parseSelectionOperandClasses(*OperandClasses, Result.OperandClasses))
return false;
}
+ if (const yaml::Node *OperandImmediates = optionalNode(Node, "operand_immediates")) {
+ if (!parseSelectionOperandImmediates(*OperandImmediates, Result.OperandImmediates))
+ return false;
+ }
if (const yaml::Node *OperandDefConstants = optionalNode(Node, "operand_def_constants")) {
if (!parseSelectionOperandDefConstants(*OperandDefConstants, Result.OperandDefConstants))
return false;
diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 64cbf47..898b366 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -147,6 +147,16 @@ public:
const RISCVRegisterBankInfo &RegisterBanks)
: Subtarget(Subtarget), RegisterBanks(RegisterBanks) {}
+ [[nodiscard]] Expected<bool> matchesTargetPredicate(std::string_view Name, const MachineInstr &,
+ const MachineFunction &,
+ const TargetDescription &) const override {
+ if (Name == "zba")
+ return Subtarget.features().has(RISCVExtension::Zba);
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V generated GlobalISel rule uses unknown target predicate '" +
+ std::string(Name) + "'");
+ }
+
[[nodiscard]] Expected<void>
constrainSelectedInstruction(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target) const override {
@@ -375,9 +385,6 @@ public:
case GenericOpcode::G_PTRTOINT:
case GenericOpcode::G_INTTOPTR:
case GenericOpcode::G_TRUNC:
- case GenericOpcode::G_SEXT:
- case GenericOpcode::G_SEXT_INREG:
- case GenericOpcode::G_ZEXT:
case GenericOpcode::G_FCMP:
case GenericOpcode::G_SMULH:
case GenericOpcode::G_UMULH:
@@ -456,13 +463,9 @@ public:
case GenericOpcode::G_INTTOPTR:
return Instruction.setOpcode(opcode(GenericOpcode::COPY));
case GenericOpcode::G_ANYEXT:
- case GenericOpcode::G_SEXT:
- case GenericOpcode::G_ZEXT:
- return selectIntegerExtension(Instruction, Function, Target, Generic, Type);
+ return Instruction.setOpcode(opcode(GenericOpcode::COPY));
case GenericOpcode::G_TRUNC:
return Instruction.setOpcode(opcode(GenericOpcode::COPY));
- case GenericOpcode::G_SEXT_INREG:
- return selectSignExtendInRegister(Instruction, Function, Target, Type);
case GenericOpcode::G_FCMP:
return selectFloatingCompare(Instruction, Function, Target);
case GenericOpcode::G_SELECT:
@@ -890,7 +893,6 @@ private:
return {};
}
-
[[nodiscard]] Expected<void> selectAtomicRMW(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target,
std::optional<LowLevelType> Type,
@@ -975,123 +977,6 @@ private:
return Instruction.setOpcode(instructionOpcode(Selected));
}
- [[nodiscard]] Expected<void> selectIntegerExtension(MachineInstr &Instruction,
- MachineFunction &Function,
- const TargetDescription &Target,
- GenericOpcode Generic,
- std::optional<LowLevelType> Type) const {
- const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, 1);
- const MachineOperand *DestinationOperand = Instruction.operandAt(0);
- const MachineOperand *SourceOperand = Instruction.operandAt(1);
- const Register *Destination =
- DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
- const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>();
- if (!Type || !SourceType || Destination == nullptr || Source == nullptr)
- return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V integer extension has invalid register operands");
- const Register DestinationRegister = *Destination;
- if (Generic == GenericOpcode::G_ANYEXT)
- return Instruction.setOpcode(opcode(GenericOpcode::COPY));
-
- const std::uint32_t DestinationBits = Type->scalarBitWidth();
- const std::uint32_t SourceBits = SourceType->scalarBitWidth();
- if (Generic == GenericOpcode::G_SEXT && DestinationBits == 64 && SourceBits == 32) {
- auto ImmediateResult = appendImmediate(Instruction, 0);
- if (!ImmediateResult)
- return std::unexpected(ImmediateResult.error());
- return Instruction.setOpcode(instructionOpcode(InstructionOpcode::ADDIW));
- }
-
- const std::uint32_t ContainerBits = DestinationBits <= 32 ? 32 : 64;
- const std::int64_t Shift = static_cast<std::int64_t>(ContainerBits - SourceBits);
- const InstructionOpcode ShiftLeft =
- ContainerBits == 32 ? InstructionOpcode::SLLIW : InstructionOpcode::SLLI;
- const InstructionOpcode ShiftRight =
- Generic == GenericOpcode::G_SEXT
- ? (ContainerBits == 32 ? InstructionOpcode::SRAIW : InstructionOpcode::SRAI)
- : (ContainerBits == 32 ? InstructionOpcode::SRLIW : InstructionOpcode::SRLI);
- auto Temporary = createTemporary(Function, *Type, Target);
- if (!Temporary)
- return std::unexpected(Temporary.error());
- auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary);
- if (!SetDestination)
- return std::unexpected(SetDestination.error());
- auto SetOpcode = Instruction.setOpcode(instructionOpcode(ShiftLeft));
- if (!SetOpcode)
- return std::unexpected(SetOpcode.error());
- auto ShiftImmediate = appendImmediate(Instruction, Shift);
- if (!ShiftImmediate)
- return std::unexpected(ShiftImmediate.error());
-
- MachineIRBuilder Builder(Function, Target);
- auto Shifted = buildImmediateAfter(Builder, Instruction, ShiftRight, DestinationRegister,
- *Temporary, Shift);
- if (!Shifted)
- return std::unexpected(Shifted.error());
- return {};
- }
-
- [[nodiscard]] Expected<void> selectSignExtendInRegister(MachineInstr &Instruction,
- MachineFunction &Function,
- const TargetDescription &Target,
- std::optional<LowLevelType> Type) const {
- const MachineOperand *DestinationOperand = Instruction.operandAt(0);
- const MachineOperand *SourceOperand = Instruction.operandAt(1);
- const Register *Destination =
- DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
- const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>();
- std::optional<std::int64_t> Width;
- if (const MachineOperand *WidthOperand = Instruction.operandAt(2); WidthOperand != nullptr) {
- auto ParsedWidth = signedImmediate(*WidthOperand);
- if (ParsedWidth)
- Width = *ParsedWidth;
- }
- if (!Type || Destination == nullptr || Source == nullptr || !Width || *Width <= 0 ||
- static_cast<std::uint64_t>(*Width) > Type->scalarBitWidth())
- return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V sign-extension-in-register has invalid operands");
- const Register DestinationRegister = *Destination;
- if (static_cast<std::uint64_t>(*Width) == Type->scalarBitWidth()) {
- auto EraseWidth = Instruction.eraseOperand(2);
- if (!EraseWidth)
- return std::unexpected(EraseWidth.error());
- return Instruction.setOpcode(opcode(GenericOpcode::COPY));
- }
-
- const std::uint32_t TypeBits = Type->scalarBitWidth();
- if (TypeBits == 64 && *Width == 32) {
- auto ImmediateResult = replaceImmediate(Instruction, 2, 0);
- if (!ImmediateResult)
- return std::unexpected(ImmediateResult.error());
- return Instruction.setOpcode(instructionOpcode(InstructionOpcode::ADDIW));
- }
- const std::uint32_t ContainerBits = TypeBits <= 32 ? 32 : 64;
- const std::int64_t Shift = static_cast<std::int64_t>(ContainerBits) - *Width;
- const InstructionOpcode ShiftLeft =
- ContainerBits == 32 ? InstructionOpcode::SLLIW : InstructionOpcode::SLLI;
- const InstructionOpcode ShiftRight =
- ContainerBits == 32 ? InstructionOpcode::SRAIW : InstructionOpcode::SRAI;
- auto Temporary = createTemporary(Function, *Type, Target);
- if (!Temporary)
- return std::unexpected(Temporary.error());
- auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary);
- if (!SetDestination)
- return std::unexpected(SetDestination.error());
- auto SetOpcode = Instruction.setOpcode(instructionOpcode(ShiftLeft));
- if (!SetOpcode)
- return std::unexpected(SetOpcode.error());
- auto ShiftImmediate = replaceImmediate(Instruction, 2, Shift);
- if (!ShiftImmediate)
- return std::unexpected(ShiftImmediate.error());
-
- MachineIRBuilder Builder(Function, Target);
- auto Shifted = buildImmediateAfter(Builder, Instruction, ShiftRight, DestinationRegister,
- *Temporary, Shift);
- if (!Shifted)
- return std::unexpected(Shifted.error());
- return {};
- }
-
[[nodiscard]] Expected<void> selectFloatingCompare(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target) const {
diff --git a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc
index e096993..1667f66 100644
--- a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc
@@ -1,5 +1,198 @@
selection_rules:
-
+ id: select_g_sext_s64_s32
+ priority: 500
+ match:
+ opcode: G_SEXT
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ instructions:
+ - opcode: ADDIW
+ root: true
+ operands: [{ operand: 0 }, { operand: 1 }, { immediate: 0 }]
+ -
+ id: select_g_sext_s64_s16
+ priority: 400
+ match:
+ opcode: G_SEXT
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 16 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ temporaries:
+ - { id: extended, type_from_operand: 0 }
+ instructions:
+ - opcode: SLLI
+ root: true
+ operands:
+ - { temporary: extended, flags: [define] }
+ - { operand: 1 }
+ - { immediate: 48 }
+ - opcode: SRAI
+ root: false
+ operands:
+ - { operand: 0 }
+ - { temporary: extended, flags: [use] }
+ - { immediate: 48 }
+ -
+ id: select_g_sext_s32_s16
+ priority: 400
+ match:
+ opcode: G_SEXT
+ result_type: { kind: scalar, bits: 32 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 16 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ temporaries:
+ - { id: extended, type_from_operand: 0 }
+ instructions:
+ - opcode: SLLIW
+ root: true
+ operands:
+ - { temporary: extended, flags: [define] }
+ - { operand: 1 }
+ - { immediate: 16 }
+ - opcode: SRAIW
+ root: false
+ operands:
+ - { operand: 0 }
+ - { temporary: extended, flags: [use] }
+ - { immediate: 16 }
+ -
+ id: select_g_zext_s64_s32_zba
+ priority: 500
+ match:
+ opcode: G_ZEXT
+ result_type: { kind: scalar, bits: 64 }
+ target_predicates: [zba]
+ operand_types:
+ - { index: 1, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ instructions:
+ - opcode: ADD_UW
+ root: true
+ operands:
+ - { operand: 0 }
+ - { operand: 1 }
+ - { physical_register: X0, flags: [use] }
+ -
+ id: select_g_zext_s64_s32
+ priority: 400
+ match:
+ opcode: G_ZEXT
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ temporaries:
+ - { id: extended, type_from_operand: 0 }
+ instructions:
+ - opcode: SLLI
+ root: true
+ operands:
+ - { temporary: extended, flags: [define] }
+ - { operand: 1 }
+ - { immediate: 32 }
+ - opcode: SRLI
+ root: false
+ operands:
+ - { operand: 0 }
+ - { temporary: extended, flags: [use] }
+ - { immediate: 32 }
+ -
+ id: select_g_zext_s64_s16
+ priority: 400
+ match:
+ opcode: G_ZEXT
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 16 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ temporaries:
+ - { id: extended, type_from_operand: 0 }
+ instructions:
+ - opcode: SLLI
+ root: true
+ operands:
+ - { temporary: extended, flags: [define] }
+ - { operand: 1 }
+ - { immediate: 48 }
+ - opcode: SRLI
+ root: false
+ operands:
+ - { operand: 0 }
+ - { temporary: extended, flags: [use] }
+ - { immediate: 48 }
+ -
+ id: select_g_zext_s32_s16
+ priority: 400
+ match:
+ opcode: G_ZEXT
+ result_type: { kind: scalar, bits: 32 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 16 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ apply:
+ temporaries:
+ - { id: extended, type_from_operand: 0 }
+ instructions:
+ - opcode: SLLIW
+ root: true
+ operands:
+ - { temporary: extended, flags: [define] }
+ - { operand: 1 }
+ - { immediate: 16 }
+ - opcode: SRLIW
+ root: false
+ operands:
+ - { operand: 0 }
+ - { temporary: extended, flags: [use] }
+ - { immediate: 16 }
+ -
+ id: select_g_sext_inreg_s64_32
+ priority: 500
+ match:
+ opcode: G_SEXT_INREG
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 64 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 1, bank: GPR }
+ operand_immediates:
+ - index: 2
+ ranges: [{ min: 32, max: 32 }]
+ apply:
+ instructions:
+ - opcode: ADDIW
+ root: true
+ operands:
+ - { operand: 0 }
+ - { operand: 1 }
+ - { immediate: 0 }
+ -
id: select_g_ptr_add_immediate
priority: 400
match:
diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
index e38a574..b6370fd 100644
--- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -32,6 +32,7 @@ constexpr std::array ExtensionNames{
ExtensionName{"f", RISCVExtension::F},
ExtensionName{"d", RISCVExtension::D},
ExtensionName{"c", RISCVExtension::C},
+ ExtensionName{"zba", RISCVExtension::Zba},
ExtensionName{"zbb", RISCVExtension::Zbb},
ExtensionName{"zicsr", RISCVExtension::Zicsr},
ExtensionName{"zifencei", RISCVExtension::Zifencei},
diff --git a/backend/utils/TableGen/Common/CodeGenSelection.cpp b/backend/utils/TableGen/Common/CodeGenSelection.cpp
index 88f85f7..d3bc299 100644
--- a/backend/utils/TableGen/Common/CodeGenSelection.cpp
+++ b/backend/utils/TableGen/Common/CodeGenSelection.cpp
@@ -170,6 +170,36 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) {
}
return NormalizedSelectionTypePredicate{.Kind = Kind, .Bits = Source.Bits};
};
+ const auto NormalizeRanges = [this](const std::vector<SourceSelectionConstantRange> &Ranges,
+ TextRange PredicateRange, std::string_view PredicateName)
+ -> std::optional<std::vector<NormalizedSelectionConstantRange>> {
+ if (Ranges.empty()) {
+ fail(PredicateRange, std::string(PredicateName) + " requires at least one range");
+ return std::nullopt;
+ }
+ std::vector<NormalizedSelectionConstantRange> NormalizedRanges;
+ NormalizedRanges.reserve(Ranges.size());
+ for (const SourceSelectionConstantRange &Range : Ranges) {
+ if (Range.Minimum > Range.Maximum) {
+ fail(Range.SourceRange, std::string(PredicateName) + " range is invalid");
+ return std::nullopt;
+ }
+ NormalizedRanges.push_back({
+ .Minimum = Range.Minimum,
+ .Maximum = Range.Maximum,
+ });
+ }
+ std::ranges::sort(NormalizedRanges, {}, &NormalizedSelectionConstantRange::Minimum);
+ for (std::size_t Index = 1; Index < NormalizedRanges.size(); ++Index) {
+ const auto &Previous = NormalizedRanges[Index - 1];
+ const auto &Current = NormalizedRanges[Index];
+ if (Current.Minimum <= Previous.Maximum) {
+ fail(PredicateRange, std::string(PredicateName) + " ranges overlap");
+ return std::nullopt;
+ }
+ }
+ return NormalizedRanges;
+ };
NormalizedSelectionRule Normalized;
Normalized.Symbol = Rule.Symbol;
@@ -213,6 +243,17 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) {
++Normalized.Specificity;
}
+ std::unordered_set<std::string> TargetPredicateSymbols;
+ for (const SourceSelectionTargetPredicate &Predicate : Rule.TargetPredicates) {
+ if (!isIdentifier(Predicate.Symbol) ||
+ !TargetPredicateSymbols.insert(Predicate.Symbol).second) {
+ fail(Predicate.Range, "selection target predicates require distinct identifiers");
+ return false;
+ }
+ Normalized.TargetPredicates.push_back(Predicate.Symbol);
+ ++Normalized.Specificity;
+ }
+
std::unordered_set<std::uint32_t> TypeOperands;
for (const SourceSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) {
auto Type = NormalizeType(Predicate.Type);
@@ -261,43 +302,40 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) {
++Normalized.Specificity;
}
+ std::unordered_set<std::uint32_t> ImmediateOperands;
+ for (const SourceSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) {
+ if (!ImmediateOperands.insert(Predicate.OperandIndex).second) {
+ fail(Predicate.Range, "selection operand immediate predicates require distinct operands");
+ return false;
+ }
+ auto Ranges = NormalizeRanges(Predicate.Ranges, Predicate.Range,
+ "selection operand immediate predicate");
+ if (!Ranges)
+ return false;
+ Normalized.OperandImmediates.push_back({
+ .OperandIndex = Predicate.OperandIndex,
+ .Ranges = std::move(*Ranges),
+ });
+ ++Normalized.Specificity;
+ }
+
std::unordered_set<std::uint32_t> ConstantOperands;
for (const SourceSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) {
if (!ConstantOperands.insert(Predicate.OperandIndex).second ||
(MatchInstruction != nullptr &&
- !isRegisterOperand(*MatchInstruction, Predicate.OperandIndex)) ||
- Predicate.Ranges.empty()) {
+ !isRegisterOperand(*MatchInstruction, Predicate.OperandIndex))) {
fail(Predicate.Range,
- "selection operand definition constant predicates require distinct register "
- "operands and at least one range");
+ "selection operand definition constant predicates require distinct register operands");
return false;
}
- NormalizedSelectionOperandDefConstantPredicate NormalizedPredicate{
+ auto Ranges = NormalizeRanges(Predicate.Ranges, Predicate.Range,
+ "selection operand definition constant predicate");
+ if (!Ranges)
+ return false;
+ Normalized.OperandDefConstants.push_back({
.OperandIndex = Predicate.OperandIndex,
- .Ranges = {},
- };
- for (const SourceSelectionOperandDefConstantPredicate::ConstantRange &Range :
- Predicate.Ranges) {
- if (Range.Minimum > Range.Maximum) {
- fail(Range.SourceRange, "selection operand definition constant range is invalid");
- return false;
- }
- NormalizedPredicate.Ranges.push_back({
- .Minimum = Range.Minimum,
- .Maximum = Range.Maximum,
- });
- }
- std::ranges::sort(NormalizedPredicate.Ranges, {},
- &NormalizedSelectionOperandDefConstantPredicate::Range::Minimum);
- for (std::size_t Index = 1; Index < NormalizedPredicate.Ranges.size(); ++Index) {
- const auto &Previous = NormalizedPredicate.Ranges[Index - 1];
- const auto &Current = NormalizedPredicate.Ranges[Index];
- if (Current.Minimum <= Previous.Maximum) {
- fail(Predicate.Range, "selection operand definition constant ranges overlap");
- return false;
- }
- }
- Normalized.OperandDefConstants.push_back(std::move(NormalizedPredicate));
+ .Ranges = std::move(*Ranges),
+ });
++Normalized.Specificity;
}
@@ -338,38 +376,18 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) {
std::unordered_set<std::uint32_t> ConstantOperandsInDef;
for (const SourceSelectionOperandDefConstantPredicate &Constant :
Predicate.OperandDefConstants) {
- if (!ConstantOperandsInDef.insert(Constant.OperandIndex).second ||
- Constant.Ranges.empty()) {
- fail(Constant.Range, "selection def-use constant predicates require distinct operands "
- "and at least one range");
+ if (!ConstantOperandsInDef.insert(Constant.OperandIndex).second) {
+ fail(Constant.Range, "selection def-use constant predicates require distinct operands");
return false;
}
- NormalizedSelectionOperandDefConstantPredicate NormalizedConstant{
+ auto Ranges = NormalizeRanges(Constant.Ranges, Constant.Range,
+ "selection def-use constant predicate");
+ if (!Ranges)
+ return false;
+ NormalizedPredicate.OperandDefConstants.push_back({
.OperandIndex = Constant.OperandIndex,
- .Ranges = {},
- };
- for (const SourceSelectionOperandDefConstantPredicate::ConstantRange &Range :
- Constant.Ranges) {
- if (Range.Minimum > Range.Maximum) {
- fail(Range.SourceRange, "selection def-use constant range is invalid");
- return false;
- }
- NormalizedConstant.Ranges.push_back({
- .Minimum = Range.Minimum,
- .Maximum = Range.Maximum,
- });
- }
- std::ranges::sort(NormalizedConstant.Ranges, {},
- &NormalizedSelectionOperandDefConstantPredicate::Range::Minimum);
- for (std::size_t Index = 1; Index < NormalizedConstant.Ranges.size(); ++Index) {
- const auto &Previous = NormalizedConstant.Ranges[Index - 1];
- const auto &Current = NormalizedConstant.Ranges[Index];
- if (Current.Minimum <= Previous.Maximum) {
- fail(Constant.Range, "selection def-use constant ranges overlap");
- return false;
- }
- }
- NormalizedPredicate.OperandDefConstants.push_back(std::move(NormalizedConstant));
+ .Ranges = std::move(*Ranges),
+ });
}
Normalized.DefUsePredicates.push_back(std::move(NormalizedPredicate));
Normalized.Specificity += 1U + static_cast<std::uint32_t>(Predicate.Captures.size()) +
diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h
index 47dd598..d66cfee 100644
--- a/backend/utils/TableGen/Common/CodeGenTarget.h
+++ b/backend/utils/TableGen/Common/CodeGenTarget.h
@@ -194,14 +194,19 @@ struct NormalizedSelectionIntegerPredicate final {
std::uint32_t Predicate = 0;
};
-struct NormalizedSelectionOperandDefConstantPredicate final {
- struct Range final {
- std::int64_t Minimum = 0;
- std::int64_t Maximum = 0;
- };
+struct NormalizedSelectionConstantRange final {
+ std::int64_t Minimum = 0;
+ std::int64_t Maximum = 0;
+};
+struct NormalizedSelectionOperandImmediatePredicate final {
+ std::uint32_t OperandIndex = 0;
+ std::vector<NormalizedSelectionConstantRange> Ranges;
+};
+
+struct NormalizedSelectionOperandDefConstantPredicate final {
std::uint32_t OperandIndex = 0;
- std::vector<Range> Ranges;
+ std::vector<NormalizedSelectionConstantRange> Ranges;
};
struct NormalizedSelectionDefUseCapture final {
@@ -259,9 +264,11 @@ struct NormalizedSelectionRule final {
std::uint32_t MatchOpcode = 0;
std::optional<NormalizedSelectionTypePredicate> ResultType;
std::optional<NormalizedSelectionIntegerPredicate> IntegerPredicate;
+ std::vector<std::string> TargetPredicates;
std::vector<NormalizedSelectionOperandTypePredicate> OperandTypes;
std::vector<NormalizedSelectionOperandBankPredicate> OperandBanks;
std::vector<NormalizedSelectionOperandClassPredicate> OperandClasses;
+ std::vector<NormalizedSelectionOperandImmediatePredicate> OperandImmediates;
std::vector<NormalizedSelectionOperandDefConstantPredicate> OperandDefConstants;
std::vector<NormalizedSelectionDefUsePredicate> DefUsePredicates;
std::vector<NormalizedSelectionTemporary> Temporaries;
diff --git a/backend/utils/TableGen/GlobalISelEmitter.cpp b/backend/utils/TableGen/GlobalISelEmitter.cpp
index 562ff7c..98568b1 100644
--- a/backend/utils/TableGen/GlobalISelEmitter.cpp
+++ b/backend/utils/TableGen/GlobalISelEmitter.cpp
@@ -42,8 +42,9 @@ void emitTypePredicate(std::ostream &Output, std::uint32_t OperandIndex,
[[nodiscard]] std::size_t instructionCount(const NormalizedSelectionRule &Rule) noexcept {
std::size_t Count = 2U + (Rule.ResultType ? 1U : 0U) + (Rule.IntegerPredicate ? 1U : 0U) +
- Rule.OperandTypes.size() + Rule.OperandBanks.size() +
- Rule.OperandClasses.size() + Rule.OperandDefConstants.size() +
+ Rule.TargetPredicates.size() + Rule.OperandTypes.size() +
+ Rule.OperandBanks.size() + Rule.OperandClasses.size() +
+ Rule.OperandImmediates.size() + Rule.OperandDefConstants.size() +
Rule.Temporaries.size() + Rule.EraseOperandDefinitions.size();
for (const NormalizedSelectionDefUsePredicate &Predicate : Rule.DefUsePredicates)
Count += 1U + Predicate.Captures.size() + Predicate.OperandDefConstants.size();
@@ -60,6 +61,9 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view
for (const NormalizedSelectionRule &Rule : Model.SelectionRules)
InstructionCount += instructionCount(Rule);
for (const NormalizedSelectionRule &Rule : Model.SelectionRules) {
+ for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) {
+ ConstantRangeCount += Predicate.Ranges.size();
+ }
for (const NormalizedSelectionOperandDefConstantPredicate &Predicate :
Rule.OperandDefConstants) {
ConstantRangeCount += Predicate.Ranges.size();
@@ -81,15 +85,19 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view
Output << "constexpr std::array<GIMatchTableConstantRange, " << ConstantRangeCount
<< "> GeneratedGlobalISelConstantRanges = {{\n";
for (const NormalizedSelectionRule &Rule : Model.SelectionRules) {
+ for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) {
+ for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges)
+ Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n";
+ }
for (const NormalizedSelectionOperandDefConstantPredicate &Predicate :
Rule.OperandDefConstants) {
- for (const NormalizedSelectionOperandDefConstantPredicate::Range &Range : Predicate.Ranges)
+ for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges)
Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n";
}
for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) {
for (const NormalizedSelectionOperandDefConstantPredicate &Predicate :
DefUse.OperandDefConstants) {
- for (const NormalizedSelectionOperandDefConstantPredicate::Range &Range : Predicate.Ranges)
+ for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges)
Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n";
}
}
@@ -106,12 +114,20 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view
if (Rule.IntegerPredicate)
emitInstruction(Output, "CheckIntegerPredicate", Rule.IntegerPredicate->OperandIndex,
Rule.IntegerPredicate->Predicate);
+ for (const std::string &Predicate : Rule.TargetPredicates)
+ emitInstruction(Output, "CheckTargetPredicate", 0, 0, "0", 0, Predicate);
for (const NormalizedSelectionOperandTypePredicate &Predicate : Rule.OperandTypes)
emitTypePredicate(Output, Predicate.OperandIndex, Predicate.Type);
for (const NormalizedSelectionOperandBankPredicate &Predicate : Rule.OperandBanks)
emitInstruction(Output, "CheckOperandBank", Predicate.OperandIndex, Predicate.Bank);
for (const NormalizedSelectionOperandClassPredicate &Predicate : Rule.OperandClasses)
emitInstruction(Output, "CheckOperandClass", Predicate.OperandIndex, Predicate.RegClass);
+ for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) {
+ emitInstruction(Output, "CheckOperandImmediateRanges", Predicate.OperandIndex,
+ static_cast<std::uint32_t>(FirstConstantRange),
+ std::to_string(Predicate.Ranges.size()));
+ FirstConstantRange += Predicate.Ranges.size();
+ }
for (const NormalizedSelectionOperandDefConstantPredicate &Predicate :
Rule.OperandDefConstants) {
emitInstruction(Output, "CheckOperandDefConstantRanges", Predicate.OperandIndex,