Initial Commit

This commit is contained in:
Sajid
2024-09-07 18:00:09 +06:00
commit 0f9a53f75a
3352 changed files with 1563708 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
//===- CGPassBuilderOption.h - Options for pass builder ---------*- C++ -*-===//
//
// 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 declares the CCState and CCValAssign classes, used for lowering
// and implementing calling conventions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_CGPASSBUILDEROPTION_H
#define LLVM_TARGET_CGPASSBUILDEROPTION_H
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Target/TargetOptions.h"
namespace llvm {
enum class RunOutliner { TargetDefault, AlwaysOutline, NeverOutline };
enum class RegAllocType { Default, Basic, Fast, Greedy, PBQP };
enum class CFLAAType { None, Steensgaard, Andersen, Both };
// Not one-on-one but mostly corresponding to commandline options in
// TargetPassConfig.cpp.
struct CGPassBuilderOption {
Optional<bool> OptimizeRegAlloc;
Optional<bool> EnableIPRA;
bool DebugPM = false;
bool DisableVerify = false;
bool EnableImplicitNullChecks = false;
bool EnableBlockPlacementStats = false;
bool MISchedPostRA = false;
bool EarlyLiveIntervals = false;
bool DisableLSR = false;
bool DisableCGP = false;
bool PrintLSR = false;
bool DisableMergeICmps = false;
bool DisablePartialLibcallInlining = false;
bool DisableConstantHoisting = false;
bool PrintISelInput = false;
bool PrintGCInfo = false;
bool RequiresCodeGenSCCOrder = false;
RunOutliner EnableMachineOutliner = RunOutliner::TargetDefault;
RegAllocType RegAlloc = RegAllocType::Default;
CFLAAType UseCFLAA = CFLAAType::None;
Optional<GlobalISelAbortMode> EnableGlobalISelAbort;
Optional<bool> VerifyMachineCode;
Optional<bool> EnableFastISelOption;
Optional<bool> EnableGlobalISelOption;
};
CGPassBuilderOption getCGPassBuilderOption();
} // namespace llvm
#endif // LLVM_TARGET_CGPASSBUILDEROPTION_H

View File

@@ -0,0 +1,64 @@
//===- llvm/Target/CodeGenCWrappers.h - CodeGen C Wrappers ------*- C++ -*-===//
//
// 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 C bindings wrappers for enums in llvm/Support/CodeGen.h
// that need them. The wrappers are separated to avoid adding an indirect
// dependency on llvm/Config/Targets.def to CodeGen.h.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_CODEGENCWRAPPERS_H
#define LLVM_TARGET_CODEGENCWRAPPERS_H
#include "llvm-c/TargetMachine.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
inline Optional<CodeModel::Model> unwrap(LLVMCodeModel Model, bool &JIT) {
JIT = false;
switch (Model) {
case LLVMCodeModelJITDefault:
JIT = true;
LLVM_FALLTHROUGH;
case LLVMCodeModelDefault:
return None;
case LLVMCodeModelTiny:
return CodeModel::Tiny;
case LLVMCodeModelSmall:
return CodeModel::Small;
case LLVMCodeModelKernel:
return CodeModel::Kernel;
case LLVMCodeModelMedium:
return CodeModel::Medium;
case LLVMCodeModelLarge:
return CodeModel::Large;
}
return CodeModel::Small;
}
inline LLVMCodeModel wrap(CodeModel::Model Model) {
switch (Model) {
case CodeModel::Tiny:
return LLVMCodeModelTiny;
case CodeModel::Small:
return LLVMCodeModelSmall;
case CodeModel::Kernel:
return LLVMCodeModelKernel;
case CodeModel::Medium:
return LLVMCodeModelMedium;
case CodeModel::Large:
return LLVMCodeModelLarge;
}
llvm_unreachable("Bad CodeModel!");
}
} // namespace llvm
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,910 @@
//===- Combine.td - Combine rule definitions ---------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Declare GlobalISel combine rules and provide mechanisms to opt-out.
//
//===----------------------------------------------------------------------===//
// Common base class for GICombineRule and GICombineGroup.
class GICombine {
// See GICombineGroup. We only declare it here to make the tablegen pass
// simpler.
list<GICombine> Rules = ?;
}
// A group of combine rules that can be added to a GICombiner or another group.
class GICombineGroup<list<GICombine> rules> : GICombine {
// The rules contained in this group. The rules in a group are flattened into
// a single list and sorted into whatever order is most efficient. However,
// they will never be re-ordered such that behaviour differs from the
// specified order. It is therefore possible to use the order of rules in this
// list to describe priorities.
let Rules = rules;
}
class GICombinerHelperArg<string type, string name> {
string Type = type;
string Name = name;
}
// Declares a combiner helper class
class GICombinerHelper<string classname, list<GICombine> rules>
: GICombineGroup<rules> {
// The class name to use in the generated output.
string Classname = classname;
// The name of a run-time compiler option that will be generated to disable
// specific rules within this combiner.
string DisableRuleOption = ?;
// The state class to inherit from (if any). The generated helper will inherit
// from this class and will forward arguments to its constructors.
string StateClass = "";
// Any additional arguments that should be appended to the tryCombine*().
list<GICombinerHelperArg> AdditionalArguments =
[GICombinerHelperArg<"CombinerHelper &", "Helper">];
}
class GICombineRule<dag defs, dag match, dag apply> : GICombine {
/// Defines the external interface of the match rule. This includes:
/// * The names of the root nodes (requires at least one)
/// See GIDefKind for details.
dag Defs = defs;
/// Defines the things which must be true for the pattern to match
/// See GIMatchKind for details.
dag Match = match;
/// Defines the things which happen after the decision is made to apply a
/// combine rule.
/// See GIApplyKind for details.
dag Apply = apply;
}
/// The operator at the root of a GICombineRule.Defs dag.
def defs;
/// All arguments of the defs operator must be subclasses of GIDefKind or
/// sub-dags whose operator is GIDefKindWithArgs.
class GIDefKind;
class GIDefKindWithArgs;
/// Declare a root node. There must be at least one of these in every combine
/// rule.
/// TODO: The plan is to elide `root` definitions and determine it from the DAG
/// itself with an override for situations where the usual determination
/// is incorrect.
def root : GIDefKind;
/// Declares data that is passed from the match stage to the apply stage.
class GIDefMatchData<string type> : GIDefKind {
/// A C++ type name indicating the storage type.
string Type = type;
}
def extending_load_matchdata : GIDefMatchData<"PreferredTuple">;
def indexed_load_store_matchdata : GIDefMatchData<"IndexedLoadStoreMatchInfo">;
def instruction_steps_matchdata: GIDefMatchData<"InstructionStepsMatchInfo">;
/// The operator at the root of a GICombineRule.Match dag.
def match;
/// All arguments of the match operator must be either:
/// * A subclass of GIMatchKind
/// * A subclass of GIMatchKindWithArgs
/// * A subclass of Instruction
/// * A MIR code block (deprecated)
/// The GIMatchKind and GIMatchKindWithArgs cases are described in more detail
/// in their definitions below.
/// For the Instruction case, these are collected into a DAG where operand names
/// that occur multiple times introduce edges.
class GIMatchKind;
class GIMatchKindWithArgs;
/// In lieu of having proper macro support. Trivial one-off opcode checks can be
/// performed with this.
def wip_match_opcode : GIMatchKindWithArgs;
/// The operator at the root of a GICombineRule.Apply dag.
def apply;
/// All arguments of the apply operator must be subclasses of GIApplyKind, or
/// sub-dags whose operator is GIApplyKindWithArgs, or an MIR block
/// (deprecated).
class GIApplyKind;
class GIApplyKindWithArgs;
def register_matchinfo: GIDefMatchData<"Register">;
def int64_matchinfo: GIDefMatchData<"int64_t">;
def apint_matchinfo : GIDefMatchData<"APInt">;
def build_fn_matchinfo :
GIDefMatchData<"std::function<void(MachineIRBuilder &)>">;
def copy_prop : GICombineRule<
(defs root:$d),
(match (COPY $d, $s):$mi,
[{ return Helper.matchCombineCopy(*${mi}); }]),
(apply [{ Helper.applyCombineCopy(*${mi}); }])>;
def extending_loads : GICombineRule<
(defs root:$root, extending_load_matchdata:$matchinfo),
(match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD):$root,
[{ return Helper.matchCombineExtendingLoads(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineExtendingLoads(*${root}, ${matchinfo}); }])>;
def load_and_mask : GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchCombineLoadWithAndMask(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
def combines_for_extload: GICombineGroup<[extending_loads, load_and_mask]>;
def sext_trunc_sextload : GICombineRule<
(defs root:$d),
(match (wip_match_opcode G_SEXT_INREG):$d,
[{ return Helper.matchSextTruncSextLoad(*${d}); }]),
(apply [{ Helper.applySextTruncSextLoad(*${d}); }])>;
def sext_inreg_of_load_matchdata : GIDefMatchData<"std::tuple<Register, unsigned>">;
def sext_inreg_of_load : GICombineRule<
(defs root:$root, sext_inreg_of_load_matchdata:$matchinfo),
(match (wip_match_opcode G_SEXT_INREG):$root,
[{ return Helper.matchSextInRegOfLoad(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applySextInRegOfLoad(*${root}, ${matchinfo}); }])>;
def combine_indexed_load_store : GICombineRule<
(defs root:$root, indexed_load_store_matchdata:$matchinfo),
(match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD, G_STORE):$root,
[{ return Helper.matchCombineIndexedLoadStore(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineIndexedLoadStore(*${root}, ${matchinfo}); }])>;
def opt_brcond_by_inverting_cond_matchdata : GIDefMatchData<"MachineInstr *">;
def opt_brcond_by_inverting_cond : GICombineRule<
(defs root:$root, opt_brcond_by_inverting_cond_matchdata:$matchinfo),
(match (wip_match_opcode G_BR):$root,
[{ return Helper.matchOptBrCondByInvertingCond(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyOptBrCondByInvertingCond(*${root}, ${matchinfo}); }])>;
def ptr_add_immed_matchdata : GIDefMatchData<"PtrAddChain">;
def ptr_add_immed_chain : GICombineRule<
(defs root:$d, ptr_add_immed_matchdata:$matchinfo),
(match (wip_match_opcode G_PTR_ADD):$d,
[{ return Helper.matchPtrAddImmedChain(*${d}, ${matchinfo}); }]),
(apply [{ Helper.applyPtrAddImmedChain(*${d}, ${matchinfo}); }])>;
// Fold shift (shift base x), y -> shift base, (x+y), if shifts are same
def shift_immed_matchdata : GIDefMatchData<"RegisterImmPair">;
def shift_immed_chain : GICombineRule<
(defs root:$d, shift_immed_matchdata:$matchinfo),
(match (wip_match_opcode G_SHL, G_ASHR, G_LSHR, G_SSHLSAT, G_USHLSAT):$d,
[{ return Helper.matchShiftImmedChain(*${d}, ${matchinfo}); }]),
(apply [{ Helper.applyShiftImmedChain(*${d}, ${matchinfo}); }])>;
// Transform shift (logic (shift X, C0), Y), C1
// -> logic (shift X, (C0+C1)), (shift Y, C1), if shifts are same
def shift_of_shifted_logic_matchdata : GIDefMatchData<"ShiftOfShiftedLogic">;
def shift_of_shifted_logic_chain : GICombineRule<
(defs root:$d, shift_of_shifted_logic_matchdata:$matchinfo),
(match (wip_match_opcode G_SHL, G_ASHR, G_LSHR, G_USHLSAT, G_SSHLSAT):$d,
[{ return Helper.matchShiftOfShiftedLogic(*${d}, ${matchinfo}); }]),
(apply [{ Helper.applyShiftOfShiftedLogic(*${d}, ${matchinfo}); }])>;
def mul_to_shl_matchdata : GIDefMatchData<"unsigned">;
def mul_to_shl : GICombineRule<
(defs root:$d, mul_to_shl_matchdata:$matchinfo),
(match (G_MUL $d, $op1, $op2):$mi,
[{ return Helper.matchCombineMulToShl(*${mi}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineMulToShl(*${mi}, ${matchinfo}); }])>;
// shl ([asz]ext x), y => zext (shl x, y), if shift does not overflow int
def reduce_shl_of_extend_matchdata : GIDefMatchData<"RegisterImmPair">;
def reduce_shl_of_extend : GICombineRule<
(defs root:$dst, reduce_shl_of_extend_matchdata:$matchinfo),
(match (G_SHL $dst, $src0, $src1):$mi,
[{ return Helper.matchCombineShlOfExtend(*${mi}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineShlOfExtend(*${mi}, ${matchinfo}); }])>;
def narrow_binop_feeding_and : GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchNarrowBinopFeedingAnd(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
// [us]itofp(undef) = 0, because the result value is bounded.
def undef_to_fp_zero : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_UITOFP, G_SITOFP):$root,
[{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
(apply [{ Helper.replaceInstWithFConstant(*${root}, 0.0); }])>;
def undef_to_int_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_AND, G_MUL):$root,
[{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
(apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>;
def undef_to_negative_one: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_OR):$root,
[{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
(apply [{ Helper.replaceInstWithConstant(*${root}, -1); }])>;
def binop_left_undef_to_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SHL):$root,
[{ return Helper.matchOperandIsUndef(*${root}, 1); }]),
(apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>;
// Instructions where if any source operand is undef, the instruction can be
// replaced with undef.
def propagate_undef_any_op: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_ADD, G_FPTOSI, G_FPTOUI, G_SUB, G_XOR, G_TRUNC):$root,
[{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
(apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
// Instructions where if all source operands are undef, the instruction can be
// replaced with undef.
def propagate_undef_all_ops: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SHUFFLE_VECTOR):$root,
[{ return Helper.matchAllExplicitUsesAreUndef(*${root}); }]),
(apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
// Replace a G_SHUFFLE_VECTOR with an undef mask with a G_IMPLICIT_DEF.
def propagate_undef_shuffle_mask: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SHUFFLE_VECTOR):$root,
[{ return Helper.matchUndefShuffleVectorMask(*${root}); }]),
(apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
// Fold (cond ? x : x) -> x
def select_same_val: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SELECT):$root,
[{ return Helper.matchSelectSameVal(*${root}); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }])
>;
// Fold (undef ? x : y) -> y
def select_undef_cmp: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SELECT):$root,
[{ return Helper.matchUndefSelectCmp(*${root}); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }])
>;
// Fold (true ? x : y) -> x
// Fold (false ? x : y) -> y
def select_constant_cmp_matchdata : GIDefMatchData<"unsigned">;
def select_constant_cmp: GICombineRule<
(defs root:$root, select_constant_cmp_matchdata:$matchinfo),
(match (wip_match_opcode G_SELECT):$root,
[{ return Helper.matchConstantSelectCmp(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, ${matchinfo}); }])
>;
// Fold x op 0 -> x
def right_identity_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SUB, G_ADD, G_OR, G_XOR, G_SHL, G_ASHR, G_LSHR,
G_PTR_ADD, G_ROTL, G_ROTR):$root,
[{ return Helper.matchConstantOp(${root}->getOperand(2), 0); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
// Fold x op 1 -> x
def right_identity_one: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_MUL):$root,
[{ return Helper.matchConstantOp(${root}->getOperand(2), 1); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
// Fold (x op x) - > x
def binop_same_val: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_AND, G_OR):$root,
[{ return Helper.matchBinOpSameVal(*${root}); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
// Fold (0 op x) - > 0
def binop_left_to_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root,
[{ return Helper.matchOperandIsZero(*${root}, 1); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
def urem_pow2_to_mask : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_UREM):$root,
[{ return Helper.matchOperandIsKnownToBeAPowerOfTwo(*${root}, 2); }]),
(apply [{ Helper.applySimplifyURemByPow2(*${root}); }])
>;
// Transform d = [su]div(x, y) and r = [su]rem(x, y) - > d, r = [su]divrem(x, y)
def div_rem_to_divrem_matchdata : GIDefMatchData<"MachineInstr *">;
def div_rem_to_divrem : GICombineRule<
(defs root:$root, div_rem_to_divrem_matchdata:$matchinfo),
(match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root,
[{ return Helper.matchCombineDivRem(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineDivRem(*${root}, ${matchinfo}); }])
>;
// Fold (x op 0) - > 0
def binop_right_to_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_MUL):$root,
[{ return Helper.matchOperandIsZero(*${root}, 2); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }])
>;
// Erase stores of undef values.
def erase_undef_store : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_STORE):$root,
[{ return Helper.matchUndefStore(*${root}); }]),
(apply [{ return Helper.eraseInst(*${root}); }])
>;
def simplify_add_to_sub_matchinfo: GIDefMatchData<"std::tuple<Register, Register>">;
def simplify_add_to_sub: GICombineRule <
(defs root:$root, simplify_add_to_sub_matchinfo:$info),
(match (wip_match_opcode G_ADD):$root,
[{ return Helper.matchSimplifyAddToSub(*${root}, ${info}); }]),
(apply [{ Helper.applySimplifyAddToSub(*${root}, ${info});}])
>;
// Fold fp_op(cst) to the constant result of the floating point operation.
def constant_fp_op_matchinfo: GIDefMatchData<"Optional<APFloat>">;
def constant_fp_op: GICombineRule <
(defs root:$root, constant_fp_op_matchinfo:$info),
(match (wip_match_opcode G_FNEG, G_FABS, G_FPTRUNC, G_FSQRT, G_FLOG2):$root,
[{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineConstantFoldFpUnary(*${root}, ${info}); }])
>;
// Fold int2ptr(ptr2int(x)) -> x
def p2i_to_i2p: GICombineRule<
(defs root:$root, register_matchinfo:$info),
(match (wip_match_opcode G_INTTOPTR):$root,
[{ return Helper.matchCombineI2PToP2I(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineI2PToP2I(*${root}, ${info}); }])
>;
// Fold ptr2int(int2ptr(x)) -> x
def i2p_to_p2i: GICombineRule<
(defs root:$root, register_matchinfo:$info),
(match (wip_match_opcode G_PTRTOINT):$root,
[{ return Helper.matchCombineP2IToI2P(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineP2IToI2P(*${root}, ${info}); }])
>;
// Fold add ptrtoint(x), y -> ptrtoint (ptr_add x), y
def add_p2i_to_ptradd_matchinfo : GIDefMatchData<"std::pair<Register, bool>">;
def add_p2i_to_ptradd : GICombineRule<
(defs root:$root, add_p2i_to_ptradd_matchinfo:$info),
(match (wip_match_opcode G_ADD):$root,
[{ return Helper.matchCombineAddP2IToPtrAdd(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineAddP2IToPtrAdd(*${root}, ${info}); }])
>;
// Fold (ptr_add (int2ptr C1), C2) -> C1 + C2
def const_ptradd_to_i2p_matchinfo : GIDefMatchData<"APInt">;
def const_ptradd_to_i2p: GICombineRule<
(defs root:$root, const_ptradd_to_i2p_matchinfo:$info),
(match (wip_match_opcode G_PTR_ADD):$root,
[{ return Helper.matchCombineConstPtrAddToI2P(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineConstPtrAddToI2P(*${root}, ${info}); }])
>;
// Simplify: (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
def hoist_logic_op_with_same_opcode_hands: GICombineRule <
(defs root:$root, instruction_steps_matchdata:$info),
(match (wip_match_opcode G_AND, G_OR, G_XOR):$root,
[{ return Helper.matchHoistLogicOpWithSameOpcodeHands(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildInstructionSteps(*${root}, ${info});}])
>;
// Fold ashr (shl x, C), C -> sext_inreg (C)
def shl_ashr_to_sext_inreg_matchinfo : GIDefMatchData<"std::tuple<Register, int64_t>">;
def shl_ashr_to_sext_inreg : GICombineRule<
(defs root:$root, shl_ashr_to_sext_inreg_matchinfo:$info),
(match (wip_match_opcode G_ASHR): $root,
[{ return Helper.matchAshrShlToSextInreg(*${root}, ${info}); }]),
(apply [{ Helper.applyAshShlToSextInreg(*${root}, ${info});}])
>;
// Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0
def overlapping_and: GICombineRule <
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchOverlappingAnd(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])
>;
// Fold (x & y) -> x or (x & y) -> y when (x & y) is known to equal x or equal y.
def redundant_and: GICombineRule <
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchRedundantAnd(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// Fold (x | y) -> x or (x | y) -> y when (x | y) is known to equal x or equal y.
def redundant_or: GICombineRule <
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_OR):$root,
[{ return Helper.matchRedundantOr(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// If the input is already sign extended, just drop the extension.
// sext_inreg x, K ->
// if computeNumSignBits(x) >= (x.getScalarSizeInBits() - K + 1)
def redundant_sext_inreg: GICombineRule <
(defs root:$root),
(match (wip_match_opcode G_SEXT_INREG):$root,
[{ return Helper.matchRedundantSExtInReg(*${root}); }]),
(apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
// Fold (anyext (trunc x)) -> x if the source type is same as
// the destination type.
def anyext_trunc_fold: GICombineRule <
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_ANYEXT):$root,
[{ return Helper.matchCombineAnyExtTrunc(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// Fold (zext (trunc x)) -> x if the source type is same as the destination type
// and truncated bits are known to be zero.
def zext_trunc_fold_matchinfo : GIDefMatchData<"Register">;
def zext_trunc_fold: GICombineRule <
(defs root:$root, zext_trunc_fold_matchinfo:$matchinfo),
(match (wip_match_opcode G_ZEXT):$root,
[{ return Helper.matchCombineZextTrunc(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// Fold ([asz]ext ([asz]ext x)) -> ([asz]ext x).
def ext_ext_fold_matchinfo : GIDefMatchData<"std::tuple<Register, unsigned>">;
def ext_ext_fold: GICombineRule <
(defs root:$root, ext_ext_fold_matchinfo:$matchinfo),
(match (wip_match_opcode G_ANYEXT, G_SEXT, G_ZEXT):$root,
[{ return Helper.matchCombineExtOfExt(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineExtOfExt(*${root}, ${matchinfo}); }])
>;
def not_cmp_fold_matchinfo : GIDefMatchData<"SmallVector<Register, 4>">;
def not_cmp_fold : GICombineRule<
(defs root:$d, not_cmp_fold_matchinfo:$info),
(match (wip_match_opcode G_XOR): $d,
[{ return Helper.matchNotCmp(*${d}, ${info}); }]),
(apply [{ Helper.applyNotCmp(*${d}, ${info}); }])
>;
// Fold (fneg (fneg x)) -> x.
def fneg_fneg_fold: GICombineRule <
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_FNEG):$root,
[{ return Helper.matchCombineFNegOfFNeg(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// Fold (unmerge(merge x, y, z)) -> z, y, z.
def unmerge_merge_matchinfo : GIDefMatchData<"SmallVector<Register, 8>">;
def unmerge_merge : GICombineRule<
(defs root:$d, unmerge_merge_matchinfo:$info),
(match (wip_match_opcode G_UNMERGE_VALUES): $d,
[{ return Helper.matchCombineUnmergeMergeToPlainValues(*${d}, ${info}); }]),
(apply [{ Helper.applyCombineUnmergeMergeToPlainValues(*${d}, ${info}); }])
>;
// Fold merge(unmerge).
def merge_unmerge : GICombineRule<
(defs root:$d, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_MERGE_VALUES):$d,
[{ return Helper.matchCombineMergeUnmerge(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceSingleDefInstWithReg(*${d}, ${matchinfo}); }])
>;
// Fold (fabs (fabs x)) -> (fabs x).
def fabs_fabs_fold: GICombineRule<
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_FABS):$root,
[{ return Helper.matchCombineFAbsOfFAbs(*${root}, ${matchinfo}); }]),
(apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }])
>;
// Fold (fabs (fneg x)) -> (fabs x).
def fabs_fneg_fold: GICombineRule <
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_FABS):$root,
[{ return Helper.matchCombineFAbsOfFNeg(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
// Fold (unmerge cst) -> cst1, cst2, ...
def unmerge_cst_matchinfo : GIDefMatchData<"SmallVector<APInt, 8>">;
def unmerge_cst : GICombineRule<
(defs root:$d, unmerge_cst_matchinfo:$info),
(match (wip_match_opcode G_UNMERGE_VALUES): $d,
[{ return Helper.matchCombineUnmergeConstant(*${d}, ${info}); }]),
(apply [{ Helper.applyCombineUnmergeConstant(*${d}, ${info}); }])
>;
// Fold (unmerge undef) -> undef, undef, ...
def unmerge_undef : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_UNMERGE_VALUES): $root,
[{ return Helper.matchCombineUnmergeUndef(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])
>;
// Transform x,y<dead> = unmerge z -> x = trunc z.
def unmerge_dead_to_trunc : GICombineRule<
(defs root:$d),
(match (wip_match_opcode G_UNMERGE_VALUES): $d,
[{ return Helper.matchCombineUnmergeWithDeadLanesToTrunc(*${d}); }]),
(apply [{ Helper.applyCombineUnmergeWithDeadLanesToTrunc(*${d}); }])
>;
// Transform x,y = unmerge(zext(z)) -> x = zext z; y = 0.
def unmerge_zext_to_zext : GICombineRule<
(defs root:$d),
(match (wip_match_opcode G_UNMERGE_VALUES): $d,
[{ return Helper.matchCombineUnmergeZExtToZExt(*${d}); }]),
(apply [{ Helper.applyCombineUnmergeZExtToZExt(*${d}); }])
>;
// Fold trunc ([asz]ext x) -> x or ([asz]ext x) or (trunc x).
def trunc_ext_fold_matchinfo : GIDefMatchData<"std::pair<Register, unsigned>">;
def trunc_ext_fold: GICombineRule <
(defs root:$root, trunc_ext_fold_matchinfo:$matchinfo),
(match (wip_match_opcode G_TRUNC):$root,
[{ return Helper.matchCombineTruncOfExt(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineTruncOfExt(*${root}, ${matchinfo}); }])
>;
// Fold trunc (shl x, K) -> shl (trunc x), K => K < VT.getScalarSizeInBits().
def trunc_shl_matchinfo : GIDefMatchData<"std::pair<Register, Register>">;
def trunc_shl: GICombineRule <
(defs root:$root, trunc_shl_matchinfo:$matchinfo),
(match (wip_match_opcode G_TRUNC):$root,
[{ return Helper.matchCombineTruncOfShl(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyCombineTruncOfShl(*${root}, ${matchinfo}); }])
>;
// Transform (mul x, -1) -> (sub 0, x)
def mul_by_neg_one: GICombineRule <
(defs root:$root),
(match (wip_match_opcode G_MUL):$root,
[{ return Helper.matchConstantOp(${root}->getOperand(2), -1); }]),
(apply [{ Helper.applyCombineMulByNegativeOne(*${root}); }])
>;
// Fold (xor (and x, y), y) -> (and (not x), y)
def xor_of_and_with_same_reg_matchinfo :
GIDefMatchData<"std::pair<Register, Register>">;
def xor_of_and_with_same_reg: GICombineRule <
(defs root:$root, xor_of_and_with_same_reg_matchinfo:$matchinfo),
(match (wip_match_opcode G_XOR):$root,
[{ return Helper.matchXorOfAndWithSameReg(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyXorOfAndWithSameReg(*${root}, ${matchinfo}); }])
>;
// Transform (ptr_add 0, x) -> (int_to_ptr x)
def ptr_add_with_zero: GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_PTR_ADD):$root,
[{ return Helper.matchPtrAddZero(*${root}); }]),
(apply [{ Helper.applyPtrAddZero(*${root}); }])>;
def regs_small_vec : GIDefMatchData<"SmallVector<Register, 4>">;
def combine_insert_vec_elts_build_vector : GICombineRule<
(defs root:$root, regs_small_vec:$info),
(match (wip_match_opcode G_INSERT_VECTOR_ELT):$root,
[{ return Helper.matchCombineInsertVecElts(*${root}, ${info}); }]),
(apply [{ Helper.applyCombineInsertVecElts(*${root}, ${info}); }])>;
def load_or_combine : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_OR):$root,
[{ return Helper.matchLoadOrCombine(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def truncstore_merge_matcdata : GIDefMatchData<"MergeTruncStoresInfo">;
def truncstore_merge : GICombineRule<
(defs root:$root, truncstore_merge_matcdata:$info),
(match (wip_match_opcode G_STORE):$root,
[{ return Helper.matchTruncStoreMerge(*${root}, ${info}); }]),
(apply [{ Helper.applyTruncStoreMerge(*${root}, ${info}); }])>;
def extend_through_phis_matchdata: GIDefMatchData<"MachineInstr*">;
def extend_through_phis : GICombineRule<
(defs root:$root, extend_through_phis_matchdata:$matchinfo),
(match (wip_match_opcode G_PHI):$root,
[{ return Helper.matchExtendThroughPhis(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyExtendThroughPhis(*${root}, ${matchinfo}); }])>;
// Currently only the one combine above.
def insert_vec_elt_combines : GICombineGroup<
[combine_insert_vec_elts_build_vector]>;
def extract_vec_elt_build_vec : GICombineRule<
(defs root:$root, register_matchinfo:$matchinfo),
(match (wip_match_opcode G_EXTRACT_VECTOR_ELT):$root,
[{ return Helper.matchExtractVecEltBuildVec(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyExtractVecEltBuildVec(*${root}, ${matchinfo}); }])>;
// Fold away full elt extracts from a build_vector.
def extract_all_elts_from_build_vector_matchinfo :
GIDefMatchData<"SmallVector<std::pair<Register, MachineInstr*>>">;
def extract_all_elts_from_build_vector : GICombineRule<
(defs root:$root, extract_all_elts_from_build_vector_matchinfo:$matchinfo),
(match (wip_match_opcode G_BUILD_VECTOR):$root,
[{ return Helper.matchExtractAllEltsFromBuildVector(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyExtractAllEltsFromBuildVector(*${root}, ${matchinfo}); }])>;
def extract_vec_elt_combines : GICombineGroup<[
extract_vec_elt_build_vec,
extract_all_elts_from_build_vector]>;
def funnel_shift_from_or_shift : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_OR):$root,
[{ return Helper.matchOrShiftToFunnelShift(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])
>;
def funnel_shift_to_rotate : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_FSHL, G_FSHR):$root,
[{ return Helper.matchFunnelShiftToRotate(*${root}); }]),
(apply [{ Helper.applyFunnelShiftToRotate(*${root}); }])
>;
def rotate_out_of_range : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_ROTR, G_ROTL):$root,
[{ return Helper.matchRotateOutOfRange(*${root}); }]),
(apply [{ Helper.applyRotateOutOfRange(*${root}); }])
>;
def icmp_to_true_false_known_bits : GICombineRule<
(defs root:$d, int64_matchinfo:$matchinfo),
(match (wip_match_opcode G_ICMP):$d,
[{ return Helper.matchICmpToTrueFalseKnownBits(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>;
def icmp_to_lhs_known_bits : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_ICMP):$root,
[{ return Helper.matchICmpToLHSKnownBits(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def and_or_disjoint_mask : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchAndOrDisjointMask(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${info}); }])>;
def bitfield_extract_from_and : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_AND):$root,
[{ return Helper.matchBitfieldExtractFromAnd(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def funnel_shift_combines : GICombineGroup<[funnel_shift_from_or_shift,
funnel_shift_to_rotate]>;
def bitfield_extract_from_sext_inreg : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_SEXT_INREG):$root,
[{ return Helper.matchBitfieldExtractFromSExtInReg(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def bitfield_extract_from_shr : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_ASHR, G_LSHR):$root,
[{ return Helper.matchBitfieldExtractFromShr(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def bitfield_extract_from_shr_and : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_ASHR, G_LSHR):$root,
[{ return Helper.matchBitfieldExtractFromShrAnd(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
def form_bitfield_extract : GICombineGroup<[bitfield_extract_from_sext_inreg,
bitfield_extract_from_and,
bitfield_extract_from_shr,
bitfield_extract_from_shr_and]>;
def udiv_by_const : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_UDIV):$root,
[{ return Helper.matchUDivByConst(*${root}); }]),
(apply [{ Helper.applyUDivByConst(*${root}); }])>;
def intdiv_combines : GICombineGroup<[udiv_by_const]>;
def reassoc_ptradd : GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_PTR_ADD):$root,
[{ return Helper.matchReassocPtrAdd(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
def reassocs : GICombineGroup<[reassoc_ptradd]>;
// Constant fold operations.
def constant_fold : GICombineRule<
(defs root:$d, apint_matchinfo:$matchinfo),
(match (wip_match_opcode G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR):$d,
[{ return Helper.matchConstantFold(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>;
def mulo_by_2: GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_UMULO, G_SMULO):$root,
[{ return Helper.matchMulOBy2(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
def mulh_to_lshr : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_UMULH):$root,
[{ return Helper.matchUMulHToLShr(*${root}); }]),
(apply [{ Helper.applyUMulHToLShr(*${root}); }])>;
def mulh_combines : GICombineGroup<[mulh_to_lshr]>;
def redundant_neg_operands: GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMAD, G_FMA):$root,
[{ return Helper.matchRedundantNegOperands(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>;
// Transform (fadd x, (fmul y, z)) -> (fma y, z, x)
// (fadd x, (fmul y, z)) -> (fmad y, z, x)
// Transform (fadd (fmul x, y), z) -> (fma x, y, z)
// (fadd (fmul x, y), z) -> (fmad x, y, z)
def combine_fadd_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FADD):$root,
[{ return Helper.matchCombineFAddFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z)
// -> (fmad (fpext x), (fpext y), z)
// Transform (fadd x, (fpext (fmul y, z))) -> (fma (fpext y), (fpext z), x)
// -> (fmad (fpext y), (fpext z), x)
def combine_fadd_fpext_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FADD):$root,
[{ return Helper.matchCombineFAddFpExtFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fadd (fma x, y, (fmul z, u)), v) -> (fma x, y, (fma z, u, v))
// (fadd (fmad x, y, (fmul z, u)), v) -> (fmad x, y, (fmad z, u, v))
// Transform (fadd v, (fma x, y, (fmul z, u))) -> (fma x, y, (fma z, u, v))
// (fadd v, (fmad x, y, (fmul z, u))) -> (fmad x, y, (fmad z, u, v))
def combine_fadd_fma_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FADD):$root,
[{ return Helper.matchCombineFAddFMAFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fadd (fma x, y, (fpext (fmul u, v))), z) ->
// (fma x, y, (fma (fpext u), (fpext v), z))
def combine_fadd_fpext_fma_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FADD):$root,
[{ return Helper.matchCombineFAddFpExtFMulToFMadOrFMAAggressive(
*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fsub (fmul x, y), z) -> (fma x, y, -z)
// -> (fmad x, y, -z)
def combine_fsub_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FSUB):$root,
[{ return Helper.matchCombineFSubFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z))
// (fsub x, (fneg (fmul, y, z))) -> (fma y, z, x)
def combine_fsub_fneg_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FSUB):$root,
[{ return Helper.matchCombineFSubFNegFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fsub (fpext (fmul x, y)), z) ->
// (fma (fpext x), (fpext y), (fneg z))
def combine_fsub_fpext_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FSUB):$root,
[{ return Helper.matchCombineFSubFpExtFMulToFMadOrFMA(*${root},
${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// Transform (fsub (fneg (fpext (fmul x, y))), z) ->
// (fneg (fma (fpext x), (fpext y), z))
def combine_fsub_fpext_fneg_fmul_to_fmad_or_fma: GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_FSUB):$root,
[{ return Helper.matchCombineFSubFpExtFNegFMulToFMadOrFMA(
*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
// FIXME: These should use the custom predicate feature once it lands.
def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
undef_to_negative_one,
binop_left_undef_to_zero,
propagate_undef_any_op,
propagate_undef_all_ops,
propagate_undef_shuffle_mask,
erase_undef_store,
unmerge_undef]>;
def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
binop_same_val, binop_left_to_zero,
binop_right_to_zero, p2i_to_i2p,
i2p_to_p2i, anyext_trunc_fold,
fneg_fneg_fold, right_identity_one]>;
def const_combines : GICombineGroup<[constant_fp_op, const_ptradd_to_i2p,
overlapping_and, mulo_by_2]>;
def known_bits_simplifications : GICombineGroup<[
redundant_and, redundant_sext_inreg, redundant_or, urem_pow2_to_mask,
zext_trunc_fold, icmp_to_true_false_known_bits, icmp_to_lhs_known_bits]>;
def width_reduction_combines : GICombineGroup<[reduce_shl_of_extend,
narrow_binop_feeding_and]>;
def phi_combines : GICombineGroup<[extend_through_phis]>;
def select_combines : GICombineGroup<[select_undef_cmp, select_constant_cmp]>;
def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl, add_p2i_to_ptradd,
mul_by_neg_one]>;
def fma_combines : GICombineGroup<[combine_fadd_fmul_to_fmad_or_fma,
combine_fadd_fpext_fmul_to_fmad_or_fma, combine_fadd_fma_fmul_to_fmad_or_fma,
combine_fadd_fpext_fma_fmul_to_fmad_or_fma, combine_fsub_fmul_to_fmad_or_fma,
combine_fsub_fneg_fmul_to_fmad_or_fma, combine_fsub_fpext_fmul_to_fmad_or_fma,
combine_fsub_fpext_fneg_fmul_to_fmad_or_fma]>;
def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines,
extract_vec_elt_combines, combines_for_extload,
combine_indexed_load_store, undef_combines, identity_combines, phi_combines,
simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands,
reassocs, ptr_add_immed_chain,
shl_ashr_to_sext_inreg, sext_inreg_of_load,
width_reduction_combines, select_combines,
known_bits_simplifications, ext_ext_fold,
not_cmp_fold, opt_brcond_by_inverting_cond,
unmerge_merge, fabs_fabs_fold, unmerge_cst, unmerge_dead_to_trunc,
unmerge_zext_to_zext, merge_unmerge, trunc_ext_fold, trunc_shl,
const_combines, xor_of_and_with_same_reg, ptr_add_with_zero,
shift_immed_chain, shift_of_shifted_logic_chain, load_or_combine,
truncstore_merge, div_rem_to_divrem, funnel_shift_combines,
form_bitfield_extract, constant_fold, fabs_fneg_fold,
intdiv_combines, mulh_combines, redundant_neg_operands,
and_or_disjoint_mask, fma_combines]>;
// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
// compile time performance.
def optnone_combines : GICombineGroup<[trivial_combines,
ptr_add_immed_chain, combines_for_extload,
not_cmp_fold, opt_brcond_by_inverting_cond]>;

View File

@@ -0,0 +1,15 @@
//===- RegisterBank.td - Register bank definitions ---------*- 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
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
class RegisterBank<string name, list<RegisterClass> classes> {
string Name = name;
list<RegisterClass> RegisterClasses = classes;
}

View File

@@ -0,0 +1,221 @@
//===- TargetGlobalISel.td - Common code for GlobalISel ----*- 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 target-independent interfaces used to support
// SelectionDAG instruction selection patterns (specified in
// TargetSelectionDAG.td) when generating GlobalISel instruction selectors.
//
// This is intended as a compatibility layer, to enable reuse of target
// descriptions written for SelectionDAG without requiring explicit GlobalISel
// support. It will eventually supersede SelectionDAG patterns.
//
//===----------------------------------------------------------------------===//
// Declare that a generic Instruction is 'equivalent' to an SDNode, that is,
// SelectionDAG patterns involving the SDNode can be transformed to match the
// Instruction instead.
class GINodeEquiv<Instruction i, SDNode node> {
Instruction I = i;
SDNode Node = node;
// SelectionDAG has separate nodes for atomic and non-atomic memory operations
// (ISD::LOAD, ISD::ATOMIC_LOAD, ISD::STORE, ISD::ATOMIC_STORE) but GlobalISel
// stores this information in the MachineMemoryOperand.
bit CheckMMOIsNonAtomic = false;
bit CheckMMOIsAtomic = false;
// SelectionDAG has one node for all loads and uses predicates to
// differentiate them. GlobalISel on the other hand uses separate opcodes.
// When this is true, the resulting opcode is G_LOAD/G_SEXTLOAD/G_ZEXTLOAD
// depending on the predicates on the node.
Instruction IfSignExtend = ?;
Instruction IfZeroExtend = ?;
// SelectionDAG has one setcc for all compares. This differentiates
// for G_ICMP and G_FCMP.
Instruction IfFloatingPoint = ?;
}
// These are defined in the same order as the G_* instructions.
def : GINodeEquiv<G_ANYEXT, anyext>;
def : GINodeEquiv<G_SEXT, sext>;
def : GINodeEquiv<G_ZEXT, zext>;
def : GINodeEquiv<G_TRUNC, trunc>;
def : GINodeEquiv<G_BITCAST, bitconvert>;
// G_INTTOPTR - SelectionDAG has no equivalent.
// G_PTRTOINT - SelectionDAG has no equivalent.
def : GINodeEquiv<G_CONSTANT, imm>;
// timm must not be materialized and therefore has no GlobalISel equivalent
def : GINodeEquiv<G_FCONSTANT, fpimm>;
def : GINodeEquiv<G_IMPLICIT_DEF, undef>;
def : GINodeEquiv<G_FRAME_INDEX, frameindex>;
def : GINodeEquiv<G_BLOCK_ADDR, blockaddress>;
def : GINodeEquiv<G_ADD, add>;
def : GINodeEquiv<G_SUB, sub>;
def : GINodeEquiv<G_MUL, mul>;
def : GINodeEquiv<G_UMULH, mulhu>;
def : GINodeEquiv<G_SMULH, mulhs>;
def : GINodeEquiv<G_SDIV, sdiv>;
def : GINodeEquiv<G_UDIV, udiv>;
def : GINodeEquiv<G_SREM, srem>;
def : GINodeEquiv<G_UREM, urem>;
def : GINodeEquiv<G_AND, and>;
def : GINodeEquiv<G_OR, or>;
def : GINodeEquiv<G_XOR, xor>;
def : GINodeEquiv<G_SHL, shl>;
def : GINodeEquiv<G_LSHR, srl>;
def : GINodeEquiv<G_ASHR, sra>;
def : GINodeEquiv<G_SADDSAT, saddsat>;
def : GINodeEquiv<G_UADDSAT, uaddsat>;
def : GINodeEquiv<G_SSUBSAT, ssubsat>;
def : GINodeEquiv<G_USUBSAT, usubsat>;
def : GINodeEquiv<G_SSHLSAT, sshlsat>;
def : GINodeEquiv<G_USHLSAT, ushlsat>;
def : GINodeEquiv<G_SMULFIX, smulfix>;
def : GINodeEquiv<G_UMULFIX, umulfix>;
def : GINodeEquiv<G_SMULFIXSAT, smulfixsat>;
def : GINodeEquiv<G_UMULFIXSAT, umulfixsat>;
def : GINodeEquiv<G_SDIVFIX, sdivfix>;
def : GINodeEquiv<G_UDIVFIX, udivfix>;
def : GINodeEquiv<G_SDIVFIXSAT, sdivfixsat>;
def : GINodeEquiv<G_UDIVFIXSAT, udivfixsat>;
def : GINodeEquiv<G_SELECT, select>;
def : GINodeEquiv<G_FNEG, fneg>;
def : GINodeEquiv<G_FPEXT, fpextend>;
def : GINodeEquiv<G_FPTRUNC, fpround>;
def : GINodeEquiv<G_FPTOSI, fp_to_sint>;
def : GINodeEquiv<G_FPTOUI, fp_to_uint>;
def : GINodeEquiv<G_SITOFP, sint_to_fp>;
def : GINodeEquiv<G_UITOFP, uint_to_fp>;
def : GINodeEquiv<G_FADD, fadd>;
def : GINodeEquiv<G_FSUB, fsub>;
def : GINodeEquiv<G_FMA, fma>;
def : GINodeEquiv<G_FMAD, fmad>;
def : GINodeEquiv<G_FMUL, fmul>;
def : GINodeEquiv<G_FDIV, fdiv>;
def : GINodeEquiv<G_FREM, frem>;
def : GINodeEquiv<G_FPOW, fpow>;
def : GINodeEquiv<G_FEXP2, fexp2>;
def : GINodeEquiv<G_FLOG2, flog2>;
def : GINodeEquiv<G_FCANONICALIZE, fcanonicalize>;
def : GINodeEquiv<G_INTRINSIC, intrinsic_wo_chain>;
// ISD::INTRINSIC_VOID can also be handled with G_INTRINSIC_W_SIDE_EFFECTS.
def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_void>;
def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_w_chain>;
def : GINodeEquiv<G_BR, br>;
def : GINodeEquiv<G_BSWAP, bswap>;
def : GINodeEquiv<G_BITREVERSE, bitreverse>;
def : GINodeEquiv<G_FSHL, fshl>;
def : GINodeEquiv<G_FSHR, fshr>;
def : GINodeEquiv<G_CTLZ, ctlz>;
def : GINodeEquiv<G_CTTZ, cttz>;
def : GINodeEquiv<G_CTLZ_ZERO_UNDEF, ctlz_zero_undef>;
def : GINodeEquiv<G_CTTZ_ZERO_UNDEF, cttz_zero_undef>;
def : GINodeEquiv<G_CTPOP, ctpop>;
def : GINodeEquiv<G_EXTRACT_VECTOR_ELT, extractelt>;
def : GINodeEquiv<G_CONCAT_VECTORS, concat_vectors>;
def : GINodeEquiv<G_BUILD_VECTOR, build_vector>;
def : GINodeEquiv<G_FCEIL, fceil>;
def : GINodeEquiv<G_FCOS, fcos>;
def : GINodeEquiv<G_FSIN, fsin>;
def : GINodeEquiv<G_FABS, fabs>;
def : GINodeEquiv<G_FSQRT, fsqrt>;
def : GINodeEquiv<G_FFLOOR, ffloor>;
def : GINodeEquiv<G_FRINT, frint>;
def : GINodeEquiv<G_FNEARBYINT, fnearbyint>;
def : GINodeEquiv<G_INTRINSIC_TRUNC, ftrunc>;
def : GINodeEquiv<G_INTRINSIC_ROUND, fround>;
def : GINodeEquiv<G_INTRINSIC_LRINT, lrint>;
def : GINodeEquiv<G_FCOPYSIGN, fcopysign>;
def : GINodeEquiv<G_SMIN, smin>;
def : GINodeEquiv<G_SMAX, smax>;
def : GINodeEquiv<G_UMIN, umin>;
def : GINodeEquiv<G_UMAX, umax>;
def : GINodeEquiv<G_ABS, abs>;
def : GINodeEquiv<G_FMINNUM, fminnum>;
def : GINodeEquiv<G_FMAXNUM, fmaxnum>;
def : GINodeEquiv<G_FMINNUM_IEEE, fminnum_ieee>;
def : GINodeEquiv<G_FMAXNUM_IEEE, fmaxnum_ieee>;
def : GINodeEquiv<G_READCYCLECOUNTER, readcyclecounter>;
def : GINodeEquiv<G_ROTR, rotr>;
def : GINodeEquiv<G_ROTL, rotl>;
def : GINodeEquiv<G_LROUND, lround>;
def : GINodeEquiv<G_LLROUND, llround>;
def : GINodeEquiv<G_STRICT_FADD, strict_fadd>;
def : GINodeEquiv<G_STRICT_FSUB, strict_fsub>;
def : GINodeEquiv<G_STRICT_FMUL, strict_fmul>;
def : GINodeEquiv<G_STRICT_FDIV, strict_fdiv>;
def : GINodeEquiv<G_STRICT_FREM, strict_frem>;
def : GINodeEquiv<G_STRICT_FMA, strict_fma>;
def : GINodeEquiv<G_STRICT_FSQRT, strict_fsqrt>;
// Broadly speaking G_LOAD is equivalent to ISD::LOAD but there are some
// complications that tablegen must take care of. For example, Predicates such
// as isSignExtLoad require that this is not a perfect 1:1 mapping since a
// sign-extending load is (G_SEXTLOAD x) in GlobalISel. Additionally,
// G_LOAD handles both atomic and non-atomic loads where as SelectionDAG had
// separate nodes for them. This GINodeEquiv maps the non-atomic loads to
// G_LOAD with a non-atomic MachineMemOperand.
def : GINodeEquiv<G_LOAD, ld> {
let CheckMMOIsNonAtomic = true;
let IfSignExtend = G_SEXTLOAD;
let IfZeroExtend = G_ZEXTLOAD;
}
def : GINodeEquiv<G_ICMP, setcc> {
let IfFloatingPoint = G_FCMP;
}
// Broadly speaking G_STORE is equivalent to ISD::STORE but there are some
// complications that tablegen must take care of. For example, predicates such
// as isTruncStore require that this is not a perfect 1:1 mapping since a
// truncating store is (G_STORE (G_TRUNCATE x)) in GlobalISel. Additionally,
// G_STORE handles both atomic and non-atomic stores where as SelectionDAG had
// separate nodes for them. This GINodeEquiv maps the non-atomic stores to
// G_STORE with a non-atomic MachineMemOperand.
def : GINodeEquiv<G_STORE, st> { let CheckMMOIsNonAtomic = true; }
def : GINodeEquiv<G_LOAD, atomic_load> {
let CheckMMOIsNonAtomic = false;
let CheckMMOIsAtomic = true;
}
// Operands are swapped for atomic_store vs. regular store
def : GINodeEquiv<G_STORE, atomic_store> {
let CheckMMOIsNonAtomic = false;
let CheckMMOIsAtomic = true;
}
def : GINodeEquiv<G_ATOMIC_CMPXCHG, atomic_cmp_swap>;
def : GINodeEquiv<G_ATOMICRMW_XCHG, atomic_swap>;
def : GINodeEquiv<G_ATOMICRMW_ADD, atomic_load_add>;
def : GINodeEquiv<G_ATOMICRMW_SUB, atomic_load_sub>;
def : GINodeEquiv<G_ATOMICRMW_AND, atomic_load_and>;
def : GINodeEquiv<G_ATOMICRMW_NAND, atomic_load_nand>;
def : GINodeEquiv<G_ATOMICRMW_OR, atomic_load_or>;
def : GINodeEquiv<G_ATOMICRMW_XOR, atomic_load_xor>;
def : GINodeEquiv<G_ATOMICRMW_MIN, atomic_load_min>;
def : GINodeEquiv<G_ATOMICRMW_MAX, atomic_load_max>;
def : GINodeEquiv<G_ATOMICRMW_UMIN, atomic_load_umin>;
def : GINodeEquiv<G_ATOMICRMW_UMAX, atomic_load_umax>;
def : GINodeEquiv<G_ATOMICRMW_FADD, atomic_load_fadd>;
def : GINodeEquiv<G_ATOMICRMW_FSUB, atomic_load_fsub>;
def : GINodeEquiv<G_FENCE, atomic_fence>;
// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
// Should be used on defs that subclass GIComplexOperandMatcher<>.
class GIComplexPatternEquiv<ComplexPattern seldag> {
ComplexPattern SelDAGEquivalent = seldag;
}
// Specifies the GlobalISel equivalents for SelectionDAG's SDNodeXForm.
// Should be used on defs that subclass GICustomOperandRenderer<>.
class GISDNodeXFormEquiv<SDNodeXForm seldag> {
SDNodeXForm SelDAGEquivalent = seldag;
}

View File

@@ -0,0 +1,65 @@
//===- Target.td - Define GlobalISel rules -----------------*- 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 target-independent interfaces used to support
// SelectionDAG instruction selection patterns (specified in
// TargetSelectionDAG.td) when generating GlobalISel instruction selectors.
//
// This is intended as a compatibility layer, to enable reuse of target
// descriptions written for SelectionDAG without requiring explicit GlobalISel
// support. It will eventually supersede SelectionDAG patterns.
//
//===----------------------------------------------------------------------===//
// Definitions that inherit from LLT define types that will be used in the
// GlobalISel matcher.
class LLT;
def s32 : LLT;
def s64 : LLT;
// Defines a matcher for complex operands. This is analogous to ComplexPattern
// from SelectionDAG.
//
// Definitions that inherit from this may also inherit from
// GIComplexPatternEquiv to enable the import of SelectionDAG patterns involving
// those ComplexPatterns.
class GIComplexOperandMatcher<LLT type, string matcherfn> {
// The expected type of the root of the match.
//
// TODO: We should probably support, any-type, any-scalar, and multiple types
// in the future.
LLT Type = type;
// The function that determines whether the operand matches. It should be of
// the form:
// ComplexRendererFn select(MachineOperand &Root) const;
// where Root is the root of the match. The function should return nullptr
// on match failure, or a ComplexRendererFn that renders the operand in case
// of a successful match.
string MatcherFn = matcherfn;
}
// Defines a custom renderer. This is analogous to SDNodeXForm from
// SelectionDAG. Unlike SDNodeXForm, this matches a MachineInstr and
// renders directly to the result instruction without an intermediate node.
//
// Definitions that inherit from this may also inherit from GISDNodeXFormEquiv
// to enable the import of SelectionDAG patterns involving those SDNodeXForms.
class GICustomOperandRenderer<string rendererfn> {
// The function renders the operand(s) of the matched instruction to
// the specified instruction. It should be of the form:
// void render(MachineInstrBuilder &MIB, const MachineInstr &MI,
// int OpIdx = -1)
//
// If OpIdx is specified (i.e. not invalid/negative), this
// references the source operand MI.getOperand(OpIdx). Otherwise,
// this is the value defined by MI. This is to support the case
// where there is no corresponding instruction to match.
string RendererFn = rendererfn;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
//===- TargetCallingConv.td - Target Calling Conventions ---*- 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 target-independent interfaces with which targets
// describe their calling conventions.
//
//===----------------------------------------------------------------------===//
class CCAction;
class CallingConv;
/// CCCustom - Calls a custom arg handling function.
class CCCustom<string fn> : CCAction {
string FuncName = fn;
}
/// CCPredicateAction - Instances of this class check some predicate, then
/// delegate to another action if the predicate is true.
class CCPredicateAction<CCAction A> : CCAction {
CCAction SubAction = A;
}
/// CCIfType - If the current argument is one of the specified types, apply
/// Action A.
class CCIfType<list<ValueType> vts, CCAction A> : CCPredicateAction<A> {
list<ValueType> VTs = vts;
}
/// CCIf - If the predicate matches, apply A.
class CCIf<string predicate, CCAction A> : CCPredicateAction<A> {
string Predicate = predicate;
}
/// CCIfByVal - If the current argument has ByVal parameter attribute, apply
/// Action A.
class CCIfByVal<CCAction A> : CCIf<"ArgFlags.isByVal()", A> {
}
/// CCIfPreallocated - If the current argument has Preallocated parameter attribute,
/// apply Action A.
class CCIfPreallocated<CCAction A> : CCIf<"ArgFlags.isPreallocated()", A> {
}
/// CCIfSwiftSelf - If the current argument has swiftself parameter attribute,
/// apply Action A.
class CCIfSwiftSelf<CCAction A> : CCIf<"ArgFlags.isSwiftSelf()", A> {
}
/// CCIfSwiftAsync - If the current argument has swiftasync parameter attribute,
/// apply Action A.
class CCIfSwiftAsync<CCAction A> : CCIf<"ArgFlags.isSwiftAsync()", A> {
}
/// CCIfSwiftError - If the current argument has swifterror parameter attribute,
/// apply Action A.
class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> {
}
/// CCIfCFGuardTarget - If the current argument has cfguardtarget parameter
/// attribute, apply Action A.
class CCIfCFGuardTarget<CCAction A> : CCIf<"ArgFlags.isCFGuardTarget()", A> {
}
/// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs
/// parameter attribute, apply Action A.
class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> {
}
/// CCIfCC - Match if the current calling convention is 'CC'.
class CCIfCC<string CC, CCAction A>
: CCIf<!strconcat("State.getCallingConv() == ", CC), A> {}
/// CCIfInReg - If this argument is marked with the 'inreg' attribute, apply
/// the specified action.
class CCIfInReg<CCAction A> : CCIf<"ArgFlags.isInReg()", A> {}
/// CCIfNest - If this argument is marked with the 'nest' attribute, apply
/// the specified action.
class CCIfNest<CCAction A> : CCIf<"ArgFlags.isNest()", A> {}
/// CCIfSplit - If this argument is marked with the 'split' attribute, apply
/// the specified action.
class CCIfSplit<CCAction A> : CCIf<"ArgFlags.isSplit()", A> {}
/// CCIfSRet - If this argument is marked with the 'sret' attribute, apply
/// the specified action.
class CCIfSRet<CCAction A> : CCIf<"ArgFlags.isSRet()", A> {}
/// CCIfVarArg - If the current function is vararg - apply the action
class CCIfVarArg<CCAction A> : CCIf<"State.isVarArg()", A> {}
/// CCIfNotVarArg - If the current function is not vararg - apply the action
class CCIfNotVarArg<CCAction A> : CCIf<"!State.isVarArg()", A> {}
/// CCIfPtrAddrSpace - If the top-level parent of the current argument has
/// pointer type in the specified address-space.
class CCIfPtrAddrSpace<int AS, CCAction A>
: CCIf<"(ArgFlags.isPointer() && ArgFlags.getPointerAddrSpace() == " # AS # ")", A> {}
/// CCIfPtr - If the top-level parent of the current argument had
/// pointer type in some address-space.
class CCIfPtr<CCAction A> : CCIf<"ArgFlags.isPointer()", A> {}
/// CCAssignToReg - This action matches if there is a register in the specified
/// list that is still available. If so, it assigns the value to the first
/// available register and succeeds.
class CCAssignToReg<list<Register> regList> : CCAction {
list<Register> RegList = regList;
}
/// CCAssignToRegWithShadow - Same as CCAssignToReg, but with list of registers
/// which became shadowed, when some register is used.
class CCAssignToRegWithShadow<list<Register> regList,
list<Register> shadowList> : CCAction {
list<Register> RegList = regList;
list<Register> ShadowRegList = shadowList;
}
/// CCAssignToStack - This action always matches: it assigns the value to a
/// stack slot of the specified size and alignment on the stack. If size is
/// zero then the ABI size is used; if align is zero then the ABI alignment
/// is used - these may depend on the target or subtarget.
class CCAssignToStack<int size, int align> : CCAction {
int Size = size;
int Align = align;
}
/// CCAssignToStackWithShadow - Same as CCAssignToStack, but with a list of
/// registers to be shadowed. Note that, unlike CCAssignToRegWithShadow, this
/// shadows ALL of the registers in shadowList.
class CCAssignToStackWithShadow<int size,
int align,
list<Register> shadowList> : CCAction {
int Size = size;
int Align = align;
list<Register> ShadowRegList = shadowList;
}
/// CCPassByVal - This action always matches: it assigns the value to a stack
/// slot to implement ByVal aggregate parameter passing. Size and alignment
/// specify the minimum size and alignment for the stack slot.
class CCPassByVal<int size, int align> : CCAction {
int Size = size;
int Align = align;
}
/// CCPromoteToType - If applied, this promotes the specified current value to
/// the specified type.
class CCPromoteToType<ValueType destTy> : CCAction {
ValueType DestTy = destTy;
}
/// CCPromoteToUpperBitsInType - If applied, this promotes the specified current
/// value to the specified type and shifts the value into the upper bits.
class CCPromoteToUpperBitsInType<ValueType destTy> : CCAction {
ValueType DestTy = destTy;
}
/// CCBitConvertToType - If applied, this bitconverts the specified current
/// value to the specified type.
class CCBitConvertToType<ValueType destTy> : CCAction {
ValueType DestTy = destTy;
}
/// CCTruncToType - If applied, this truncates the specified current value to
/// the specified type.
class CCTruncToType<ValueType destTy> : CCAction {
ValueType DestTy = destTy;
}
/// CCPassIndirect - If applied, this stores the value to stack and passes the pointer
/// as normal argument.
class CCPassIndirect<ValueType destTy> : CCAction {
ValueType DestTy = destTy;
}
/// CCDelegateTo - This action invokes the specified sub-calling-convention. It
/// is successful if the specified CC matches.
class CCDelegateTo<CallingConv cc> : CCAction {
CallingConv CC = cc;
}
/// CallingConv - An instance of this is used to define each calling convention
/// that the target supports.
class CallingConv<list<CCAction> actions> {
list<CCAction> Actions = actions;
/// If true, this calling convention will be emitted as externally visible in
/// the llvm namespaces instead of as a static function.
bit Entry = false;
bit Custom = false;
}
/// CustomCallingConv - An instance of this is used to declare calling
/// conventions that are implemented using a custom function of the same name.
class CustomCallingConv : CallingConv<[]> {
let Custom = true;
}
/// CalleeSavedRegs - A list of callee saved registers for a given calling
/// convention. The order of registers is used by PrologEpilogInsertion when
/// allocation stack slots for saved registers.
///
/// For each CalleeSavedRegs def, TableGen will emit a FOO_SaveList array for
/// returning from getCalleeSavedRegs(), and a FOO_RegMask bit mask suitable for
/// returning from getCallPreservedMask().
class CalleeSavedRegs<dag saves> {
dag SaveList = saves;
// Registers that are also preserved across function calls, but should not be
// included in the generated FOO_SaveList array. These registers will be
// included in the FOO_RegMask bit mask. This can be used for registers that
// are saved automatically, like the SPARC register windows.
dag OtherPreserved;
}

View File

@@ -0,0 +1,377 @@
//===- TargetInstrPredicate.td - ---------------------------*- 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 class MCInstPredicate and its subclasses.
//
// MCInstPredicate definitions are used by target scheduling models to describe
// constraints on instructions.
//
// Here is an example of an MCInstPredicate definition in TableGen:
//
// def MCInstPredicateExample : CheckAll<[
// CheckOpcode<[BLR]>,
// CheckIsRegOperand<0>,
// CheckNot<CheckRegOperand<0, LR>>]>;
//
// The syntax for MCInstPredicate is declarative, and predicate definitions can
// be composed together in order to generate more complex constraints.
//
// The `CheckAll` from the example defines a composition of three different
// predicates. Definition `MCInstPredicateExample` identifies instructions
// whose opcode is BLR, and whose first operand is a register different from
// register `LR`.
//
// Every MCInstPredicate class has a well-known semantic in tablegen. For
// example, `CheckOpcode` is a special type of predicate used to describe a
// constraint on the value of an instruction opcode.
//
// MCInstPredicate definitions are typically used by scheduling models to
// construct MCSchedPredicate definitions (see the definition of class
// MCSchedPredicate in llvm/Target/TargetSchedule.td).
// In particular, an MCSchedPredicate can be used instead of a SchedPredicate
// when defining the set of SchedReadVariant and SchedWriteVariant of a
// processor scheduling model.
//
// The `MCInstPredicateExample` definition above is equivalent (and therefore
// could replace) the following definition from a previous ExynosM3 model (see
// AArch64SchedExynosM3.td):
//
// def M3BranchLinkFastPred : SchedPredicate<[{
// MI->getOpcode() == AArch64::BLR &&
// MI->getOperand(0).isReg() &&
// MI->getOperand(0).getReg() != AArch64::LR}]>;
//
// The main advantage of using MCInstPredicate instead of SchedPredicate is
// portability: users don't need to specify predicates in C++. As a consequence
// of this, MCInstPredicate definitions are not bound to a particular
// representation (i.e. MachineInstr vs MCInst).
//
// Tablegen backends know how to expand MCInstPredicate definitions into actual
// C++ code that works on MachineInstr (and/or MCInst).
//
// Instances of class PredicateExpander (see utils/Tablegen/PredicateExpander.h)
// know how to expand a predicate. For each MCInstPredicate class, there must be
// an "expand" method available in the PredicateExpander interface.
//
// For example, a `CheckOpcode` predicate is expanded using method
// `PredicateExpander::expandCheckOpcode()`.
//
// New MCInstPredicate classes must be added to this file. For each new class
// XYZ, an "expandXYZ" method must be added to the PredicateExpander.
//
//===----------------------------------------------------------------------===//
// Forward declarations.
class Instruction;
class SchedMachineModel;
// A generic machine instruction predicate.
class MCInstPredicate;
class MCTrue : MCInstPredicate; // A predicate that always evaluates to True.
class MCFalse : MCInstPredicate; // A predicate that always evaluates to False.
def TruePred : MCTrue;
def FalsePred : MCFalse;
// A predicate used to negate the outcome of another predicate.
// It allows to easily express "set difference" operations. For example, it
// makes it easy to describe a check that tests if an opcode is not part of a
// set of opcodes.
class CheckNot<MCInstPredicate P> : MCInstPredicate {
MCInstPredicate Pred = P;
}
// This class is used as a building block to define predicates on instruction
// operands. It is used to reference a specific machine operand.
class MCOperandPredicate<int Index> : MCInstPredicate {
int OpIndex = Index;
}
// Return true if machine operand at position `Index` is a register operand.
class CheckIsRegOperand<int Index> : MCOperandPredicate<Index>;
// Return true if machine operand at position `Index` is an immediate operand.
class CheckIsImmOperand<int Index> : MCOperandPredicate<Index>;
// Check if machine operands at index `First` and index `Second` both reference
// the same register.
class CheckSameRegOperand<int First, int Second> : MCInstPredicate {
int FirstIndex = First;
int SecondIndex = Second;
}
// Base class for checks on register/immediate operands.
// It allows users to define checks like:
// MyFunction(MI->getOperand(Index).getImm()) == Val;
//
// In the example above, `MyFunction` is a function that takes as input an
// immediate operand value, and returns another value. Field `FunctionMapper` is
// the name of the function to call on the operand value.
class CheckOperandBase<int Index, string Fn = ""> : MCOperandPredicate<Index> {
string FunctionMapper = Fn;
}
// Check that the machine register operand at position `Index` references
// register R. This predicate assumes that we already checked that the machine
// operand at position `Index` is a register operand.
class CheckRegOperand<int Index, Register R> : CheckOperandBase<Index> {
Register Reg = R;
}
// Check if register operand at index `Index` is the invalid register.
class CheckInvalidRegOperand<int Index> : CheckOperandBase<Index>;
// Return true if machine operand at position `Index` is a valid
// register operand.
class CheckValidRegOperand<int Index> :
CheckNot<CheckInvalidRegOperand<Index>>;
// Check that the operand at position `Index` is immediate `Imm`.
// If field `FunctionMapper` is a non-empty string, then function
// `FunctionMapper` is applied to the operand value, and the return value is then
// compared against `Imm`.
class CheckImmOperand<int Index, int Imm> : CheckOperandBase<Index> {
int ImmVal = Imm;
}
// Similar to CheckImmOperand, however the immediate is not a literal number.
// This is useful when we want to compare the value of an operand against an
// enum value, and we know the actual integer value of that enum.
class CheckImmOperand_s<int Index, string Value> : CheckOperandBase<Index> {
string ImmVal = Value;
}
// Expands to a call to `FunctionMapper` if field `FunctionMapper` is set.
// Otherwise, it expands to a CheckNot<CheckInvalidRegOperand<Index>>.
class CheckRegOperandSimple<int Index> : CheckOperandBase<Index>;
// Expands to a call to `FunctionMapper` if field `FunctionMapper` is set.
// Otherwise, it simply evaluates to TruePred.
class CheckImmOperandSimple<int Index> : CheckOperandBase<Index>;
// Check that the operand at position `Index` is immediate value zero.
class CheckZeroOperand<int Index> : CheckImmOperand<Index, 0>;
// Check that the instruction has exactly `Num` operands.
class CheckNumOperands<int Num> : MCInstPredicate {
int NumOps = Num;
}
// Check that the instruction opcode is one of the opcodes in set `Opcodes`.
// This is a simple set membership query. The easier way to check if an opcode
// is not a member of the set is by using a `CheckNot<CheckOpcode<[...]>>`
// sequence.
class CheckOpcode<list<Instruction> Opcodes> : MCInstPredicate {
list<Instruction> ValidOpcodes = Opcodes;
}
// Check that the instruction opcode is a pseudo opcode member of the set
// `Opcodes`. This check is always expanded to "false" if we are generating
// code for MCInst.
class CheckPseudo<list<Instruction> Opcodes> : CheckOpcode<Opcodes>;
// A non-portable predicate. Only to use as a last resort when a block of code
// cannot possibly be converted in a declarative way using other MCInstPredicate
// classes. This check is always expanded to "false" when generating code for
// MCInst.
class CheckNonPortable<string Code> : MCInstPredicate {
string CodeBlock = Code;
}
// A sequence of predicates. It is used as the base class for CheckAll, and
// CheckAny. It allows to describe compositions of predicates.
class CheckPredicateSequence<list<MCInstPredicate> Preds> : MCInstPredicate {
list<MCInstPredicate> Predicates = Preds;
}
// Check that all of the predicates in `Preds` evaluate to true.
class CheckAll<list<MCInstPredicate> Sequence>
: CheckPredicateSequence<Sequence>;
// Check that at least one of the predicates in `Preds` evaluates to true.
class CheckAny<list<MCInstPredicate> Sequence>
: CheckPredicateSequence<Sequence>;
// Used to expand the body of a function predicate. See the definition of
// TIIPredicate below.
class MCStatement;
// Expands to a return statement. The return expression is a boolean expression
// described by a MCInstPredicate.
class MCReturnStatement<MCInstPredicate predicate> : MCStatement {
MCInstPredicate Pred = predicate;
}
// Used to automatically construct cases of a switch statement where the switch
// variable is an instruction opcode. There is a 'case' for every opcode in the
// `opcodes` list, and each case is associated with MCStatement `caseStmt`.
class MCOpcodeSwitchCase<list<Instruction> opcodes, MCStatement caseStmt> {
list<Instruction> Opcodes = opcodes;
MCStatement CaseStmt = caseStmt;
}
// Expands to a switch statement. The switch variable is an instruction opcode.
// The auto-generated switch is populated by a number of cases based on the
// `cases` list in input. A default case is automatically generated, and it
// evaluates to `default`.
class MCOpcodeSwitchStatement<list<MCOpcodeSwitchCase> cases,
MCStatement default> : MCStatement {
list<MCOpcodeSwitchCase> Cases = cases;
MCStatement DefaultCase = default;
}
// Base class for function predicates.
class FunctionPredicateBase<string name, MCStatement body> {
string FunctionName = name;
MCStatement Body = body;
}
// Check that a call to method `Name` in class "XXXInstrInfo" (where XXX is
// the name of a target) returns true.
//
// TIIPredicate definitions are used to model calls to the target-specific
// InstrInfo. A TIIPredicate is treated specially by the InstrInfoEmitter
// tablegen backend, which will use it to automatically generate a definition in
// the target specific `InstrInfo` class.
//
// There cannot be multiple TIIPredicate definitions with the same name for the
// same target.
class TIIPredicate<string Name, MCStatement body>
: FunctionPredicateBase<Name, body>, MCInstPredicate;
// A function predicate that takes as input a machine instruction, and returns
// a boolean value.
//
// This predicate is expanded into a function call by the PredicateExpander.
// In particular, the PredicateExpander would either expand this predicate into
// a call to `MCInstFn`, or into a call to`MachineInstrFn` depending on whether
// it is lowering predicates for MCInst or MachineInstr.
//
// In this context, `MCInstFn` and `MachineInstrFn` are both function names.
class CheckFunctionPredicate<string MCInstFn, string MachineInstrFn> : MCInstPredicate {
string MCInstFnName = MCInstFn;
string MachineInstrFnName = MachineInstrFn;
}
// Similar to CheckFunctionPredicate. However it assumes that MachineInstrFn is
// a method in TargetInstrInfo, and MCInstrFn takes an extra pointer to
// MCInstrInfo.
//
// It Expands to:
// - TIIPointer->MachineInstrFn(MI)
// - MCInstrFn(MI, MCII);
class CheckFunctionPredicateWithTII<string MCInstFn, string MachineInstrFn, string
TIIPointer = "TII"> : MCInstPredicate {
string MCInstFnName = MCInstFn;
string TIIPtrName = TIIPointer;
string MachineInstrFnName = MachineInstrFn;
}
// Used to classify machine instructions based on a machine instruction
// predicate.
//
// Let IC be an InstructionEquivalenceClass definition, and MI a machine
// instruction. We say that MI belongs to the equivalence class described by IC
// if and only if the following two conditions are met:
// a) MI's opcode is in the `opcodes` set, and
// b) `Predicate` evaluates to true when applied to MI.
//
// Instances of this class can be used by processor scheduling models to
// describe instructions that have a property in common. For example,
// InstructionEquivalenceClass definitions can be used to identify the set of
// dependency breaking instructions for a processor model.
//
// An (optional) list of operand indices can be used to further describe
// properties that apply to instruction operands. For example, it can be used to
// identify register uses of a dependency breaking instructions that are not in
// a RAW dependency.
class InstructionEquivalenceClass<list<Instruction> opcodes,
MCInstPredicate pred,
list<int> operands = []> {
list<Instruction> Opcodes = opcodes;
MCInstPredicate Predicate = pred;
list<int> OperandIndices = operands;
}
// Used by processor models to describe dependency breaking instructions.
//
// This is mainly an alias for InstructionEquivalenceClass. Input operand
// `BrokenDeps` identifies the set of "broken dependencies". There is one bit
// per each implicit and explicit input operand. An empty set of broken
// dependencies means: "explicit input register operands are independent."
class DepBreakingClass<list<Instruction> opcodes, MCInstPredicate pred,
list<int> BrokenDeps = []>
: InstructionEquivalenceClass<opcodes, pred, BrokenDeps>;
// A function descriptor used to describe the signature of a predicate methods
// which will be expanded by the STIPredicateExpander into a tablegen'd
// XXXGenSubtargetInfo class member definition (here, XXX is a target name).
//
// It describes the signature of a TargetSubtarget hook, as well as a few extra
// properties. Examples of extra properties are:
// - The default return value for the auto-generate function hook.
// - A list of subtarget hooks (Delegates) that are called from this function.
//
class STIPredicateDecl<string name, MCInstPredicate default = FalsePred,
bit overrides = true, bit expandForMC = true,
bit updatesOpcodeMask = false,
list<STIPredicateDecl> delegates = []> {
string Name = name;
MCInstPredicate DefaultReturnValue = default;
// True if this method is declared as virtual in class TargetSubtargetInfo.
bit OverridesBaseClassMember = overrides;
// True if we need an equivalent predicate function in the MC layer.
bit ExpandForMC = expandForMC;
// True if the autogenerated method has a extra in/out APInt param used as a
// mask of operands.
bit UpdatesOpcodeMask = updatesOpcodeMask;
// A list of STIPredicates used by this definition to delegate part of the
// computation. For example, STIPredicateFunction `isDependencyBreaking()`
// delegates to `isZeroIdiom()` part of its computation.
list<STIPredicateDecl> Delegates = delegates;
}
// A predicate function definition member of class `XXXGenSubtargetInfo`.
//
// If `Declaration.ExpandForMC` is true, then SubtargetEmitter
// will also expand another definition of this method that accepts a MCInst.
class STIPredicate<STIPredicateDecl declaration,
list<InstructionEquivalenceClass> classes> {
STIPredicateDecl Declaration = declaration;
list<InstructionEquivalenceClass> Classes = classes;
SchedMachineModel SchedModel = ?;
}
// Convenience classes and definitions used by processor scheduling models to
// describe dependency breaking instructions and move elimination candidates.
let UpdatesOpcodeMask = true in {
def IsZeroIdiomDecl : STIPredicateDecl<"isZeroIdiom">;
let Delegates = [IsZeroIdiomDecl] in
def IsDepBreakingDecl : STIPredicateDecl<"isDependencyBreaking">;
} // UpdatesOpcodeMask
def IsOptimizableRegisterMoveDecl
: STIPredicateDecl<"isOptimizableRegisterMove">;
class IsZeroIdiomFunction<list<DepBreakingClass> classes>
: STIPredicate<IsZeroIdiomDecl, classes>;
class IsDepBreakingFunction<list<DepBreakingClass> classes>
: STIPredicate<IsDepBreakingDecl, classes>;
class IsOptimizableRegisterMove<list<InstructionEquivalenceClass> classes>
: STIPredicate<IsOptimizableRegisterMoveDecl, classes>;

View File

@@ -0,0 +1,68 @@
//===-- llvm/Target/TargetIntrinsicInfo.h - Instruction Info ----*- C++ -*-===//
//
// 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 describes the target intrinsic instructions to the code generator.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_TARGETINTRINSICINFO_H
#define LLVM_TARGET_TARGETINTRINSICINFO_H
#include "llvm/ADT/StringRef.h"
#include <string>
namespace llvm {
class Function;
class Module;
class Type;
//---------------------------------------------------------------------------
///
/// TargetIntrinsicInfo - Interface to description of machine instruction set
///
class TargetIntrinsicInfo {
TargetIntrinsicInfo(const TargetIntrinsicInfo &) = delete;
void operator=(const TargetIntrinsicInfo &) = delete;
public:
TargetIntrinsicInfo();
virtual ~TargetIntrinsicInfo();
/// Return the name of a target intrinsic, e.g. "llvm.bfin.ssync".
/// The Tys and numTys parameters are for intrinsics with overloaded types
/// (e.g., those using iAny or fAny). For a declaration for an overloaded
/// intrinsic, Tys should point to an array of numTys pointers to Type,
/// and must provide exactly one type for each overloaded type in the
/// intrinsic.
virtual std::string getName(unsigned IID, Type **Tys = nullptr,
unsigned numTys = 0) const = 0;
/// Look up target intrinsic by name. Return intrinsic ID or 0 for unknown
/// names.
virtual unsigned lookupName(const char *Name, unsigned Len) const =0;
unsigned lookupName(StringRef Name) const {
return lookupName(Name.data(), Name.size());
}
/// Return the target intrinsic ID of a function, or 0.
virtual unsigned getIntrinsicID(const Function *F) const;
/// Returns true if the intrinsic can be overloaded.
virtual bool isOverloaded(unsigned IID) const = 0;
/// Create or insert an LLVM Function declaration for an intrinsic,
/// and return it. The Tys and numTys are for intrinsics with overloaded
/// types. See above for more information.
virtual Function *getDeclaration(Module *M, unsigned ID, Type **Tys = nullptr,
unsigned numTys = 0) const = 0;
};
} // End llvm namespace
#endif

View File

@@ -0,0 +1,162 @@
//===- TargetItinerary.td - Target Itinerary Description --*- 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 target-independent scheduling interfaces
// which should be implemented by each target that uses instruction
// itineraries for scheduling. Itineraries are detailed reservation
// tables for each instruction class. They are most appropriate for
// in-order machine with complicated scheduling or bundling constraints.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Processor functional unit - These values represent the function units
// available across all chip sets for the target. Eg., IntUnit, FPUnit, ...
// These may be independent values for each chip set or may be shared across
// all chip sets of the target. Each functional unit is treated as a resource
// during scheduling and has an affect instruction order based on availability
// during a time interval.
//
class FuncUnit;
//===----------------------------------------------------------------------===//
// Pipeline bypass / forwarding - These values specifies the symbolic names of
// pipeline bypasses which can be used to forward results of instructions
// that are forwarded to uses.
class Bypass;
def NoBypass : Bypass;
class ReservationKind<bits<1> val> {
int Value = val;
}
def Required : ReservationKind<0>;
def Reserved : ReservationKind<1>;
//===----------------------------------------------------------------------===//
// Instruction stage - These values represent a non-pipelined step in
// the execution of an instruction. Cycles represents the number of
// discrete time slots needed to complete the stage. Units represent
// the choice of functional units that can be used to complete the
// stage. Eg. IntUnit1, IntUnit2. TimeInc indicates how many cycles
// should elapse from the start of this stage to the start of the next
// stage in the itinerary. For example:
//
// A stage is specified in one of two ways:
//
// InstrStage<1, [FU_x, FU_y]> - TimeInc defaults to Cycles
// InstrStage<1, [FU_x, FU_y], 0> - TimeInc explicit
//
class InstrStage<int cycles, list<FuncUnit> units,
int timeinc = -1,
ReservationKind kind = Required> {
int Cycles = cycles; // length of stage in machine cycles
list<FuncUnit> Units = units; // choice of functional units
int TimeInc = timeinc; // cycles till start of next stage
int Kind = kind.Value; // kind of FU reservation
}
//===----------------------------------------------------------------------===//
// Instruction itinerary - An itinerary represents a sequential series of steps
// required to complete an instruction. Itineraries are represented as lists of
// instruction stages.
//
//===----------------------------------------------------------------------===//
// Instruction itinerary classes - These values represent 'named' instruction
// itinerary. Using named itineraries simplifies managing groups of
// instructions across chip sets. An instruction uses the same itinerary class
// across all chip sets. Thus a new chip set can be added without modifying
// instruction information.
//
class InstrItinClass;
def NoItinerary : InstrItinClass;
//===----------------------------------------------------------------------===//
// Instruction itinerary data - These values provide a runtime map of an
// instruction itinerary class (name) to its itinerary data.
//
// NumMicroOps represents the number of micro-operations that each instruction
// in the class are decoded to. If the number is zero, then it means the
// instruction can decode into variable number of micro-ops and it must be
// determined dynamically. This directly relates to the itineraries
// global IssueWidth property, which constrains the number of microops
// that can issue per cycle.
//
// OperandCycles are optional "cycle counts". They specify the cycle after
// instruction issue the values which correspond to specific operand indices
// are defined or read. Bypasses are optional "pipeline forwarding paths", if
// a def by an instruction is available on a specific bypass and the use can
// read from the same bypass, then the operand use latency is reduced by one.
//
// InstrItinData<IIC_iLoad_i , [InstrStage<1, [A9_Pipe1]>,
// InstrStage<1, [A9_AGU]>],
// [3, 1], [A9_LdBypass]>,
// InstrItinData<IIC_iMVNr , [InstrStage<1, [A9_Pipe0, A9_Pipe1]>],
// [1, 1], [NoBypass, A9_LdBypass]>,
//
// In this example, the instruction of IIC_iLoadi reads its input on cycle 1
// (after issue) and the result of the load is available on cycle 3. The result
// is available via forwarding path A9_LdBypass. If it's used by the first
// source operand of instructions of IIC_iMVNr class, then the operand latency
// is reduced by 1.
class InstrItinData<InstrItinClass Class, list<InstrStage> stages,
list<int> operandcycles = [],
list<Bypass> bypasses = [], int uops = 1> {
InstrItinClass TheClass = Class;
int NumMicroOps = uops;
list<InstrStage> Stages = stages;
list<int> OperandCycles = operandcycles;
list<Bypass> Bypasses = bypasses;
}
//===----------------------------------------------------------------------===//
// Processor itineraries - These values represent the set of all itinerary
// classes for a given chip set.
//
// Set property values to -1 to use the default.
// See InstrItineraryProps for comments and defaults.
class ProcessorItineraries<list<FuncUnit> fu, list<Bypass> bp,
list<InstrItinData> iid> {
list<FuncUnit> FU = fu;
list<Bypass> BP = bp;
list<InstrItinData> IID = iid;
// The packetizer automaton to use for this itinerary. By default all
// itineraries for a target are bundled up into the same automaton. This only
// works correctly when there are no conflicts in functional unit IDs between
// itineraries. For example, given two itineraries A<[SLOT_A]>, B<[SLOT_B]>,
// SLOT_A and SLOT_B will be assigned the same functional unit index, and
// the generated packetizer will confuse instructions referencing these slots.
//
// To avoid this, setting PacketizerNamespace to non-"" will cause this
// itinerary to be generated in a different automaton. The subtarget will need
// to declare a method "create##Namespace##DFAPacketizer()".
string PacketizerNamespace = "";
}
// NoItineraries - A marker that can be used by processors without schedule
// info. Subtargets using NoItineraries can bypass the scheduler's
// expensive HazardRecognizer because no reservation table is needed.
def NoItineraries : ProcessorItineraries<[], [], []>;
//===----------------------------------------------------------------------===//
// Combo Function Unit data - This is a map of combo function unit names to
// the list of functional units that are included in the combination.
//
class ComboFuncData<FuncUnit ComboFunc, list<FuncUnit> funclist> {
FuncUnit TheComboFunc = ComboFunc;
list<FuncUnit> FuncList = funclist;
}
//===----------------------------------------------------------------------===//
// Combo Function Units - This is a list of all combo function unit data.
class ComboFuncUnits<list<ComboFuncData> cfd> {
list<ComboFuncData> CFD = cfd;
}

View File

@@ -0,0 +1,294 @@
//===-- llvm/Target/TargetLoweringObjectFile.h - Object Info ----*- C++ -*-===//
//
// 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 implements classes used to handle lowerings specific to common
// object file formats.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H
#define LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCRegister.h"
#include <cstdint>
namespace llvm {
class Constant;
class DataLayout;
class Function;
class GlobalObject;
class GlobalValue;
class MachineBasicBlock;
class MachineModuleInfo;
class Mangler;
class MCContext;
class MCExpr;
class MCSection;
class MCSymbol;
class MCSymbolRefExpr;
class MCStreamer;
class MCValue;
class Module;
class SectionKind;
class StringRef;
class TargetMachine;
class DSOLocalEquivalent;
class TargetLoweringObjectFile : public MCObjectFileInfo {
/// Name-mangler for global names.
Mangler *Mang = nullptr;
protected:
bool SupportIndirectSymViaGOTPCRel = false;
bool SupportGOTPCRelWithOffset = true;
bool SupportDebugThreadLocalLocation = true;
bool SupportDSOLocalEquivalentLowering = false;
/// PersonalityEncoding, LSDAEncoding, TTypeEncoding - Some encoding values
/// for EH.
unsigned PersonalityEncoding = 0;
unsigned LSDAEncoding = 0;
unsigned TTypeEncoding = 0;
unsigned CallSiteEncoding = 0;
/// This section contains the static constructor pointer list.
MCSection *StaticCtorSection = nullptr;
/// This section contains the static destructor pointer list.
MCSection *StaticDtorSection = nullptr;
const TargetMachine *TM = nullptr;
public:
TargetLoweringObjectFile() = default;
TargetLoweringObjectFile(const TargetLoweringObjectFile &) = delete;
TargetLoweringObjectFile &
operator=(const TargetLoweringObjectFile &) = delete;
virtual ~TargetLoweringObjectFile();
Mangler &getMangler() const { return *Mang; }
/// This method must be called before any actual lowering is done. This
/// specifies the current context for codegen, and gives the lowering
/// implementations a chance to set up their default sections.
virtual void Initialize(MCContext &ctx, const TargetMachine &TM);
virtual void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM,
const MCSymbol *Sym) const;
/// Emit the module-level metadata that the platform cares about.
virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M) const {}
/// Emit Call Graph Profile metadata.
void emitCGProfileMetadata(MCStreamer &Streamer, Module &M) const;
/// Get the module-level metadata that the platform cares about.
virtual void getModuleMetadata(Module &M) {}
/// Given a constant with the SectionKind, return a section that it should be
/// placed in.
virtual MCSection *getSectionForConstant(const DataLayout &DL,
SectionKind Kind, const Constant *C,
Align &Alignment) const;
virtual MCSection *
getSectionForMachineBasicBlock(const Function &F,
const MachineBasicBlock &MBB,
const TargetMachine &TM) const;
virtual MCSection *
getUniqueSectionForFunction(const Function &F,
const TargetMachine &TM) const;
/// Classify the specified global variable into a set of target independent
/// categories embodied in SectionKind.
static SectionKind getKindForGlobal(const GlobalObject *GO,
const TargetMachine &TM);
/// This method computes the appropriate section to emit the specified global
/// variable or function definition. This should not be passed external (or
/// available externally) globals.
MCSection *SectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const;
/// This method computes the appropriate section to emit the specified global
/// variable or function definition. This should not be passed external (or
/// available externally) globals.
MCSection *SectionForGlobal(const GlobalObject *GO,
const TargetMachine &TM) const;
virtual void getNameWithPrefix(SmallVectorImpl<char> &OutName,
const GlobalValue *GV,
const TargetMachine &TM) const;
virtual MCSection *getSectionForJumpTable(const Function &F,
const TargetMachine &TM) const;
virtual MCSection *getSectionForLSDA(const Function &, const MCSymbol &,
const TargetMachine &) const {
return LSDASection;
}
virtual bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference,
const Function &F) const;
/// Targets should implement this method to assign a section to globals with
/// an explicit section specified. The implementation of this method can
/// assume that GO->hasSection() is true.
virtual MCSection *
getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const = 0;
/// Return an MCExpr to use for a reference to the specified global variable
/// from exception handling information.
virtual const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
unsigned Encoding,
const TargetMachine &TM,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const;
/// Return the MCSymbol for a private symbol with global value name as its
/// base, with the specified suffix.
MCSymbol *getSymbolWithGlobalValueBase(const GlobalValue *GV,
StringRef Suffix,
const TargetMachine &TM) const;
// The symbol that gets passed to .cfi_personality.
virtual MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV,
const TargetMachine &TM,
MachineModuleInfo *MMI) const;
unsigned getPersonalityEncoding() const { return PersonalityEncoding; }
unsigned getLSDAEncoding() const { return LSDAEncoding; }
unsigned getTTypeEncoding() const { return TTypeEncoding; }
unsigned getCallSiteEncoding() const;
const MCExpr *getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
MCStreamer &Streamer) const;
virtual MCSection *getStaticCtorSection(unsigned Priority,
const MCSymbol *KeySym) const {
return StaticCtorSection;
}
virtual MCSection *getStaticDtorSection(unsigned Priority,
const MCSymbol *KeySym) const {
return StaticDtorSection;
}
/// Create a symbol reference to describe the given TLS variable when
/// emitting the address in debug info.
virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const;
virtual const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
const GlobalValue *RHS,
const TargetMachine &TM) const {
return nullptr;
}
/// Target supports a native lowering of a dso_local_equivalent constant
/// without needing to replace it with equivalent IR.
bool supportDSOLocalEquivalentLowering() const {
return SupportDSOLocalEquivalentLowering;
}
virtual const MCExpr *lowerDSOLocalEquivalent(const DSOLocalEquivalent *Equiv,
const TargetMachine &TM) const {
return nullptr;
}
/// Target supports replacing a data "PC"-relative access to a symbol
/// through another symbol, by accessing the later via a GOT entry instead?
bool supportIndirectSymViaGOTPCRel() const {
return SupportIndirectSymViaGOTPCRel;
}
/// Target GOT "PC"-relative relocation supports encoding an additional
/// binary expression with an offset?
bool supportGOTPCRelWithOffset() const {
return SupportGOTPCRelWithOffset;
}
/// Target supports TLS offset relocation in debug section?
bool supportDebugThreadLocalLocation() const {
return SupportDebugThreadLocalLocation;
}
/// Returns the register used as static base in RWPI variants.
virtual MCRegister getStaticBase() const { return MCRegister::NoRegister; }
/// Get the target specific RWPI relocation.
virtual const MCExpr *getIndirectSymViaRWPI(const MCSymbol *Sym) const {
return nullptr;
}
/// Get the target specific PC relative GOT entry relocation
virtual const MCExpr *getIndirectSymViaGOTPCRel(const GlobalValue *GV,
const MCSymbol *Sym,
const MCValue &MV,
int64_t Offset,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const {
return nullptr;
}
/// If supported, return the section to use for the llvm.commandline
/// metadata. Otherwise, return nullptr.
virtual MCSection *getSectionForCommandLines() const {
return nullptr;
}
/// On targets that use separate function descriptor symbols, return a section
/// for the descriptor given its symbol. Use only with defined functions.
virtual MCSection *
getSectionForFunctionDescriptor(const Function *F,
const TargetMachine &TM) const {
return nullptr;
}
/// On targets that support TOC entries, return a section for the entry given
/// the symbol it refers to.
/// TODO: Implement this interface for existing ELF targets.
virtual MCSection *getSectionForTOCEntry(const MCSymbol *S,
const TargetMachine &TM) const {
return nullptr;
}
/// On targets that associate external references with a section, return such
/// a section for the given external global.
virtual MCSection *
getSectionForExternalReference(const GlobalObject *GO,
const TargetMachine &TM) const {
return nullptr;
}
/// Targets that have a special convention for their symbols could use
/// this hook to return a specialized symbol.
virtual MCSymbol *getTargetSymbol(const GlobalValue *GV,
const TargetMachine &TM) const {
return nullptr;
}
/// If supported, return the function entry point symbol.
/// Otherwise, returns nulltpr.
/// Func must be a function or an alias which has a function as base object.
virtual MCSymbol *getFunctionEntryPointSymbol(const GlobalValue *Func,
const TargetMachine &TM) const {
return nullptr;
}
protected:
virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
SectionKind Kind,
const TargetMachine &TM) const = 0;
};
} // end namespace llvm
#endif // LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H

View File

@@ -0,0 +1,513 @@
//===-- llvm/Target/TargetMachine.h - Target Information --------*- C++ -*-===//
//
// 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 TargetMachine and LLVMTargetMachine classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_TARGETMACHINE_H
#define LLVM_TARGET_TARGETMACHINE_H
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/PGOOptions.h"
#include "llvm/Target/CGPassBuilderOption.h"
#include "llvm/Target/TargetOptions.h"
#include <string>
#include <utility>
namespace llvm {
class AAManager;
template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
class PassManager;
using ModulePassManager = PassManager<Module>;
class Function;
class GlobalValue;
class MachineFunctionPassManager;
class MachineFunctionAnalysisManager;
class MachineModuleInfoWrapperPass;
class Mangler;
class MCAsmInfo;
class MCContext;
class MCInstrInfo;
class MCRegisterInfo;
class MCStreamer;
class MCSubtargetInfo;
class MCSymbol;
class raw_pwrite_stream;
class PassBuilder;
class PassManagerBuilder;
struct PerFunctionMIParsingState;
class SMDiagnostic;
class SMRange;
class Target;
class TargetIntrinsicInfo;
class TargetIRAnalysis;
class TargetTransformInfo;
class TargetLoweringObjectFile;
class TargetPassConfig;
class TargetSubtargetInfo;
// The old pass manager infrastructure is hidden in a legacy namespace now.
namespace legacy {
class PassManagerBase;
}
using legacy::PassManagerBase;
namespace yaml {
struct MachineFunctionInfo;
}
//===----------------------------------------------------------------------===//
///
/// Primary interface to the complete machine description for the target
/// machine. All target-specific information should be accessible through this
/// interface.
///
class TargetMachine {
protected: // Can only create subclasses.
TargetMachine(const Target &T, StringRef DataLayoutString,
const Triple &TargetTriple, StringRef CPU, StringRef FS,
const TargetOptions &Options);
/// The Target that this machine was created for.
const Target &TheTarget;
/// DataLayout for the target: keep ABI type size and alignment.
///
/// The DataLayout is created based on the string representation provided
/// during construction. It is kept here only to avoid reparsing the string
/// but should not really be used during compilation, because it has an
/// internal cache that is context specific.
const DataLayout DL;
/// Triple string, CPU name, and target feature strings the TargetMachine
/// instance is created with.
Triple TargetTriple;
std::string TargetCPU;
std::string TargetFS;
Reloc::Model RM = Reloc::Static;
CodeModel::Model CMModel = CodeModel::Small;
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
/// Contains target specific asm information.
std::unique_ptr<const MCAsmInfo> AsmInfo;
std::unique_ptr<const MCRegisterInfo> MRI;
std::unique_ptr<const MCInstrInfo> MII;
std::unique_ptr<const MCSubtargetInfo> STI;
unsigned RequireStructuredCFG : 1;
unsigned O0WantsFastISel : 1;
// PGO related tunables.
Optional<PGOOptions> PGOOption = None;
public:
const TargetOptions DefaultOptions;
mutable TargetOptions Options;
TargetMachine(const TargetMachine &) = delete;
void operator=(const TargetMachine &) = delete;
virtual ~TargetMachine();
const Target &getTarget() const { return TheTarget; }
const Triple &getTargetTriple() const { return TargetTriple; }
StringRef getTargetCPU() const { return TargetCPU; }
StringRef getTargetFeatureString() const { return TargetFS; }
void setTargetFeatureString(StringRef FS) { TargetFS = std::string(FS); }
/// Virtual method implemented by subclasses that returns a reference to that
/// target's TargetSubtargetInfo-derived member variable.
virtual const TargetSubtargetInfo *getSubtargetImpl(const Function &) const {
return nullptr;
}
virtual TargetLoweringObjectFile *getObjFileLowering() const {
return nullptr;
}
/// Allocate and return a default initialized instance of the YAML
/// representation for the MachineFunctionInfo.
virtual yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const {
return nullptr;
}
/// Allocate and initialize an instance of the YAML representation of the
/// MachineFunctionInfo.
virtual yaml::MachineFunctionInfo *
convertFuncInfoToYAML(const MachineFunction &MF) const {
return nullptr;
}
/// Parse out the target's MachineFunctionInfo from the YAML representation.
virtual bool parseMachineFunctionInfo(const yaml::MachineFunctionInfo &,
PerFunctionMIParsingState &PFS,
SMDiagnostic &Error,
SMRange &SourceRange) const {
return false;
}
/// This method returns a pointer to the specified type of
/// TargetSubtargetInfo. In debug builds, it verifies that the object being
/// returned is of the correct type.
template <typename STC> const STC &getSubtarget(const Function &F) const {
return *static_cast<const STC*>(getSubtargetImpl(F));
}
/// Create a DataLayout.
const DataLayout createDataLayout() const { return DL; }
/// Test if a DataLayout if compatible with the CodeGen for this target.
///
/// The LLVM Module owns a DataLayout that is used for the target independent
/// optimizations and code generation. This hook provides a target specific
/// check on the validity of this DataLayout.
bool isCompatibleDataLayout(const DataLayout &Candidate) const {
return DL == Candidate;
}
/// Get the pointer size for this target.
///
/// This is the only time the DataLayout in the TargetMachine is used.
unsigned getPointerSize(unsigned AS) const {
return DL.getPointerSize(AS);
}
unsigned getPointerSizeInBits(unsigned AS) const {
return DL.getPointerSizeInBits(AS);
}
unsigned getProgramPointerSize() const {
return DL.getPointerSize(DL.getProgramAddressSpace());
}
unsigned getAllocaPointerSize() const {
return DL.getPointerSize(DL.getAllocaAddrSpace());
}
/// Reset the target options based on the function's attributes.
// FIXME: Remove TargetOptions that affect per-function code generation
// from TargetMachine.
void resetTargetOptions(const Function &F) const;
/// Return target specific asm information.
const MCAsmInfo *getMCAsmInfo() const { return AsmInfo.get(); }
const MCRegisterInfo *getMCRegisterInfo() const { return MRI.get(); }
const MCInstrInfo *getMCInstrInfo() const { return MII.get(); }
const MCSubtargetInfo *getMCSubtargetInfo() const { return STI.get(); }
/// If intrinsic information is available, return it. If not, return null.
virtual const TargetIntrinsicInfo *getIntrinsicInfo() const {
return nullptr;
}
bool requiresStructuredCFG() const { return RequireStructuredCFG; }
void setRequiresStructuredCFG(bool Value) { RequireStructuredCFG = Value; }
/// Returns the code generation relocation model. The choices are static, PIC,
/// and dynamic-no-pic, and target default.
Reloc::Model getRelocationModel() const;
/// Returns the code model. The choices are small, kernel, medium, large, and
/// target default.
CodeModel::Model getCodeModel() const;
bool isPositionIndependent() const;
bool shouldAssumeDSOLocal(const Module &M, const GlobalValue *GV) const;
/// Returns true if this target uses emulated TLS.
bool useEmulatedTLS() const;
/// Returns the TLS model which should be used for the given global variable.
TLSModel::Model getTLSModel(const GlobalValue *GV) const;
/// Returns the optimization level: None, Less, Default, or Aggressive.
CodeGenOpt::Level getOptLevel() const;
/// Overrides the optimization level.
void setOptLevel(CodeGenOpt::Level Level);
void setFastISel(bool Enable) { Options.EnableFastISel = Enable; }
bool getO0WantsFastISel() { return O0WantsFastISel; }
void setO0WantsFastISel(bool Enable) { O0WantsFastISel = Enable; }
void setGlobalISel(bool Enable) { Options.EnableGlobalISel = Enable; }
void setGlobalISelAbort(GlobalISelAbortMode Mode) {
Options.GlobalISelAbort = Mode;
}
void setMachineOutliner(bool Enable) {
Options.EnableMachineOutliner = Enable;
}
void setSupportsDefaultOutlining(bool Enable) {
Options.SupportsDefaultOutlining = Enable;
}
void setSupportsDebugEntryValues(bool Enable) {
Options.SupportsDebugEntryValues = Enable;
}
bool getAIXExtendedAltivecABI() const {
return Options.EnableAIXExtendedAltivecABI;
}
bool getUniqueSectionNames() const { return Options.UniqueSectionNames; }
/// Return true if unique basic block section names must be generated.
bool getUniqueBasicBlockSectionNames() const {
return Options.UniqueBasicBlockSectionNames;
}
/// Return true if data objects should be emitted into their own section,
/// corresponds to -fdata-sections.
bool getDataSections() const {
return Options.DataSections;
}
/// Return true if functions should be emitted into their own section,
/// corresponding to -ffunction-sections.
bool getFunctionSections() const {
return Options.FunctionSections;
}
/// Return true if visibility attribute should not be emitted in XCOFF,
/// corresponding to -mignore-xcoff-visibility.
bool getIgnoreXCOFFVisibility() const {
return Options.IgnoreXCOFFVisibility;
}
/// Return true if XCOFF traceback table should be emitted,
/// corresponding to -xcoff-traceback-table.
bool getXCOFFTracebackTable() const { return Options.XCOFFTracebackTable; }
/// If basic blocks should be emitted into their own section,
/// corresponding to -fbasic-block-sections.
llvm::BasicBlockSection getBBSectionsType() const {
return Options.BBSections;
}
/// Get the list of functions and basic block ids that need unique sections.
const MemoryBuffer *getBBSectionsFuncListBuf() const {
return Options.BBSectionsFuncListBuf.get();
}
/// Returns true if a cast between SrcAS and DestAS is a noop.
virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const {
return false;
}
void setPGOOption(Optional<PGOOptions> PGOOpt) { PGOOption = PGOOpt; }
const Optional<PGOOptions> &getPGOOption() const { return PGOOption; }
/// If the specified generic pointer could be assumed as a pointer to a
/// specific address space, return that address space.
///
/// Under offloading programming, the offloading target may be passed with
/// values only prepared on the host side and could assume certain
/// properties.
virtual unsigned getAssumedAddrSpace(const Value *V) const { return -1; }
/// If the specified predicate checks whether a generic pointer falls within
/// a specified address space, return that generic pointer and the address
/// space being queried.
///
/// Such predicates could be specified in @llvm.assume intrinsics for the
/// optimizer to assume that the given generic pointer always falls within
/// the address space based on that predicate.
virtual std::pair<const Value *, unsigned>
getPredicatedAddrSpace(const Value *V) const {
return std::make_pair(nullptr, -1);
}
/// Get a \c TargetIRAnalysis appropriate for the target.
///
/// This is used to construct the new pass manager's target IR analysis pass,
/// set up appropriately for this target machine. Even the old pass manager
/// uses this to answer queries about the IR.
TargetIRAnalysis getTargetIRAnalysis();
/// Return a TargetTransformInfo for a given function.
///
/// The returned TargetTransformInfo is specialized to the subtarget
/// corresponding to \p F.
virtual TargetTransformInfo getTargetTransformInfo(const Function &F);
/// Allow the target to modify the pass manager, e.g. by calling
/// PassManagerBuilder::addExtension.
virtual void adjustPassManager(PassManagerBuilder &) {}
/// Allow the target to modify the pass pipeline with New Pass Manager
/// (similar to adjustPassManager for Legacy Pass manager).
virtual void registerPassBuilderCallbacks(PassBuilder &) {}
/// Allow the target to register alias analyses with the AAManager for use
/// with the new pass manager. Only affects the "default" AAManager.
virtual void registerDefaultAliasAnalyses(AAManager &) {}
/// Add passes to the specified pass manager to get the specified file
/// emitted. Typically this will involve several steps of code generation.
/// This method should return true if emission of this file type is not
/// supported, or false on success.
/// \p MMIWP is an optional parameter that, if set to non-nullptr,
/// will be used to set the MachineModuloInfo for this PM.
virtual bool
addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
raw_pwrite_stream *, CodeGenFileType,
bool /*DisableVerify*/ = true,
MachineModuleInfoWrapperPass *MMIWP = nullptr) {
return true;
}
/// Add passes to the specified pass manager to get machine code emitted with
/// the MCJIT. This method returns true if machine code is not supported. It
/// fills the MCContext Ctx pointer which can be used to build custom
/// MCStreamer.
///
virtual bool addPassesToEmitMC(PassManagerBase &, MCContext *&,
raw_pwrite_stream &,
bool /*DisableVerify*/ = true) {
return true;
}
/// True if subtarget inserts the final scheduling pass on its own.
///
/// Branch relaxation, which must happen after block placement, can
/// on some targets (e.g. SystemZ) expose additional post-RA
/// scheduling opportunities.
virtual bool targetSchedulesPostRAScheduling() const { return false; };
void getNameWithPrefix(SmallVectorImpl<char> &Name, const GlobalValue *GV,
Mangler &Mang, bool MayAlwaysUsePrivate = false) const;
MCSymbol *getSymbol(const GlobalValue *GV) const;
/// The integer bit size to use for SjLj based exception handling.
static constexpr unsigned DefaultSjLjDataSize = 32;
virtual unsigned getSjLjDataSize() const { return DefaultSjLjDataSize; }
static std::pair<int, int> parseBinutilsVersion(StringRef Version);
};
/// This class describes a target machine that is implemented with the LLVM
/// target-independent code generator.
///
class LLVMTargetMachine : public TargetMachine {
protected: // Can only create subclasses.
LLVMTargetMachine(const Target &T, StringRef DataLayoutString,
const Triple &TT, StringRef CPU, StringRef FS,
const TargetOptions &Options, Reloc::Model RM,
CodeModel::Model CM, CodeGenOpt::Level OL);
void initAsmInfo();
public:
/// Get a TargetTransformInfo implementation for the target.
///
/// The TTI returned uses the common code generator to answer queries about
/// the IR.
TargetTransformInfo getTargetTransformInfo(const Function &F) override;
/// Create a pass configuration object to be used by addPassToEmitX methods
/// for generating a pipeline of CodeGen passes.
virtual TargetPassConfig *createPassConfig(PassManagerBase &PM);
/// Add passes to the specified pass manager to get the specified file
/// emitted. Typically this will involve several steps of code generation.
/// \p MMIWP is an optional parameter that, if set to non-nullptr,
/// will be used to set the MachineModuloInfo for this PM.
bool
addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
bool DisableVerify = true,
MachineModuleInfoWrapperPass *MMIWP = nullptr) override;
virtual Error buildCodeGenPipeline(ModulePassManager &,
MachineFunctionPassManager &,
MachineFunctionAnalysisManager &,
raw_pwrite_stream &, raw_pwrite_stream *,
CodeGenFileType, CGPassBuilderOption,
PassInstrumentationCallbacks *) {
return make_error<StringError>("buildCodeGenPipeline is not overridden",
inconvertibleErrorCode());
}
virtual std::pair<StringRef, bool> getPassNameFromLegacyName(StringRef) {
llvm_unreachable(
"getPassNameFromLegacyName parseMIRPipeline is not overridden");
}
/// Add passes to the specified pass manager to get machine code emitted with
/// the MCJIT. This method returns true if machine code is not supported. It
/// fills the MCContext Ctx pointer which can be used to build custom
/// MCStreamer.
bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
raw_pwrite_stream &Out,
bool DisableVerify = true) override;
/// Returns true if the target is expected to pass all machine verifier
/// checks. This is a stopgap measure to fix targets one by one. We will
/// remove this at some point and always enable the verifier when
/// EXPENSIVE_CHECKS is enabled.
virtual bool isMachineVerifierClean() const { return true; }
/// Adds an AsmPrinter pass to the pipeline that prints assembly or
/// machine code from the MI representation.
bool addAsmPrinter(PassManagerBase &PM, raw_pwrite_stream &Out,
raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
MCContext &Context);
Expected<std::unique_ptr<MCStreamer>>
createMCStreamer(raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
CodeGenFileType FileType, MCContext &Ctx);
/// True if the target uses physical regs (as nearly all targets do). False
/// for stack machines such as WebAssembly and other virtual-register
/// machines. If true, all vregs must be allocated before PEI. If false, then
/// callee-save register spilling and scavenging are not needed or used. If
/// false, implicitly defined registers will still be assumed to be physical
/// registers, except that variadic defs will be allocated vregs.
virtual bool usesPhysRegsForValues() const { return true; }
/// True if the target wants to use interprocedural register allocation by
/// default. The -enable-ipra flag can be used to override this.
virtual bool useIPRA() const {
return false;
}
/// The default variant to use in unqualified `asm` instructions.
/// If this returns 0, `asm "$(foo$|bar$)"` will evaluate to `asm "foo"`.
virtual int unqualifiedInlineAsmVariant() const { return 0; }
};
/// Helper method for getting the code model, returning Default if
/// CM does not have a value. The tiny and kernel models will produce
/// an error, so targets that support them or require more complex codemodel
/// selection logic should implement and call their own getEffectiveCodeModel.
inline CodeModel::Model getEffectiveCodeModel(Optional<CodeModel::Model> CM,
CodeModel::Model Default) {
if (CM) {
// By default, targets do not support the tiny and kernel models.
if (*CM == CodeModel::Tiny)
report_fatal_error("Target does not support the tiny CodeModel", false);
if (*CM == CodeModel::Kernel)
report_fatal_error("Target does not support the kernel CodeModel", false);
return *CM;
}
return Default;
}
} // end namespace llvm
#endif // LLVM_TARGET_TARGETMACHINE_H

View File

@@ -0,0 +1,433 @@
//===-- llvm/Target/TargetOptions.h - Target Options ------------*- C++ -*-===//
//
// 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 command line option flags that are shared across various
// targets.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_TARGETOPTIONS_H
#define LLVM_TARGET_TARGETOPTIONS_H
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/MC/MCTargetOptions.h"
#include <memory>
namespace llvm {
struct fltSemantics;
class MachineFunction;
class MemoryBuffer;
namespace FloatABI {
enum ABIType {
Default, // Target-specific (either soft or hard depending on triple, etc).
Soft, // Soft float.
Hard // Hard float.
};
}
namespace FPOpFusion {
enum FPOpFusionMode {
Fast, // Enable fusion of FP ops wherever it's profitable.
Standard, // Only allow fusion of 'blessed' ops (currently just fmuladd).
Strict // Never fuse FP-ops.
};
}
namespace JumpTable {
enum JumpTableType {
Single, // Use a single table for all indirect jumptable calls.
Arity, // Use one table per number of function parameters.
Simplified, // Use one table per function type, with types projected
// into 4 types: pointer to non-function, struct,
// primitive, and function pointer.
Full // Use one table per unique function type
};
}
namespace ThreadModel {
enum Model {
POSIX, // POSIX Threads
Single // Single Threaded Environment
};
}
enum class BasicBlockSection {
All, // Use Basic Block Sections for all basic blocks. A section
// for every basic block can significantly bloat object file sizes.
List, // Get list of functions & BBs from a file. Selectively enables
// basic block sections for a subset of basic blocks which can be
// used to control object size bloats from creating sections.
Labels, // Do not use Basic Block Sections but label basic blocks. This
// is useful when associating profile counts from virtual addresses
// to basic blocks.
Preset, // Similar to list but the blocks are identified by passes which
// seek to use Basic Block Sections, e.g. MachineFunctionSplitter.
// This option cannot be set via the command line.
None // Do not use Basic Block Sections.
};
enum class EABI {
Unknown,
Default, // Default means not specified
EABI4, // Target-specific (either 4, 5 or gnu depending on triple).
EABI5,
GNU
};
/// Identify a debugger for "tuning" the debug info.
///
/// The "debugger tuning" concept allows us to present a more intuitive
/// interface that unpacks into different sets of defaults for the various
/// individual feature-flag settings, that suit the preferences of the
/// various debuggers. However, it's worth remembering that debuggers are
/// not the only consumers of debug info, and some variations in DWARF might
/// better be treated as target/platform issues. Fundamentally,
/// o if the feature is useful (or not) to a particular debugger, regardless
/// of the target, that's a tuning decision;
/// o if the feature is useful (or not) on a particular platform, regardless
/// of the debugger, that's a target decision.
/// It's not impossible to see both factors in some specific case.
enum class DebuggerKind {
Default, ///< No specific tuning requested.
GDB, ///< Tune debug info for gdb.
LLDB, ///< Tune debug info for lldb.
SCE, ///< Tune debug info for SCE targets (e.g. PS4).
DBX ///< Tune debug info for dbx.
};
/// Enable abort calls when global instruction selection fails to lower/select
/// an instruction.
enum class GlobalISelAbortMode {
Disable, // Disable the abort.
Enable, // Enable the abort.
DisableWithDiag // Disable the abort but emit a diagnostic on failure.
};
/// Indicates when and how the Swift async frame pointer bit should be set.
enum class SwiftAsyncFramePointerMode {
/// Determine whether to set the bit statically or dynamically based
/// on the deployment target.
DeploymentBased,
/// Always set the bit.
Always,
/// Never set the bit.
Never,
};
class TargetOptions {
public:
TargetOptions()
: UnsafeFPMath(false), NoInfsFPMath(false), NoNaNsFPMath(false),
NoTrappingFPMath(true), NoSignedZerosFPMath(false),
ApproxFuncFPMath(false), EnableAIXExtendedAltivecABI(false),
HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false),
GuaranteedTailCallOpt(false), StackSymbolOrdering(true),
EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false),
DisableIntegratedAS(false), RelaxELFRelocations(false),
FunctionSections(false), DataSections(false),
IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false),
EmitStackSizeSection(false), EnableMachineOutliner(false),
EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
EmitAddrsig(false), EmitCallSiteInfo(false),
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
XRayOmitFunctionIndex(false), DebugStrictDwarf(false),
Hotpatch(false),
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
/// DisableFramePointerElim - This returns true if frame pointer elimination
/// optimization should be disabled for the given machine function.
bool DisableFramePointerElim(const MachineFunction &MF) const;
/// If greater than 0, override the default value of
/// MCAsmInfo::BinutilsVersion.
std::pair<int, int> BinutilsVersion{0, 0};
/// UnsafeFPMath - This flag is enabled when the
/// -enable-unsafe-fp-math flag is specified on the command line. When
/// this flag is off (the default), the code generator is not allowed to
/// produce results that are "less precise" than IEEE allows. This includes
/// use of X86 instructions like FSIN and FCOS instead of libcalls.
unsigned UnsafeFPMath : 1;
/// NoInfsFPMath - This flag is enabled when the
/// -enable-no-infs-fp-math flag is specified on the command line. When
/// this flag is off (the default), the code generator is not allowed to
/// assume the FP arithmetic arguments and results are never +-Infs.
unsigned NoInfsFPMath : 1;
/// NoNaNsFPMath - This flag is enabled when the
/// -enable-no-nans-fp-math flag is specified on the command line. When
/// this flag is off (the default), the code generator is not allowed to
/// assume the FP arithmetic arguments and results are never NaNs.
unsigned NoNaNsFPMath : 1;
/// NoTrappingFPMath - This flag is enabled when the
/// -enable-no-trapping-fp-math is specified on the command line. This
/// specifies that there are no trap handlers to handle exceptions.
unsigned NoTrappingFPMath : 1;
/// NoSignedZerosFPMath - This flag is enabled when the
/// -enable-no-signed-zeros-fp-math is specified on the command line. This
/// specifies that optimizations are allowed to treat the sign of a zero
/// argument or result as insignificant.
unsigned NoSignedZerosFPMath : 1;
/// ApproxFuncFPMath - This flag is enabled when the
/// -enable-approx-func-fp-math is specified on the command line. This
/// specifies that optimizations are allowed to substitute math functions
/// with approximate calculations
unsigned ApproxFuncFPMath : 1;
/// EnableAIXExtendedAltivecABI - This flag returns true when -vec-extabi is
/// specified. The code generator is then able to use both volatile and
/// nonvolatile vector registers. When false, the code generator only uses
/// volatile vector registers which is the default setting on AIX.
unsigned EnableAIXExtendedAltivecABI : 1;
/// HonorSignDependentRoundingFPMath - This returns true when the
/// -enable-sign-dependent-rounding-fp-math is specified. If this returns
/// false (the default), the code generator is allowed to assume that the
/// rounding behavior is the default (round-to-zero for all floating point
/// to integer conversions, and round-to-nearest for all other arithmetic
/// truncations). If this is enabled (set to true), the code generator must
/// assume that the rounding mode may dynamically change.
unsigned HonorSignDependentRoundingFPMathOption : 1;
bool HonorSignDependentRoundingFPMath() const;
/// NoZerosInBSS - By default some codegens place zero-initialized data to
/// .bss section. This flag disables such behaviour (necessary, e.g. for
/// crt*.o compiling).
unsigned NoZerosInBSS : 1;
/// GuaranteedTailCallOpt - This flag is enabled when -tailcallopt is
/// specified on the commandline. When the flag is on, participating targets
/// will perform tail call optimization on all calls which use the fastcc
/// calling convention and which satisfy certain target-independent
/// criteria (being at the end of a function, having the same return type
/// as their parent function, etc.), using an alternate ABI if necessary.
unsigned GuaranteedTailCallOpt : 1;
/// StackSymbolOrdering - When true, this will allow CodeGen to order
/// the local stack symbols (for code size, code locality, or any other
/// heuristics). When false, the local symbols are left in whatever order
/// they were generated. Default is true.
unsigned StackSymbolOrdering : 1;
/// EnableFastISel - This flag enables fast-path instruction selection
/// which trades away generated code quality in favor of reducing
/// compile time.
unsigned EnableFastISel : 1;
/// EnableGlobalISel - This flag enables global instruction selection.
unsigned EnableGlobalISel : 1;
/// EnableGlobalISelAbort - Control abort behaviour when global instruction
/// selection fails to lower/select an instruction.
GlobalISelAbortMode GlobalISelAbort = GlobalISelAbortMode::Enable;
/// Control when and how the Swift async frame pointer bit should
/// be set.
SwiftAsyncFramePointerMode SwiftAsyncFramePointer =
SwiftAsyncFramePointerMode::Always;
/// UseInitArray - Use .init_array instead of .ctors for static
/// constructors.
unsigned UseInitArray : 1;
/// Disable the integrated assembler.
unsigned DisableIntegratedAS : 1;
/// Compress DWARF debug sections.
DebugCompressionType CompressDebugSections = DebugCompressionType::None;
unsigned RelaxELFRelocations : 1;
/// Emit functions into separate sections.
unsigned FunctionSections : 1;
/// Emit data into separate sections.
unsigned DataSections : 1;
/// Do not emit visibility attribute for xcoff.
unsigned IgnoreXCOFFVisibility : 1;
/// Emit XCOFF traceback table.
unsigned XCOFFTracebackTable : 1;
unsigned UniqueSectionNames : 1;
/// Use unique names for basic block sections.
unsigned UniqueBasicBlockSectionNames : 1;
/// Emit target-specific trap instruction for 'unreachable' IR instructions.
unsigned TrapUnreachable : 1;
/// Do not emit a trap instruction for 'unreachable' IR instructions behind
/// noreturn calls, even if TrapUnreachable is true.
unsigned NoTrapAfterNoreturn : 1;
/// Bit size of immediate TLS offsets (0 == use the default).
unsigned TLSSize : 8;
/// EmulatedTLS - This flag enables emulated TLS model, using emutls
/// function in the runtime library..
unsigned EmulatedTLS : 1;
/// Whether -emulated-tls or -no-emulated-tls is set.
unsigned ExplicitEmulatedTLS : 1;
/// This flag enables InterProcedural Register Allocation (IPRA).
unsigned EnableIPRA : 1;
/// Emit section containing metadata on function stack sizes.
unsigned EmitStackSizeSection : 1;
/// Enables the MachineOutliner pass.
unsigned EnableMachineOutliner : 1;
/// Enables the MachineFunctionSplitter pass.
unsigned EnableMachineFunctionSplitter : 1;
/// Set if the target supports default outlining behaviour.
unsigned SupportsDefaultOutlining : 1;
/// Emit address-significance table.
unsigned EmitAddrsig : 1;
/// Emit basic blocks into separate sections.
BasicBlockSection BBSections = BasicBlockSection::None;
/// Memory Buffer that contains information on sampled basic blocks and used
/// to selectively generate basic block sections.
std::shared_ptr<MemoryBuffer> BBSectionsFuncListBuf;
/// The flag enables call site info production. It is used only for debug
/// info, and it is restricted only to optimized code. This can be used for
/// something else, so that should be controlled in the frontend.
unsigned EmitCallSiteInfo : 1;
/// Set if the target supports the debug entry values by default.
unsigned SupportsDebugEntryValues : 1;
/// When set to true, the EnableDebugEntryValues option forces production
/// of debug entry values even if the target does not officially support
/// it. Useful for testing purposes only. This flag should never be checked
/// directly, always use \ref ShouldEmitDebugEntryValues instead.
unsigned EnableDebugEntryValues : 1;
/// NOTE: There are targets that still do not support the debug entry values
/// production.
bool ShouldEmitDebugEntryValues() const;
// When set to true, use experimental new debug variable location tracking,
// which seeks to follow the values of variables rather than their location,
// post isel.
unsigned ValueTrackingVariableLocations : 1;
/// Emit DWARF debug frame section.
unsigned ForceDwarfFrameSection : 1;
/// Emit XRay Function Index section
unsigned XRayOmitFunctionIndex : 1;
/// When set to true, don't use DWARF extensions in later DWARF versions.
/// By default, it is set to false.
unsigned DebugStrictDwarf : 1;
/// Emit the hotpatch flag in CodeView debug.
unsigned Hotpatch : 1;
/// Name of the stack usage file (i.e., .su file) if user passes
/// -fstack-usage. If empty, it can be implied that -fstack-usage is not
/// passed on the command line.
std::string StackUsageOutput;
/// If greater than 0, override TargetLoweringBase::PrefLoopAlignment.
unsigned LoopAlignment = 0;
/// FloatABIType - This setting is set by -float-abi=xxx option is specified
/// on the command line. This setting may either be Default, Soft, or Hard.
/// Default selects the target's default behavior. Soft selects the ABI for
/// software floating point, but does not indicate that FP hardware may not
/// be used. Such a combination is unfortunately popular (e.g.
/// arm-apple-darwin). Hard presumes that the normal FP ABI is used.
FloatABI::ABIType FloatABIType = FloatABI::Default;
/// AllowFPOpFusion - This flag is set by the -fp-contract=xxx option.
/// This controls the creation of fused FP ops that store intermediate
/// results in higher precision than IEEE allows (E.g. FMAs).
///
/// Fast mode - allows formation of fused FP ops whenever they're
/// profitable.
/// Standard mode - allow fusion only for 'blessed' FP ops. At present the
/// only blessed op is the fmuladd intrinsic. In the future more blessed ops
/// may be added.
/// Strict mode - allow fusion only if/when it can be proven that the excess
/// precision won't effect the result.
///
/// Note: This option only controls formation of fused ops by the
/// optimizers. Fused operations that are explicitly specified (e.g. FMA
/// via the llvm.fma.* intrinsic) will always be honored, regardless of
/// the value of this option.
FPOpFusion::FPOpFusionMode AllowFPOpFusion = FPOpFusion::Standard;
/// ThreadModel - This flag specifies the type of threading model to assume
/// for things like atomics
ThreadModel::Model ThreadModel = ThreadModel::POSIX;
/// EABIVersion - This flag specifies the EABI version
EABI EABIVersion = EABI::Default;
/// Which debugger to tune for.
DebuggerKind DebuggerTuning = DebuggerKind::Default;
private:
/// Flushing mode to assume in default FP environment.
DenormalMode FPDenormalMode;
/// Flushing mode to assume in default FP environment, for float/vector of
/// float.
DenormalMode FP32DenormalMode;
public:
void setFPDenormalMode(DenormalMode Mode) {
FPDenormalMode = Mode;
}
void setFP32DenormalMode(DenormalMode Mode) {
FP32DenormalMode = Mode;
}
DenormalMode getRawFPDenormalMode() const {
return FPDenormalMode;
}
DenormalMode getRawFP32DenormalMode() const {
return FP32DenormalMode;
}
DenormalMode getDenormalMode(const fltSemantics &FPType) const;
/// What exception model to use
ExceptionHandling ExceptionModel = ExceptionHandling::None;
/// Machine level options.
MCTargetOptions MCOptions;
/// Stores the filename/path of the final .o/.obj file, to be written in the
/// debug information. This is used for emitting the CodeView S_OBJNAME
/// record.
std::string ObjectFilenameForDebug;
};
} // End llvm namespace
#endif

View File

@@ -0,0 +1,51 @@
//===- TargetPfmCounters.td - Target Pfm Counters -*- 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 target-independent interfaces for performance counters.
//
//===----------------------------------------------------------------------===//
// Definition of a hardware counters from libpfm identifiers.
class PfmCounter<string counter> {
// The name of the counter that measures events.
// The name can be "some_counter + some_other_counter", in which case the
// measured value is the sum of events on these counters.
string Counter = counter;
}
// Issue counters can be tied to a ProcResource
class PfmIssueCounter<string resource_name, string counter>
: PfmCounter<counter> {
// The name of the ProcResource on which uops are issued. This is used by
// llvm-exegesis to compare measurements with values in the SchedModels.
// If the CPU has a sched model, this should correspond to the name of a
// ProcResource.
string ResourceName = resource_name;
}
def NoPfmCounter : PfmCounter <""> {}
// Set of PfmCounters for measuring sched model characteristics.
class ProcPfmCounters {
// Processors can define how to measure cycles by defining a CycleCounter.
PfmCounter CycleCounter = NoPfmCounter;
// Processors can define how to measure uops by defining a UopsCounter.
PfmCounter UopsCounter = NoPfmCounter;
// Processors can define how to measure issued uops by defining IssueCounters.
list<PfmIssueCounter> IssueCounters = [];
}
// A binding of a set of counters to a CPU.
class PfmCountersBinding<string cpu_name, ProcPfmCounters counters> {
string CpuName = cpu_name;
ProcPfmCounters Counters = counters;
}
// Declares the default binding for unbound CPUs for the target.
class PfmCountersDefaultBinding<ProcPfmCounters counters>
: PfmCountersBinding<"", counters> {}

View File

@@ -0,0 +1,574 @@
//===- TargetSchedule.td - Target Independent Scheduling ---*- 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 target-independent scheduling interfaces which should
// be implemented by each target which is using TableGen based scheduling.
//
// The SchedMachineModel is defined by subtargets for three categories of data:
// 1. Basic properties for coarse grained instruction cost model.
// 2. Scheduler Read/Write resources for simple per-opcode cost model.
// 3. Instruction itineraries for detailed reservation tables.
//
// (1) Basic properties are defined by the SchedMachineModel
// class. Target hooks allow subtargets to associate opcodes with
// those properties.
//
// (2) A per-operand machine model can be implemented in any
// combination of the following ways:
//
// A. Associate per-operand SchedReadWrite types with Instructions by
// modifying the Instruction definition to inherit from Sched. For
// each subtarget, define WriteRes and ReadAdvance to associate
// processor resources and latency with each SchedReadWrite type.
//
// B. In each instruction definition, name an ItineraryClass. For each
// subtarget, define ItinRW entries to map ItineraryClass to
// per-operand SchedReadWrite types. Unlike method A, these types may
// be subtarget specific and can be directly associated with resources
// by defining SchedWriteRes and SchedReadAdvance.
//
// C. In the subtarget, map SchedReadWrite types to specific
// opcodes. This overrides any SchedReadWrite types or
// ItineraryClasses defined by the Instruction. As in method B, the
// subtarget can directly associate resources with SchedReadWrite
// types by defining SchedWriteRes and SchedReadAdvance.
//
// D. In either the target or subtarget, define SchedWriteVariant or
// SchedReadVariant to map one SchedReadWrite type onto another
// sequence of SchedReadWrite types. This allows dynamic selection of
// an instruction's machine model via custom C++ code. It also allows
// a machine-independent SchedReadWrite type to map to a sequence of
// machine-dependent types.
//
// (3) A per-pipeline-stage machine model can be implemented by providing
// Itineraries in addition to mapping instructions to ItineraryClasses.
//===----------------------------------------------------------------------===//
// Include legacy support for instruction itineraries.
include "llvm/Target/TargetItinerary.td"
class Predicate; // Forward def
// DAG operator that interprets the DAG args as Instruction defs.
def instrs;
// DAG operator that interprets each DAG arg as a regex pattern for
// matching Instruction opcode names.
// The regex must match the beginning of the opcode (as in Python re.match).
// To avoid matching prefixes, append '$' to the pattern.
def instregex;
// Define the SchedMachineModel and provide basic properties for
// coarse grained instruction cost model. Default values for the
// properties are defined in MCSchedModel. A value of "-1" in the
// target description's SchedMachineModel indicates that the property
// is not overridden by the target.
//
// Target hooks allow subtargets to associate LoadLatency and
// HighLatency with groups of opcodes.
//
// See MCSchedule.h for detailed comments.
class SchedMachineModel {
int IssueWidth = -1; // Max micro-ops that may be scheduled per cycle.
int MicroOpBufferSize = -1; // Max micro-ops that can be buffered.
int LoopMicroOpBufferSize = -1; // Max micro-ops that can be buffered for
// optimized loop dispatch/execution.
int LoadLatency = -1; // Cycles for loads to access the cache.
int HighLatency = -1; // Approximation of cycles for "high latency" ops.
int MispredictPenalty = -1; // Extra cycles for a mispredicted branch.
// Per-cycle resources tables.
ProcessorItineraries Itineraries = NoItineraries;
bit PostRAScheduler = false; // Enable Post RegAlloc Scheduler pass.
// Subtargets that define a model for only a subset of instructions
// that have a scheduling class (itinerary class or SchedRW list)
// and may actually be generated for that subtarget must clear this
// bit. Otherwise, the scheduler considers an unmodelled opcode to
// be an error. This should only be set during initial bringup,
// or there will be no way to catch simple errors in the model
// resulting from changes to the instruction definitions.
bit CompleteModel = true;
// Indicates that we should do full overlap checking for multiple InstrRWs
// defining the same instructions within the same SchedMachineModel.
// FIXME: Remove when all in tree targets are clean with the full check
// enabled.
bit FullInstRWOverlapCheck = true;
// A processor may only implement part of published ISA, due to either new ISA
// extensions, (e.g. Pentium 4 doesn't have AVX) or implementation
// (ARM/MIPS/PowerPC/SPARC soft float cores).
//
// For a processor which doesn't support some feature(s), the schedule model
// can use:
//
// let<Predicate> UnsupportedFeatures = [HaveA,..,HaveY];
//
// to skip the checks for scheduling information when building LLVM for
// instructions which have any of the listed predicates in their Predicates
// field.
list<Predicate> UnsupportedFeatures = [];
bit NoModel = false; // Special tag to indicate missing machine model.
}
def NoSchedModel : SchedMachineModel {
let NoModel = true;
let CompleteModel = false;
}
// Define a kind of processor resource that may be common across
// similar subtargets.
class ProcResourceKind;
// Define a number of interchangeable processor resources. NumUnits
// determines the throughput of instructions that require the resource.
//
// An optional Super resource may be given to model these resources as
// a subset of the more general super resources. Using one of these
// resources implies using one of the super resources.
//
// ProcResourceUnits normally model a few buffered resources within an
// out-of-order engine. Buffered resources may be held for multiple
// clock cycles, but the scheduler does not pin them to a particular
// clock cycle relative to instruction dispatch. Setting BufferSize=0
// changes this to an in-order issue/dispatch resource. In this case,
// the scheduler counts down from the cycle that the instruction
// issues in-order, forcing a stall whenever a subsequent instruction
// requires the same resource until the number of ResourceCycles
// specified in WriteRes expire. Setting BufferSize=1 changes this to
// an in-order latency resource. In this case, the scheduler models
// producer/consumer stalls between instructions that use the
// resource.
//
// Examples (all assume an out-of-order engine):
//
// Use BufferSize = -1 for "issue ports" fed by a unified reservation
// station. Here the size of the reservation station is modeled by
// MicroOpBufferSize, which should be the minimum size of either the
// register rename pool, unified reservation station, or reorder
// buffer.
//
// Use BufferSize = 0 for resources that force "dispatch/issue
// groups". (Different processors define dispath/issue
// differently. Here we refer to stage between decoding into micro-ops
// and moving them into a reservation station.) Normally NumMicroOps
// is sufficient to limit dispatch/issue groups. However, some
// processors can form groups of with only certain combinations of
// instruction types. e.g. POWER7.
//
// Use BufferSize = 1 for in-order execution units. This is used for
// an in-order pipeline within an out-of-order core where scheduling
// dependent operations back-to-back is guaranteed to cause a
// bubble. e.g. Cortex-a9 floating-point.
//
// Use BufferSize > 1 for out-of-order executions units with a
// separate reservation station. This simply models the size of the
// reservation station.
//
// To model both dispatch/issue groups and in-order execution units,
// create two types of units, one with BufferSize=0 and one with
// BufferSize=1.
//
// SchedModel ties these units to a processor for any stand-alone defs
// of this class.
class ProcResourceUnits<ProcResourceKind kind, int num> {
ProcResourceKind Kind = kind;
int NumUnits = num;
ProcResourceKind Super = ?;
int BufferSize = -1;
SchedMachineModel SchedModel = ?;
}
// EponymousProcResourceKind helps implement ProcResourceUnits by
// allowing a ProcResourceUnits definition to reference itself. It
// should not be referenced anywhere else.
def EponymousProcResourceKind : ProcResourceKind;
// Subtargets typically define processor resource kind and number of
// units in one place.
class ProcResource<int num> : ProcResourceKind,
ProcResourceUnits<EponymousProcResourceKind, num>;
class ProcResGroup<list<ProcResource> resources> : ProcResourceKind {
list<ProcResource> Resources = resources;
SchedMachineModel SchedModel = ?;
int BufferSize = -1;
}
// A target architecture may define SchedReadWrite types and associate
// them with instruction operands.
class SchedReadWrite;
// List the per-operand types that map to the machine model of an
// instruction. One SchedWrite type must be listed for each explicit
// def operand in order. Additional SchedWrite types may optionally be
// listed for implicit def operands. SchedRead types may optionally
// be listed for use operands in order. The order of defs relative to
// uses is insignificant. This way, the same SchedReadWrite list may
// be used for multiple forms of an operation. For example, a
// two-address instruction could have two tied operands or single
// operand that both reads and writes a reg. In both cases we have a
// single SchedWrite and single SchedRead in any order.
class Sched<list<SchedReadWrite> schedrw> {
list<SchedReadWrite> SchedRW = schedrw;
}
// Define a scheduler resource associated with a def operand.
class SchedWrite : SchedReadWrite;
def NoWrite : SchedWrite;
// Define a scheduler resource associated with a use operand.
class SchedRead : SchedReadWrite;
// Define a SchedWrite that is modeled as a sequence of other
// SchedWrites with additive latency. This allows a single operand to
// be mapped the resources composed from a set of previously defined
// SchedWrites.
//
// If the final write in this sequence is a SchedWriteVariant marked
// Variadic, then the list of prior writes are distributed across all
// operands after resolving the predicate for the final write.
//
// SchedModel silences warnings but is ignored.
class WriteSequence<list<SchedWrite> writes, int rep = 1> : SchedWrite {
list<SchedWrite> Writes = writes;
int Repeat = rep;
SchedMachineModel SchedModel = ?;
}
// Define values common to WriteRes and SchedWriteRes.
//
// SchedModel ties these resources to a processor.
class ProcWriteResources<list<ProcResourceKind> resources> {
list<ProcResourceKind> ProcResources = resources;
list<int> ResourceCycles = [];
int Latency = 1;
int NumMicroOps = 1;
bit BeginGroup = false;
bit EndGroup = false;
// Allow a processor to mark some scheduling classes as unsupported
// for stronger verification.
bit Unsupported = false;
// Allow a processor to mark some scheduling classes as single-issue.
// SingleIssue is an alias for Begin/End Group.
bit SingleIssue = false;
// An instruction is allowed to retire out-of-order if RetireOOO is
// true for at least one of its writes. This field is only used by
// MCA for in-order subtargets, and is ignored for other targets.
bit RetireOOO = false;
SchedMachineModel SchedModel = ?;
}
// Define the resources and latency of a SchedWrite. This will be used
// directly by targets that have no itinerary classes. In this case,
// SchedWrite is defined by the target, while WriteResources is
// defined by the subtarget, and maps the SchedWrite to processor
// resources.
//
// If a target already has itinerary classes, SchedWriteResources can
// be used instead to define subtarget specific SchedWrites and map
// them to processor resources in one place. Then ItinRW can map
// itinerary classes to the subtarget's SchedWrites.
//
// ProcResources indicates the set of resources consumed by the write.
// Optionally, ResourceCycles indicates the number of cycles the
// resource is consumed. Each ResourceCycles item is paired with the
// ProcResource item at the same position in its list. ResourceCycles
// can be `[]`: in that case, all resources are consumed for a single
// cycle, regardless of latency, which models a fully pipelined processing
// unit. A value of 0 for ResourceCycles means that the resource must
// be available but is not consumed, which is only relevant for
// unbuffered resources.
//
// By default, each SchedWrite takes one micro-op, which is counted
// against the processor's IssueWidth limit. If an instruction can
// write multiple registers with a single micro-op, the subtarget
// should define one of the writes to be zero micro-ops. If a
// subtarget requires multiple micro-ops to write a single result, it
// should either override the write's NumMicroOps to be greater than 1
// or require additional writes. Extra writes can be required either
// by defining a WriteSequence, or simply listing extra writes in the
// instruction's list of writers beyond the number of "def"
// operands. The scheduler assumes that all micro-ops must be
// dispatched in the same cycle. These micro-ops may be required to
// begin or end the current dispatch group.
class WriteRes<SchedWrite write, list<ProcResourceKind> resources>
: ProcWriteResources<resources> {
SchedWrite WriteType = write;
}
// Directly name a set of WriteResources defining a new SchedWrite
// type at the same time. This class is unaware of its SchedModel so
// must be referenced by InstRW or ItinRW.
class SchedWriteRes<list<ProcResourceKind> resources> : SchedWrite,
ProcWriteResources<resources>;
// Define values common to ReadAdvance and SchedReadAdvance.
//
// SchedModel ties these resources to a processor.
class ProcReadAdvance<int cycles, list<SchedWrite> writes = []> {
int Cycles = cycles;
list<SchedWrite> ValidWrites = writes;
// Allow a processor to mark some scheduling classes as unsupported
// for stronger verification.
bit Unsupported = false;
SchedMachineModel SchedModel = ?;
}
// A processor may define a ReadAdvance associated with a SchedRead
// to reduce latency of a prior write by N cycles. A negative advance
// effectively increases latency, which may be used for cross-domain
// stalls.
//
// A ReadAdvance may be associated with a list of SchedWrites
// to implement pipeline bypass. The Writes list may be empty to
// indicate operands that are always read this number of Cycles later
// than a normal register read, allowing the read's parent instruction
// to issue earlier relative to the writer.
class ReadAdvance<SchedRead read, int cycles, list<SchedWrite> writes = []>
: ProcReadAdvance<cycles, writes> {
SchedRead ReadType = read;
}
// Directly associate a new SchedRead type with a delay and optional
// pipeline bypass. For use with InstRW or ItinRW.
class SchedReadAdvance<int cycles, list<SchedWrite> writes = []> : SchedRead,
ProcReadAdvance<cycles, writes>;
// Define SchedRead defaults. Reads seldom need special treatment.
def ReadDefault : SchedRead;
def NoReadAdvance : SchedReadAdvance<0>;
// Define shared code that will be in the same scope as all
// SchedPredicates. Available variables are:
// (const MachineInstr *MI, const TargetSchedModel *SchedModel)
class PredicateProlog<code c> {
code Code = c;
}
// Base class for scheduling predicates.
class SchedPredicateBase;
// A scheduling predicate whose logic is defined by a MCInstPredicate.
// This can directly be used by SchedWriteVariant definitions.
class MCSchedPredicate<MCInstPredicate P> : SchedPredicateBase {
MCInstPredicate Pred = P;
SchedMachineModel SchedModel = ?;
}
// Define a predicate to determine which SchedVariant applies to a
// particular MachineInstr. The code snippet is used as an
// if-statement's expression. Available variables are MI, SchedModel,
// and anything defined in a PredicateProlog.
//
// SchedModel silences warnings but is ignored.
class SchedPredicate<code pred> : SchedPredicateBase {
SchedMachineModel SchedModel = ?;
code Predicate = pred;
}
// Define a predicate to be typically used as the default case in a
// SchedVariant. It the SchedVariant does not use any other predicate based on
// MCSchedPredicate, this is the default scheduling case used by llvm-mca.
def NoSchedPred : MCSchedPredicate<TruePred>;
// Associate a predicate with a list of SchedReadWrites. By default,
// the selected SchedReadWrites are still associated with a single
// operand and assumed to execute sequentially with additive
// latency. However, if the parent SchedWriteVariant or
// SchedReadVariant is marked "Variadic", then each Selected
// SchedReadWrite is mapped in place to the instruction's variadic
// operands. In this case, latency is not additive. If the current Variant
// is already part of a Sequence, then that entire chain leading up to
// the Variant is distributed over the variadic operands.
class SchedVar<SchedPredicateBase pred, list<SchedReadWrite> selected> {
SchedPredicateBase Predicate = pred;
list<SchedReadWrite> Selected = selected;
}
// SchedModel silences warnings but is ignored.
class SchedVariant<list<SchedVar> variants> {
list<SchedVar> Variants = variants;
bit Variadic = false;
SchedMachineModel SchedModel = ?;
}
// A SchedWriteVariant is a single SchedWrite type that maps to a list
// of SchedWrite types under the conditions defined by its predicates.
//
// A Variadic write is expanded to cover multiple "def" operands. The
// SchedVariant's Expansion list is then interpreted as one write
// per-operand instead of the usual sequential writes feeding a single
// operand.
class SchedWriteVariant<list<SchedVar> variants> : SchedWrite,
SchedVariant<variants> {
}
// A SchedReadVariant is a single SchedRead type that maps to a list
// of SchedRead types under the conditions defined by its predicates.
//
// A Variadic write is expanded to cover multiple "readsReg" operands as
// explained above.
class SchedReadVariant<list<SchedVar> variants> : SchedRead,
SchedVariant<variants> {
}
// Map a set of opcodes to a list of SchedReadWrite types. This allows
// the subtarget to easily override specific operations.
//
// SchedModel ties this opcode mapping to a processor.
class InstRW<list<SchedReadWrite> rw, dag instrlist> {
list<SchedReadWrite> OperandReadWrites = rw;
dag Instrs = instrlist;
SchedMachineModel SchedModel = ?;
// Allow a subtarget to mark some instructions as unsupported.
bit Unsupported = false;
}
// Map a set of itinerary classes to SchedReadWrite resources. This is
// used to bootstrap a target (e.g. ARM) when itineraries already
// exist and changing InstrInfo is undesirable.
//
// SchedModel ties this ItineraryClass mapping to a processor.
class ItinRW<list<SchedReadWrite> rw, list<InstrItinClass> iic> {
list<InstrItinClass> MatchedItinClasses = iic;
list<SchedReadWrite> OperandReadWrites = rw;
SchedMachineModel SchedModel = ?;
}
// Alias a target-defined SchedReadWrite to a processor specific
// SchedReadWrite. This allows a subtarget to easily map a
// SchedReadWrite type onto a WriteSequence, SchedWriteVariant, or
// SchedReadVariant.
//
// SchedModel will usually be provided by surrounding let statement
// and ties this SchedAlias mapping to a processor.
class SchedAlias<SchedReadWrite match, SchedReadWrite alias> {
SchedReadWrite MatchRW = match;
SchedReadWrite AliasRW = alias;
SchedMachineModel SchedModel = ?;
}
// Allow the definition of processor register files for register renaming
// purposes.
//
// Each processor register file declares:
// - The set of registers that can be renamed.
// - The number of physical registers which can be used for register renaming
// purpose.
// - The cost of a register rename.
// - The set of registers that allow move elimination.
// - The maximum number of moves that can be eliminated every cycle.
// - Whether move elimination is limited to register moves whose input
// is known to be zero.
//
// The cost of a rename is the number of physical registers allocated by the
// register alias table to map the new definition. By default, register can be
// renamed at the cost of a single physical register. Note that register costs
// are defined at register class granularity (see field `Costs`).
//
// The set of registers that are subject to register renaming is declared using
// a list of register classes (see field `RegClasses`). An empty list of
// register classes means: all the logical registers defined by the target can
// be fully renamed.
//
// A register R can be renamed if its register class appears in the `RegClasses`
// set. When R is written, a new alias is allocated at the cost of one or more
// physical registers; as a result, false dependencies on R are removed.
//
// A sub-register V of register R is implicitly part of the same register file.
// However, V is only renamed if its register class is part of `RegClasses`.
// Otherwise, the processor keeps it (as well as any other different part
// of R) together with R, and a write of V always causes a compulsory read of R.
//
// This is what happens for example on AMD processors (at least from Bulldozer
// onwards), where AL and AH are not treated as independent from AX, and AX is
// not treated as independent from EAX. A write to AL has an implicitly false
// dependency on the last write to EAX (or a portion of EAX). As a consequence,
// a write to AL cannot go in parallel with a write to AH.
//
// There is no false dependency if the partial register write belongs to a
// register class that is in `RegClasses`.
// There is also no penalty for writes that "clear the content a super-register"
// (see MC/MCInstrAnalysis.h - method MCInstrAnalysis::clearsSuperRegisters()).
// On x86-64, 32-bit GPR writes implicitly zero the upper half of the underlying
// physical register, effectively removing any false dependencies with the
// previous register definition.
//
// TODO: This implementation assumes that there is no limit in the number of
// renames per cycle, which might not be true for all hardware or register
// classes. Also, there is no limit to how many times the same logical register
// can be renamed during the same cycle.
//
// TODO: we don't currently model merge penalties for the case where a write to
// a part of a register is followed by a read from a larger part of the same
// register. On some Intel chips, different parts of a GPR can be stored in
// different physical registers. However, there is a cost to pay for when the
// partial write is combined with the previous super-register definition. We
// should add support for these cases, and correctly model merge problems with
// partial register accesses.
//
// Field MaxMovesEliminatedPerCycle specifies how many moves can be eliminated
// every cycle. A default value of zero for that field means: there is no limit
// to the number of moves that can be eliminated by this register file.
//
// An instruction MI is a candidate for move elimination if a call to
// method TargetSubtargetInfo::isOptimizableRegisterMove(MI) returns true (see
// llvm/CodeGen/TargetSubtargetInfo.h, and llvm/MC/MCInstrAnalysis.h).
//
// Subtargets can instantiate tablegen class IsOptimizableRegisterMove (see
// llvm/Target/TargetInstrPredicate.td) to customize the set of move elimination
// candidates. By default, no instruction is a valid move elimination candidate.
//
// A register move MI is eliminated only if:
// - MI is a move elimination candidate.
// - The destination register is from a register class that allows move
// elimination (see field `AllowMoveElimination` below).
// - Constraints on the move kind, and the maximum number of moves that can be
// eliminated per cycle are all met.
class RegisterFile<int numPhysRegs, list<RegisterClass> Classes = [],
list<int> Costs = [], list<bit> AllowMoveElim = [],
int MaxMoveElimPerCy = 0, bit AllowZeroMoveElimOnly = false> {
list<RegisterClass> RegClasses = Classes;
list<int> RegCosts = Costs;
list<bit> AllowMoveElimination = AllowMoveElim;
int NumPhysRegs = numPhysRegs;
int MaxMovesEliminatedPerCycle = MaxMoveElimPerCy;
bit AllowZeroMoveEliminationOnly = AllowZeroMoveElimOnly;
SchedMachineModel SchedModel = ?;
}
// Describe the retire control unit.
// A retire control unit specifies the size of the reorder buffer, as well as
// the maximum number of opcodes that can be retired every cycle.
// A value less-than-or-equal-to zero for field 'ReorderBufferSize' means: "the
// size is unknown". The idea is that external tools can fall-back to using
// field MicroOpBufferSize in SchedModel if the reorder buffer size is unknown.
// A zero or negative value for field 'MaxRetirePerCycle' means "no
// restrictions on the number of instructions retired per cycle".
// Models can optionally specify up to one instance of RetireControlUnit per
// scheduling model.
class RetireControlUnit<int bufferSize, int retirePerCycle> {
int ReorderBufferSize = bufferSize;
int MaxRetirePerCycle = retirePerCycle;
SchedMachineModel SchedModel = ?;
}
// Base class for Load/StoreQueue. It is used to identify processor resources
// which describe load/store queues in the LS unit.
class MemoryQueue<ProcResourceKind PR> {
ProcResourceKind QueueDescriptor = PR;
SchedMachineModel SchedModel = ?;
}
class LoadQueue<ProcResourceKind LDQueue> : MemoryQueue<LDQueue>;
class StoreQueue<ProcResourceKind STQueue> : MemoryQueue<STQueue>;

File diff suppressed because it is too large Load Diff