//===-- TargetMacroFusion.td - Target Macro Fusion ---------*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the TableGen-based macro fusion classes.
// The target instruction that FusionPredicate will be evaluated on.
class FusionTarget;
def first_fusion_target : FusionTarget;
def second_fusion_target : FusionTarget;
def both_fusion_target : FusionTarget;
// Base class of FusionPredicate, etc. The avaliable variables are:
// * const TargetInstrInfo &TII
// * const TargetSubtargetInfo &STI
// * const MachineRegisterInfo &MRI
// * const MachineInstr *FirstMI
// * const MachineInstr &SecondMI
class FusionPredicate<FusionTarget target> {
FusionTarget Target = target;
}
class FirstFusionPredicate: FusionPredicate<first_fusion_target>;
class SecondFusionPredicate: FusionPredicate<second_fusion_target>;
class BothFusionPredicate: FusionPredicate<both_fusion_target>;
// FusionPredicate with raw code predicate.
class FusionPredicateWithCode<code pred> : FusionPredicate<both_fusion_target> {
code Predicate = pred;
}
// FusionPredicate with MCInstPredicate.
class FusionPredicateWithMCInstPredicate<FusionTarget target, MCInstPredicate pred>
: FusionPredicate<target> {
MCInstPredicate Predicate = pred;
}
class FirstFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
: FusionPredicateWithMCInstPredicate<first_fusion_target, pred>;
class SecondFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
: FusionPredicateWithMCInstPredicate<second_fusion_target, pred>;
// The pred will be applied on both firstMI and secondMI.
class BothFusionPredicateWithMCInstPredicate<MCInstPredicate pred>
: FusionPredicateWithMCInstPredicate<both_fusion_target, pred>;
// Tie firstOpIdx and secondOpIdx. The operand of `FirstMI` at position
// `firstOpIdx` should be the same as the operand of `SecondMI` at position
// `secondOpIdx`.
// If the fusion has `IsCommutable` being true and the operand at `secondOpIdx`
// has commutable operand, then the commutable operand will be checked too.
class TieReg<int firstOpIdx, int secondOpIdx> : BothFusionPredicate {
int FirstOpIdx = firstOpIdx;
int SecondOpIdx = secondOpIdx;
}
// The operand of `SecondMI` at position `firstOpIdx` should be the same as the
// operand at position `secondOpIdx`.
// If the fusion has `IsCommutable` being true and the operand at `secondOpIdx`
// has commutable operand, then the commutable operand will be checked too.
class SameReg<int firstOpIdx, int secondOpIdx> : SecondFusionPredicate {
int FirstOpIdx = firstOpIdx;
int SecondOpIdx = secondOpIdx;
}
// A predicate for wildcard. The generated code will be like:
// ```
// if (!FirstMI)
// return ReturnValue;
// ```
class WildcardPred<bit ret> : FirstFusionPredicate {
bit ReturnValue = ret;
}
def WildcardFalse : WildcardPred<0>;
def WildcardTrue : WildcardPred<1>;
// Indicates that the destination register of `FirstMI` should have one use if
// it is a virtual register.
class OneUsePred : FirstFusionPredicate;
def OneUse : OneUsePred;
// Handled by MacroFusionPredicatorEmitter backend.
// The generated predicator will be like:
// ```
// bool isNAME(const TargetInstrInfo &TII,
// const TargetSubtargetInfo &STI,
// const MachineInstr *FirstMI,
// const MachineInstr &SecondMI) {
// auto &MRI = SecondMI.getMF()->getRegInfo();
// /* Predicates */
// return true;
// }
// ```
//
// `IsCommutable` means whether we should handle commutable operands.
class Fusion<string name, string fieldName, string desc, list<FusionPredicate> predicates>
: SubtargetFeature<name, fieldName, "true", desc> {
list<FusionPredicate> Predicates = predicates;
bit IsCommutable = 0;
}
// The generated predicator will be like:
// ```
// bool isNAME(const TargetInstrInfo &TII,
// const TargetSubtargetInfo &STI,
// const MachineInstr *FirstMI,
// const MachineInstr &SecondMI) {
// auto &MRI = SecondMI.getMF()->getRegInfo();
// /* Prolog */
// /* Predicate for `SecondMI` */
// /* Wildcard */
// /* Predicate for `FirstMI` */
// /* Check same registers */
// /* Check One Use */
// /* Tie registers */
// /* Epilog */
// return true;
// }
// ```
class SimpleFusion<string name, string fieldName, string desc,
MCInstPredicate firstPred, MCInstPredicate secondPred,
list<FusionPredicate> prolog = [],
list<FusionPredicate> epilog = []>
: Fusion<name, fieldName, desc,
!listconcat(
prolog,
[
SecondFusionPredicateWithMCInstPredicate<secondPred>,
WildcardTrue,
FirstFusionPredicateWithMCInstPredicate<firstPred>,
SameReg<0, 1>,
OneUse,
TieReg<0, 1>,
],
epilog)>;
class SingleFusion<string name, string fieldName, string desc,
Instruction firstInst, Instruction secondInst,
MCInstPredicate firstInstPred = TruePred,
MCInstPredicate secondInstPred = TruePred,
list<FusionPredicate> prolog = [],
list<FusionPredicate> epilog = []>
: SimpleFusion<name, fieldName, desc,
CheckAll<!listconcat(
[CheckOpcode<[firstInst]>],
[firstInstPred])>,
CheckAll<!listconcat(
[CheckOpcode<[secondInst]>],
[secondInstPred])>,
prolog, epilog> {
let IsCommutable = secondInst.isCommutable;
}