Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- Combine.td - Combine rule definitions ---------------*- tablegen -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // Declare GlobalISel combine rules and provide mechanisms to opt-out. |
||
| 10 | // |
||
| 11 | //===----------------------------------------------------------------------===// |
||
| 12 | |||
| 13 | // Common base class for GICombineRule and GICombineGroup. |
||
| 14 | class GICombine { |
||
| 15 | // See GICombineGroup. We only declare it here to make the tablegen pass |
||
| 16 | // simpler. |
||
| 17 | list<GICombine> Rules = ?; |
||
| 18 | } |
||
| 19 | |||
| 20 | // A group of combine rules that can be added to a GICombiner or another group. |
||
| 21 | class GICombineGroup<list<GICombine> rules> : GICombine { |
||
| 22 | // The rules contained in this group. The rules in a group are flattened into |
||
| 23 | // a single list and sorted into whatever order is most efficient. However, |
||
| 24 | // they will never be re-ordered such that behaviour differs from the |
||
| 25 | // specified order. It is therefore possible to use the order of rules in this |
||
| 26 | // list to describe priorities. |
||
| 27 | let Rules = rules; |
||
| 28 | } |
||
| 29 | |||
| 30 | class GICombinerHelperArg<string type, string name> { |
||
| 31 | string Type = type; |
||
| 32 | string Name = name; |
||
| 33 | } |
||
| 34 | |||
| 35 | // Declares a combiner helper class |
||
| 36 | class GICombinerHelper<string classname, list<GICombine> rules> |
||
| 37 | : GICombineGroup<rules> { |
||
| 38 | // The class name to use in the generated output. |
||
| 39 | string Classname = classname; |
||
| 40 | // The name of a run-time compiler option that will be generated to disable |
||
| 41 | // specific rules within this combiner. |
||
| 42 | string DisableRuleOption = ?; |
||
| 43 | // The state class to inherit from (if any). The generated helper will inherit |
||
| 44 | // from this class and will forward arguments to its constructors. |
||
| 45 | string StateClass = ""; |
||
| 46 | // Any additional arguments that should be appended to the tryCombine*(). |
||
| 47 | list<GICombinerHelperArg> AdditionalArguments = |
||
| 48 | [GICombinerHelperArg<"CombinerHelper &", "Helper">]; |
||
| 49 | } |
||
| 50 | class GICombineRule<dag defs, dag match, dag apply> : GICombine { |
||
| 51 | /// Defines the external interface of the match rule. This includes: |
||
| 52 | /// * The names of the root nodes (requires at least one) |
||
| 53 | /// See GIDefKind for details. |
||
| 54 | dag Defs = defs; |
||
| 55 | |||
| 56 | /// Defines the things which must be true for the pattern to match |
||
| 57 | /// See GIMatchKind for details. |
||
| 58 | dag Match = match; |
||
| 59 | |||
| 60 | /// Defines the things which happen after the decision is made to apply a |
||
| 61 | /// combine rule. |
||
| 62 | /// See GIApplyKind for details. |
||
| 63 | dag Apply = apply; |
||
| 64 | |||
| 65 | /// Defines the predicates that are checked before the match function |
||
| 66 | /// is called. Targets can use this to, for instance, check Subtarget |
||
| 67 | /// features. |
||
| 68 | list<Predicate> Predicates = []; |
||
| 69 | } |
||
| 70 | |||
| 71 | /// The operator at the root of a GICombineRule.Defs dag. |
||
| 72 | def defs; |
||
| 73 | |||
| 74 | /// All arguments of the defs operator must be subclasses of GIDefKind or |
||
| 75 | /// sub-dags whose operator is GIDefKindWithArgs. |
||
| 76 | class GIDefKind; |
||
| 77 | class GIDefKindWithArgs; |
||
| 78 | /// Declare a root node. There must be at least one of these in every combine |
||
| 79 | /// rule. |
||
| 80 | /// TODO: The plan is to elide `root` definitions and determine it from the DAG |
||
| 81 | /// itself with an overide for situations where the usual determination |
||
| 82 | /// is incorrect. |
||
| 83 | def root : GIDefKind; |
||
| 84 | |||
| 85 | /// Declares data that is passed from the match stage to the apply stage. |
||
| 86 | class GIDefMatchData<string type> : GIDefKind { |
||
| 87 | /// A C++ type name indicating the storage type. |
||
| 88 | string Type = type; |
||
| 89 | } |
||
| 90 | |||
| 91 | def extending_load_matchdata : GIDefMatchData<"PreferredTuple">; |
||
| 92 | def indexed_load_store_matchdata : GIDefMatchData<"IndexedLoadStoreMatchInfo">; |
||
| 93 | def instruction_steps_matchdata: GIDefMatchData<"InstructionStepsMatchInfo">; |
||
| 94 | |||
| 95 | /// The operator at the root of a GICombineRule.Match dag. |
||
| 96 | def match; |
||
| 97 | /// All arguments of the match operator must be either: |
||
| 98 | /// * A subclass of GIMatchKind |
||
| 99 | /// * A subclass of GIMatchKindWithArgs |
||
| 100 | /// * A subclass of Instruction |
||
| 101 | /// * A MIR code block (deprecated) |
||
| 102 | /// The GIMatchKind and GIMatchKindWithArgs cases are described in more detail |
||
| 103 | /// in their definitions below. |
||
| 104 | /// For the Instruction case, these are collected into a DAG where operand names |
||
| 105 | /// that occur multiple times introduce edges. |
||
| 106 | class GIMatchKind; |
||
| 107 | class GIMatchKindWithArgs; |
||
| 108 | |||
| 109 | /// In lieu of having proper macro support. Trivial one-off opcode checks can be |
||
| 110 | /// performed with this. |
||
| 111 | def wip_match_opcode : GIMatchKindWithArgs; |
||
| 112 | |||
| 113 | /// The operator at the root of a GICombineRule.Apply dag. |
||
| 114 | def apply; |
||
| 115 | /// All arguments of the apply operator must be subclasses of GIApplyKind, or |
||
| 116 | /// sub-dags whose operator is GIApplyKindWithArgs, or an MIR block |
||
| 117 | /// (deprecated). |
||
| 118 | class GIApplyKind; |
||
| 119 | class GIApplyKindWithArgs; |
||
| 120 | |||
| 121 | def register_matchinfo: GIDefMatchData<"Register">; |
||
| 122 | def int64_matchinfo: GIDefMatchData<"int64_t">; |
||
| 123 | def apint_matchinfo : GIDefMatchData<"APInt">; |
||
| 124 | def build_fn_matchinfo : |
||
| 125 | GIDefMatchData<"std::function<void(MachineIRBuilder &)>">; |
||
| 126 | def unsigned_matchinfo: GIDefMatchData<"unsigned">; |
||
| 127 | |||
| 128 | def copy_prop : GICombineRule< |
||
| 129 | (defs root:$d), |
||
| 130 | (match (COPY $d, $s):$mi, |
||
| 131 | [{ return Helper.matchCombineCopy(*${mi}); }]), |
||
| 132 | (apply [{ Helper.applyCombineCopy(*${mi}); }])>; |
||
| 133 | |||
| 134 | // idempotent operations |
||
| 135 | // Fold (freeze (freeze x)) -> (freeze x). |
||
| 136 | // Fold (fabs (fabs x)) -> (fabs x). |
||
| 137 | // Fold (fcanonicalize (fcanonicalize x)) -> (fcanonicalize x). |
||
| 138 | def idempotent_prop : GICombineRule< |
||
| 139 | (defs root:$mi), |
||
| 140 | (match (wip_match_opcode G_FREEZE, G_FABS, G_FCANONICALIZE):$mi, |
||
| 141 | [{ return MRI.getVRegDef(${mi}->getOperand(1).getReg())->getOpcode() == |
||
| 142 | ${mi}->getOpcode(); }]), |
||
| 143 | (apply [{ Helper.replaceSingleDefInstWithOperand(*${mi}, 1); }])>; |
||
| 144 | |||
| 145 | |||
| 146 | def extending_loads : GICombineRule< |
||
| 147 | (defs root:$root, extending_load_matchdata:$matchinfo), |
||
| 148 | (match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD):$root, |
||
| 149 | [{ return Helper.matchCombineExtendingLoads(*${root}, ${matchinfo}); }]), |
||
| 150 | (apply [{ Helper.applyCombineExtendingLoads(*${root}, ${matchinfo}); }])>; |
||
| 151 | |||
| 152 | def load_and_mask : GICombineRule< |
||
| 153 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 154 | (match (wip_match_opcode G_AND):$root, |
||
| 155 | [{ return Helper.matchCombineLoadWithAndMask(*${root}, ${matchinfo}); }]), |
||
| 156 | (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; |
||
| 157 | def combines_for_extload: GICombineGroup<[extending_loads, load_and_mask]>; |
||
| 158 | |||
| 159 | def sext_trunc_sextload : GICombineRule< |
||
| 160 | (defs root:$d), |
||
| 161 | (match (wip_match_opcode G_SEXT_INREG):$d, |
||
| 162 | [{ return Helper.matchSextTruncSextLoad(*${d}); }]), |
||
| 163 | (apply [{ Helper.applySextTruncSextLoad(*${d}); }])>; |
||
| 164 | |||
| 165 | def sext_inreg_of_load_matchdata : GIDefMatchData<"std::tuple<Register, unsigned>">; |
||
| 166 | def sext_inreg_of_load : GICombineRule< |
||
| 167 | (defs root:$root, sext_inreg_of_load_matchdata:$matchinfo), |
||
| 168 | (match (wip_match_opcode G_SEXT_INREG):$root, |
||
| 169 | [{ return Helper.matchSextInRegOfLoad(*${root}, ${matchinfo}); }]), |
||
| 170 | (apply [{ Helper.applySextInRegOfLoad(*${root}, ${matchinfo}); }])>; |
||
| 171 | |||
| 172 | def sext_inreg_to_zext_inreg : GICombineRule< |
||
| 173 | (defs root:$dst), |
||
| 174 | (match |
||
| 175 | (G_SEXT_INREG $dst, $src, $imm):$root, |
||
| 176 | [{ |
||
| 177 | unsigned BitWidth = MRI.getType(${src}.getReg()).getScalarSizeInBits(); |
||
| 178 | return Helper.getKnownBits()->maskedValueIsZero(${src}.getReg(), |
||
| 179 | APInt::getOneBitSet(BitWidth, ${imm}.getImm() - 1)); }]), |
||
| 180 | (apply [{ |
||
| 181 | Helper.getBuilder().setInstrAndDebugLoc(*${root}); |
||
| 182 | Helper.getBuilder().buildZExtInReg(${dst}, ${src}, ${imm}.getImm()); |
||
| 183 | ${root}->eraseFromParent(); |
||
| 184 | return true; |
||
| 185 | }]) |
||
| 186 | >; |
||
| 187 | |||
| 188 | def combine_indexed_load_store : GICombineRule< |
||
| 189 | (defs root:$root, indexed_load_store_matchdata:$matchinfo), |
||
| 190 | (match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD, G_STORE):$root, |
||
| 191 | [{ return Helper.matchCombineIndexedLoadStore(*${root}, ${matchinfo}); }]), |
||
| 192 | (apply [{ Helper.applyCombineIndexedLoadStore(*${root}, ${matchinfo}); }])>; |
||
| 193 | |||
| 194 | def opt_brcond_by_inverting_cond_matchdata : GIDefMatchData<"MachineInstr *">; |
||
| 195 | def opt_brcond_by_inverting_cond : GICombineRule< |
||
| 196 | (defs root:$root, opt_brcond_by_inverting_cond_matchdata:$matchinfo), |
||
| 197 | (match (wip_match_opcode G_BR):$root, |
||
| 198 | [{ return Helper.matchOptBrCondByInvertingCond(*${root}, ${matchinfo}); }]), |
||
| 199 | (apply [{ Helper.applyOptBrCondByInvertingCond(*${root}, ${matchinfo}); }])>; |
||
| 200 | |||
| 201 | def ptr_add_immed_matchdata : GIDefMatchData<"PtrAddChain">; |
||
| 202 | def ptr_add_immed_chain : GICombineRule< |
||
| 203 | (defs root:$d, ptr_add_immed_matchdata:$matchinfo), |
||
| 204 | (match (wip_match_opcode G_PTR_ADD):$d, |
||
| 205 | [{ return Helper.matchPtrAddImmedChain(*${d}, ${matchinfo}); }]), |
||
| 206 | (apply [{ Helper.applyPtrAddImmedChain(*${d}, ${matchinfo}); }])>; |
||
| 207 | |||
| 208 | // Fold shift (shift base x), y -> shift base, (x+y), if shifts are same |
||
| 209 | def shift_immed_matchdata : GIDefMatchData<"RegisterImmPair">; |
||
| 210 | def shift_immed_chain : GICombineRule< |
||
| 211 | (defs root:$d, shift_immed_matchdata:$matchinfo), |
||
| 212 | (match (wip_match_opcode G_SHL, G_ASHR, G_LSHR, G_SSHLSAT, G_USHLSAT):$d, |
||
| 213 | [{ return Helper.matchShiftImmedChain(*${d}, ${matchinfo}); }]), |
||
| 214 | (apply [{ Helper.applyShiftImmedChain(*${d}, ${matchinfo}); }])>; |
||
| 215 | |||
| 216 | // Transform shift (logic (shift X, C0), Y), C1 |
||
| 217 | // -> logic (shift X, (C0+C1)), (shift Y, C1), if shifts are same |
||
| 218 | def shift_of_shifted_logic_matchdata : GIDefMatchData<"ShiftOfShiftedLogic">; |
||
| 219 | def shift_of_shifted_logic_chain : GICombineRule< |
||
| 220 | (defs root:$d, shift_of_shifted_logic_matchdata:$matchinfo), |
||
| 221 | (match (wip_match_opcode G_SHL, G_ASHR, G_LSHR, G_USHLSAT, G_SSHLSAT):$d, |
||
| 222 | [{ return Helper.matchShiftOfShiftedLogic(*${d}, ${matchinfo}); }]), |
||
| 223 | (apply [{ Helper.applyShiftOfShiftedLogic(*${d}, ${matchinfo}); }])>; |
||
| 224 | |||
| 225 | def mul_to_shl_matchdata : GIDefMatchData<"unsigned">; |
||
| 226 | def mul_to_shl : GICombineRule< |
||
| 227 | (defs root:$d, mul_to_shl_matchdata:$matchinfo), |
||
| 228 | (match (G_MUL $d, $op1, $op2):$mi, |
||
| 229 | [{ return Helper.matchCombineMulToShl(*${mi}, ${matchinfo}); }]), |
||
| 230 | (apply [{ Helper.applyCombineMulToShl(*${mi}, ${matchinfo}); }])>; |
||
| 231 | |||
| 232 | // shl ([asz]ext x), y => zext (shl x, y), if shift does not overflow int |
||
| 233 | def reduce_shl_of_extend_matchdata : GIDefMatchData<"RegisterImmPair">; |
||
| 234 | def reduce_shl_of_extend : GICombineRule< |
||
| 235 | (defs root:$dst, reduce_shl_of_extend_matchdata:$matchinfo), |
||
| 236 | (match (G_SHL $dst, $src0, $src1):$mi, |
||
| 237 | [{ return Helper.matchCombineShlOfExtend(*${mi}, ${matchinfo}); }]), |
||
| 238 | (apply [{ Helper.applyCombineShlOfExtend(*${mi}, ${matchinfo}); }])>; |
||
| 239 | |||
| 240 | def narrow_binop_feeding_and : GICombineRule< |
||
| 241 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 242 | (match (wip_match_opcode G_AND):$root, |
||
| 243 | [{ return Helper.matchNarrowBinopFeedingAnd(*${root}, ${matchinfo}); }]), |
||
| 244 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 245 | |||
| 246 | // [us]itofp(undef) = 0, because the result value is bounded. |
||
| 247 | def undef_to_fp_zero : GICombineRule< |
||
| 248 | (defs root:$root), |
||
| 249 | (match (wip_match_opcode G_UITOFP, G_SITOFP):$root, |
||
| 250 | [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), |
||
| 251 | (apply [{ Helper.replaceInstWithFConstant(*${root}, 0.0); }])>; |
||
| 252 | |||
| 253 | def undef_to_int_zero: GICombineRule< |
||
| 254 | (defs root:$root), |
||
| 255 | (match (wip_match_opcode G_AND, G_MUL):$root, |
||
| 256 | [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), |
||
| 257 | (apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>; |
||
| 258 | |||
| 259 | def undef_to_negative_one: GICombineRule< |
||
| 260 | (defs root:$root), |
||
| 261 | (match (wip_match_opcode G_OR):$root, |
||
| 262 | [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), |
||
| 263 | (apply [{ Helper.replaceInstWithConstant(*${root}, -1); }])>; |
||
| 264 | |||
| 265 | def binop_left_undef_to_zero: GICombineRule< |
||
| 266 | (defs root:$root), |
||
| 267 | (match (wip_match_opcode G_SHL, G_UDIV, G_UREM):$root, |
||
| 268 | [{ return Helper.matchOperandIsUndef(*${root}, 1); }]), |
||
| 269 | (apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>; |
||
| 270 | |||
| 271 | def binop_right_undef_to_undef: GICombineRule< |
||
| 272 | (defs root:$root), |
||
| 273 | (match (wip_match_opcode G_SHL, G_ASHR, G_LSHR):$root, |
||
| 274 | [{ return Helper.matchOperandIsUndef(*${root}, 2); }]), |
||
| 275 | (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; |
||
| 276 | |||
| 277 | def unary_undef_to_zero: GICombineRule< |
||
| 278 | (defs root:$root), |
||
| 279 | (match (wip_match_opcode G_ABS):$root, |
||
| 280 | [{ return Helper.matchOperandIsUndef(*${root}, 1); }]), |
||
| 281 | (apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>; |
||
| 282 | |||
| 283 | // Instructions where if any source operand is undef, the instruction can be |
||
| 284 | // replaced with undef. |
||
| 285 | def propagate_undef_any_op: GICombineRule< |
||
| 286 | (defs root:$root), |
||
| 287 | (match (wip_match_opcode G_ADD, G_FPTOSI, G_FPTOUI, G_SUB, G_XOR, G_TRUNC):$root, |
||
| 288 | [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), |
||
| 289 | (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; |
||
| 290 | |||
| 291 | // Instructions where if all source operands are undef, the instruction can be |
||
| 292 | // replaced with undef. |
||
| 293 | def propagate_undef_all_ops: GICombineRule< |
||
| 294 | (defs root:$root), |
||
| 295 | (match (wip_match_opcode G_SHUFFLE_VECTOR):$root, |
||
| 296 | [{ return Helper.matchAllExplicitUsesAreUndef(*${root}); }]), |
||
| 297 | (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; |
||
| 298 | |||
| 299 | // Replace a G_SHUFFLE_VECTOR with an undef mask with a G_IMPLICIT_DEF. |
||
| 300 | def propagate_undef_shuffle_mask: GICombineRule< |
||
| 301 | (defs root:$root), |
||
| 302 | (match (wip_match_opcode G_SHUFFLE_VECTOR):$root, |
||
| 303 | [{ return Helper.matchUndefShuffleVectorMask(*${root}); }]), |
||
| 304 | (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; |
||
| 305 | |||
| 306 | // Replace an insert/extract element of an out of bounds index with undef. |
||
| 307 | def insert_extract_vec_elt_out_of_bounds : GICombineRule< |
||
| 308 | (defs root:$root), |
||
| 309 | (match (wip_match_opcode G_INSERT_VECTOR_ELT, G_EXTRACT_VECTOR_ELT):$root, |
||
| 310 | [{ return Helper.matchInsertExtractVecEltOutOfBounds(*${root}); }]), |
||
| 311 | (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; |
||
| 312 | |||
| 313 | // Fold (cond ? x : x) -> x |
||
| 314 | def select_same_val: GICombineRule< |
||
| 315 | (defs root:$root), |
||
| 316 | (match (wip_match_opcode G_SELECT):$root, |
||
| 317 | [{ return Helper.matchSelectSameVal(*${root}); }]), |
||
| 318 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) |
||
| 319 | >; |
||
| 320 | |||
| 321 | // Fold (undef ? x : y) -> y |
||
| 322 | def select_undef_cmp: GICombineRule< |
||
| 323 | (defs root:$root), |
||
| 324 | (match (wip_match_opcode G_SELECT):$root, |
||
| 325 | [{ return Helper.matchUndefSelectCmp(*${root}); }]), |
||
| 326 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) |
||
| 327 | >; |
||
| 328 | |||
| 329 | // Fold (true ? x : y) -> x |
||
| 330 | // Fold (false ? x : y) -> y |
||
| 331 | def select_constant_cmp_matchdata : GIDefMatchData<"unsigned">; |
||
| 332 | def select_constant_cmp: GICombineRule< |
||
| 333 | (defs root:$root, select_constant_cmp_matchdata:$matchinfo), |
||
| 334 | (match (wip_match_opcode G_SELECT):$root, |
||
| 335 | [{ return Helper.matchConstantSelectCmp(*${root}, ${matchinfo}); }]), |
||
| 336 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, ${matchinfo}); }]) |
||
| 337 | >; |
||
| 338 | |||
| 339 | def select_to_logical : GICombineRule< |
||
| 340 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 341 | (match (wip_match_opcode G_SELECT):$root, |
||
| 342 | [{ return Helper.matchSelectToLogical(*${root}, ${matchinfo}); }]), |
||
| 343 | (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }]) |
||
| 344 | >; |
||
| 345 | |||
| 346 | // Fold (C op x) -> (x op C) |
||
| 347 | // TODO: handle more isCommutable opcodes |
||
| 348 | // TODO: handle compares (currently not marked as isCommutable) |
||
| 349 | def commute_constant_to_rhs : GICombineRule< |
||
| 350 | (defs root:$root), |
||
| 351 | (match (wip_match_opcode G_ADD, G_MUL, G_AND, G_OR, G_XOR):$root, [{ |
||
| 352 | return getIConstantVRegVal(${root}->getOperand(1).getReg(), MRI).has_value(); |
||
| 353 | }]), |
||
| 354 | (apply [{ |
||
| 355 | Observer.changingInstr(*${root}); |
||
| 356 | Register LHSReg = ${root}->getOperand(1).getReg(); |
||
| 357 | Register RHSReg = ${root}->getOperand(2).getReg(); |
||
| 358 | ${root}->getOperand(1).setReg(RHSReg); |
||
| 359 | ${root}->getOperand(2).setReg(LHSReg); |
||
| 360 | Observer.changedInstr(*${root}); |
||
| 361 | }]) |
||
| 362 | >; |
||
| 363 | |||
| 364 | // Fold x op 0 -> x |
||
| 365 | def right_identity_zero: GICombineRule< |
||
| 366 | (defs root:$root), |
||
| 367 | (match (wip_match_opcode G_SUB, G_ADD, G_OR, G_XOR, G_SHL, G_ASHR, G_LSHR, |
||
| 368 | G_PTR_ADD, G_ROTL, G_ROTR):$root, |
||
| 369 | [{ return Helper.matchConstantOp(${root}->getOperand(2), 0); }]), |
||
| 370 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) |
||
| 371 | >; |
||
| 372 | |||
| 373 | // Fold x op 1 -> x |
||
| 374 | def right_identity_one: GICombineRule< |
||
| 375 | (defs root:$root), |
||
| 376 | (match (wip_match_opcode G_MUL):$root, |
||
| 377 | [{ return Helper.matchConstantOp(${root}->getOperand(2), 1); }]), |
||
| 378 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) |
||
| 379 | >; |
||
| 380 | |||
| 381 | // Fold (x op x) - > x |
||
| 382 | def binop_same_val: GICombineRule< |
||
| 383 | (defs root:$root), |
||
| 384 | (match (wip_match_opcode G_AND, G_OR):$root, |
||
| 385 | [{ return Helper.matchBinOpSameVal(*${root}); }]), |
||
| 386 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) |
||
| 387 | >; |
||
| 388 | |||
| 389 | // Fold (0 op x) - > 0 |
||
| 390 | def binop_left_to_zero: GICombineRule< |
||
| 391 | (defs root:$root), |
||
| 392 | (match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root, |
||
| 393 | [{ return Helper.matchOperandIsZero(*${root}, 1); }]), |
||
| 394 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) |
||
| 395 | >; |
||
| 396 | |||
| 397 | def urem_pow2_to_mask : GICombineRule< |
||
| 398 | (defs root:$root), |
||
| 399 | (match (wip_match_opcode G_UREM):$root, |
||
| 400 | [{ return Helper.matchOperandIsKnownToBeAPowerOfTwo(*${root}, 2); }]), |
||
| 401 | (apply [{ Helper.applySimplifyURemByPow2(*${root}); }]) |
||
| 402 | >; |
||
| 403 | |||
| 404 | // Push a binary operator through a select on constants. |
||
| 405 | // |
||
| 406 | // binop (select cond, K0, K1), K2 -> |
||
| 407 | // select cond, (binop K0, K2), (binop K1, K2) |
||
| 408 | |||
| 409 | // Every binary operator that has constant folding. We currently do |
||
| 410 | // not have constant folding for G_FPOW, G_FMAXNUM_IEEE or |
||
| 411 | // G_FMINNUM_IEEE. |
||
| 412 | def fold_binop_into_select : GICombineRule< |
||
| 413 | (defs root:$root, unsigned_matchinfo:$select_op_no), |
||
| 414 | (match (wip_match_opcode |
||
| 415 | G_ADD, G_SUB, G_PTR_ADD, G_AND, G_OR, G_XOR, |
||
| 416 | G_SDIV, G_SREM, G_UDIV, G_UREM, G_LSHR, G_ASHR, G_SHL, |
||
| 417 | G_SMIN, G_SMAX, G_UMIN, G_UMAX, |
||
| 418 | G_FMUL, G_FADD, G_FSUB, G_FDIV, G_FREM, |
||
| 419 | G_FMINNUM, G_FMAXNUM, G_FMINIMUM, G_FMAXIMUM):$root, |
||
| 420 | [{ return Helper.matchFoldBinOpIntoSelect(*${root}, ${select_op_no}); }]), |
||
| 421 | (apply [{ return Helper.applyFoldBinOpIntoSelect(*${root}, ${select_op_no}); }]) |
||
| 422 | >; |
||
| 423 | |||
| 424 | // Transform d = [su]div(x, y) and r = [su]rem(x, y) - > d, r = [su]divrem(x, y) |
||
| 425 | def div_rem_to_divrem_matchdata : GIDefMatchData<"MachineInstr *">; |
||
| 426 | def div_rem_to_divrem : GICombineRule< |
||
| 427 | (defs root:$root, div_rem_to_divrem_matchdata:$matchinfo), |
||
| 428 | (match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root, |
||
| 429 | [{ return Helper.matchCombineDivRem(*${root}, ${matchinfo}); }]), |
||
| 430 | (apply [{ Helper.applyCombineDivRem(*${root}, ${matchinfo}); }]) |
||
| 431 | >; |
||
| 432 | |||
| 433 | // Fold (x op 0) - > 0 |
||
| 434 | def binop_right_to_zero: GICombineRule< |
||
| 435 | (defs root:$root), |
||
| 436 | (match (wip_match_opcode G_MUL):$root, |
||
| 437 | [{ return Helper.matchOperandIsZero(*${root}, 2); }]), |
||
| 438 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) |
||
| 439 | >; |
||
| 440 | |||
| 441 | // Erase stores of undef values. |
||
| 442 | def erase_undef_store : GICombineRule< |
||
| 443 | (defs root:$root), |
||
| 444 | (match (wip_match_opcode G_STORE):$root, |
||
| 445 | [{ return Helper.matchUndefStore(*${root}); }]), |
||
| 446 | (apply [{ return Helper.eraseInst(*${root}); }]) |
||
| 447 | >; |
||
| 448 | |||
| 449 | def simplify_add_to_sub_matchinfo: GIDefMatchData<"std::tuple<Register, Register>">; |
||
| 450 | def simplify_add_to_sub: GICombineRule < |
||
| 451 | (defs root:$root, simplify_add_to_sub_matchinfo:$info), |
||
| 452 | (match (wip_match_opcode G_ADD):$root, |
||
| 453 | [{ return Helper.matchSimplifyAddToSub(*${root}, ${info}); }]), |
||
| 454 | (apply [{ Helper.applySimplifyAddToSub(*${root}, ${info});}]) |
||
| 455 | >; |
||
| 456 | |||
| 457 | // Fold fp_op(cst) to the constant result of the floating point operation. |
||
| 458 | def constant_fp_op_matchinfo: GIDefMatchData<"std::optional<APFloat>">; |
||
| 459 | def constant_fp_op: GICombineRule < |
||
| 460 | (defs root:$root, constant_fp_op_matchinfo:$info), |
||
| 461 | (match (wip_match_opcode G_FNEG, G_FABS, G_FPTRUNC, G_FSQRT, G_FLOG2):$root, |
||
| 462 | [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), |
||
| 463 | (apply [{ Helper.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) |
||
| 464 | >; |
||
| 465 | |||
| 466 | // Fold int2ptr(ptr2int(x)) -> x |
||
| 467 | def p2i_to_i2p: GICombineRule< |
||
| 468 | (defs root:$root, register_matchinfo:$info), |
||
| 469 | (match (wip_match_opcode G_INTTOPTR):$root, |
||
| 470 | [{ return Helper.matchCombineI2PToP2I(*${root}, ${info}); }]), |
||
| 471 | (apply [{ Helper.applyCombineI2PToP2I(*${root}, ${info}); }]) |
||
| 472 | >; |
||
| 473 | |||
| 474 | // Fold ptr2int(int2ptr(x)) -> x |
||
| 475 | def i2p_to_p2i: GICombineRule< |
||
| 476 | (defs root:$dst, register_matchinfo:$info), |
||
| 477 | (match (G_INTTOPTR $t, $ptr), |
||
| 478 | (G_PTRTOINT $dst, $t):$mi, |
||
| 479 | [{ ${info} = ${ptr}.getReg(); }]), |
||
| 480 | (apply [{ Helper.applyCombineP2IToI2P(*${mi}, ${info}); }]) |
||
| 481 | >; |
||
| 482 | |||
| 483 | // Fold add ptrtoint(x), y -> ptrtoint (ptr_add x), y |
||
| 484 | def add_p2i_to_ptradd_matchinfo : GIDefMatchData<"std::pair<Register, bool>">; |
||
| 485 | def add_p2i_to_ptradd : GICombineRule< |
||
| 486 | (defs root:$root, add_p2i_to_ptradd_matchinfo:$info), |
||
| 487 | (match (wip_match_opcode G_ADD):$root, |
||
| 488 | [{ return Helper.matchCombineAddP2IToPtrAdd(*${root}, ${info}); }]), |
||
| 489 | (apply [{ Helper.applyCombineAddP2IToPtrAdd(*${root}, ${info}); }]) |
||
| 490 | >; |
||
| 491 | |||
| 492 | // Fold (ptr_add (int2ptr C1), C2) -> C1 + C2 |
||
| 493 | def const_ptradd_to_i2p_matchinfo : GIDefMatchData<"APInt">; |
||
| 494 | def const_ptradd_to_i2p: GICombineRule< |
||
| 495 | (defs root:$root, const_ptradd_to_i2p_matchinfo:$info), |
||
| 496 | (match (wip_match_opcode G_PTR_ADD):$root, |
||
| 497 | [{ return Helper.matchCombineConstPtrAddToI2P(*${root}, ${info}); }]), |
||
| 498 | (apply [{ Helper.applyCombineConstPtrAddToI2P(*${root}, ${info}); }]) |
||
| 499 | >; |
||
| 500 | |||
| 501 | // Simplify: (logic_op (op x...), (op y...)) -> (op (logic_op x, y)) |
||
| 502 | def hoist_logic_op_with_same_opcode_hands: GICombineRule < |
||
| 503 | (defs root:$root, instruction_steps_matchdata:$info), |
||
| 504 | (match (wip_match_opcode G_AND, G_OR, G_XOR):$root, |
||
| 505 | [{ return Helper.matchHoistLogicOpWithSameOpcodeHands(*${root}, ${info}); }]), |
||
| 506 | (apply [{ Helper.applyBuildInstructionSteps(*${root}, ${info});}]) |
||
| 507 | >; |
||
| 508 | |||
| 509 | // Fold ashr (shl x, C), C -> sext_inreg (C) |
||
| 510 | def shl_ashr_to_sext_inreg_matchinfo : GIDefMatchData<"std::tuple<Register, int64_t>">; |
||
| 511 | def shl_ashr_to_sext_inreg : GICombineRule< |
||
| 512 | (defs root:$root, shl_ashr_to_sext_inreg_matchinfo:$info), |
||
| 513 | (match (wip_match_opcode G_ASHR): $root, |
||
| 514 | [{ return Helper.matchAshrShlToSextInreg(*${root}, ${info}); }]), |
||
| 515 | (apply [{ Helper.applyAshShlToSextInreg(*${root}, ${info});}]) |
||
| 516 | >; |
||
| 517 | |||
| 518 | // Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0 |
||
| 519 | def overlapping_and: GICombineRule < |
||
| 520 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 521 | (match (wip_match_opcode G_AND):$root, |
||
| 522 | [{ return Helper.matchOverlappingAnd(*${root}, ${info}); }]), |
||
| 523 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }]) |
||
| 524 | >; |
||
| 525 | |||
| 526 | // Fold (x & y) -> x or (x & y) -> y when (x & y) is known to equal x or equal y. |
||
| 527 | def redundant_and: GICombineRule < |
||
| 528 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 529 | (match (wip_match_opcode G_AND):$root, |
||
| 530 | [{ return Helper.matchRedundantAnd(*${root}, ${matchinfo}); }]), |
||
| 531 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }]) |
||
| 532 | >; |
||
| 533 | |||
| 534 | // Fold (x | y) -> x or (x | y) -> y when (x | y) is known to equal x or equal y. |
||
| 535 | def redundant_or: GICombineRule < |
||
| 536 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 537 | (match (wip_match_opcode G_OR):$root, |
||
| 538 | [{ return Helper.matchRedundantOr(*${root}, ${matchinfo}); }]), |
||
| 539 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }]) |
||
| 540 | >; |
||
| 541 | |||
| 542 | // If the input is already sign extended, just drop the extension. |
||
| 543 | // sext_inreg x, K -> |
||
| 544 | // if computeNumSignBits(x) >= (x.getScalarSizeInBits() - K + 1) |
||
| 545 | def redundant_sext_inreg: GICombineRule < |
||
| 546 | (defs root:$root), |
||
| 547 | (match (wip_match_opcode G_SEXT_INREG):$root, |
||
| 548 | [{ return Helper.matchRedundantSExtInReg(*${root}); }]), |
||
| 549 | (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) |
||
| 550 | >; |
||
| 551 | |||
| 552 | // Fold (anyext (trunc x)) -> x if the source type is same as |
||
| 553 | // the destination type. |
||
| 554 | def anyext_trunc_fold: GICombineRule < |
||
| 555 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 556 | (match (wip_match_opcode G_ANYEXT):$root, |
||
| 557 | [{ return Helper.matchCombineAnyExtTrunc(*${root}, ${matchinfo}); }]), |
||
| 558 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }]) |
||
| 559 | >; |
||
| 560 | |||
| 561 | // Fold (zext (trunc x)) -> x if the source type is same as the destination type |
||
| 562 | // and truncated bits are known to be zero. |
||
| 563 | def zext_trunc_fold_matchinfo : GIDefMatchData<"Register">; |
||
| 564 | def zext_trunc_fold: GICombineRule < |
||
| 565 | (defs root:$root, zext_trunc_fold_matchinfo:$matchinfo), |
||
| 566 | (match (wip_match_opcode G_ZEXT):$root, |
||
| 567 | [{ return Helper.matchCombineZextTrunc(*${root}, ${matchinfo}); }]), |
||
| 568 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo}); }]) |
||
| 569 | >; |
||
| 570 | |||
| 571 | // Fold ([asz]ext ([asz]ext x)) -> ([asz]ext x). |
||
| 572 | def ext_ext_fold_matchinfo : GIDefMatchData<"std::tuple<Register, unsigned>">; |
||
| 573 | def ext_ext_fold: GICombineRule < |
||
| 574 | (defs root:$root, ext_ext_fold_matchinfo:$matchinfo), |
||
| 575 | (match (wip_match_opcode G_ANYEXT, G_SEXT, G_ZEXT):$root, |
||
| 576 | [{ return Helper.matchCombineExtOfExt(*${root}, ${matchinfo}); }]), |
||
| 577 | (apply [{ Helper.applyCombineExtOfExt(*${root}, ${matchinfo}); }]) |
||
| 578 | >; |
||
| 579 | |||
| 580 | def not_cmp_fold_matchinfo : GIDefMatchData<"SmallVector<Register, 4>">; |
||
| 581 | def not_cmp_fold : GICombineRule< |
||
| 582 | (defs root:$d, not_cmp_fold_matchinfo:$info), |
||
| 583 | (match (wip_match_opcode G_XOR): $d, |
||
| 584 | [{ return Helper.matchNotCmp(*${d}, ${info}); }]), |
||
| 585 | (apply [{ Helper.applyNotCmp(*${d}, ${info}); }]) |
||
| 586 | >; |
||
| 587 | |||
| 588 | // Fold (fneg (fneg x)) -> x. |
||
| 589 | def fneg_fneg_fold: GICombineRule < |
||
| 590 | (defs root:$dst, register_matchinfo:$matchinfo), |
||
| 591 | (match (G_FNEG $t, $src), |
||
| 592 | (G_FNEG $dst, $t):$mi, |
||
| 593 | [{ ${matchinfo} = ${src}.getReg(); }]), |
||
| 594 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${mi}, ${matchinfo}); }]) |
||
| 595 | >; |
||
| 596 | |||
| 597 | // Fold (unmerge(merge x, y, z)) -> z, y, z. |
||
| 598 | def unmerge_merge_matchinfo : GIDefMatchData<"SmallVector<Register, 8>">; |
||
| 599 | def unmerge_merge : GICombineRule< |
||
| 600 | (defs root:$d, unmerge_merge_matchinfo:$info), |
||
| 601 | (match (wip_match_opcode G_UNMERGE_VALUES): $d, |
||
| 602 | [{ return Helper.matchCombineUnmergeMergeToPlainValues(*${d}, ${info}); }]), |
||
| 603 | (apply [{ Helper.applyCombineUnmergeMergeToPlainValues(*${d}, ${info}); }]) |
||
| 604 | >; |
||
| 605 | |||
| 606 | // Fold merge(unmerge). |
||
| 607 | def merge_unmerge : GICombineRule< |
||
| 608 | (defs root:$d, register_matchinfo:$matchinfo), |
||
| 609 | (match (wip_match_opcode G_MERGE_VALUES):$d, |
||
| 610 | [{ return Helper.matchCombineMergeUnmerge(*${d}, ${matchinfo}); }]), |
||
| 611 | (apply [{ Helper.replaceSingleDefInstWithReg(*${d}, ${matchinfo}); }]) |
||
| 612 | >; |
||
| 613 | |||
| 614 | // Fold (fabs (fneg x)) -> (fabs x). |
||
| 615 | def fabs_fneg_fold: GICombineRule < |
||
| 616 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 617 | (match (wip_match_opcode G_FABS):$root, |
||
| 618 | [{ return Helper.matchCombineFAbsOfFNeg(*${root}, ${matchinfo}); }]), |
||
| 619 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 620 | |||
| 621 | // Fold (unmerge cst) -> cst1, cst2, ... |
||
| 622 | def unmerge_cst_matchinfo : GIDefMatchData<"SmallVector<APInt, 8>">; |
||
| 623 | def unmerge_cst : GICombineRule< |
||
| 624 | (defs root:$d, unmerge_cst_matchinfo:$info), |
||
| 625 | (match (wip_match_opcode G_UNMERGE_VALUES): $d, |
||
| 626 | [{ return Helper.matchCombineUnmergeConstant(*${d}, ${info}); }]), |
||
| 627 | (apply [{ Helper.applyCombineUnmergeConstant(*${d}, ${info}); }]) |
||
| 628 | >; |
||
| 629 | |||
| 630 | // Fold (unmerge undef) -> undef, undef, ... |
||
| 631 | def unmerge_undef : GICombineRule< |
||
| 632 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 633 | (match (wip_match_opcode G_UNMERGE_VALUES): $root, |
||
| 634 | [{ return Helper.matchCombineUnmergeUndef(*${root}, ${info}); }]), |
||
| 635 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }]) |
||
| 636 | >; |
||
| 637 | |||
| 638 | // Transform x,y<dead> = unmerge z -> x = trunc z. |
||
| 639 | def unmerge_dead_to_trunc : GICombineRule< |
||
| 640 | (defs root:$d), |
||
| 641 | (match (wip_match_opcode G_UNMERGE_VALUES): $d, |
||
| 642 | [{ return Helper.matchCombineUnmergeWithDeadLanesToTrunc(*${d}); }]), |
||
| 643 | (apply [{ Helper.applyCombineUnmergeWithDeadLanesToTrunc(*${d}); }]) |
||
| 644 | >; |
||
| 645 | |||
| 646 | // Transform x,y = unmerge(zext(z)) -> x = zext z; y = 0. |
||
| 647 | def unmerge_zext_to_zext : GICombineRule< |
||
| 648 | (defs root:$d), |
||
| 649 | (match (wip_match_opcode G_UNMERGE_VALUES): $d, |
||
| 650 | [{ return Helper.matchCombineUnmergeZExtToZExt(*${d}); }]), |
||
| 651 | (apply [{ Helper.applyCombineUnmergeZExtToZExt(*${d}); }]) |
||
| 652 | >; |
||
| 653 | |||
| 654 | // Fold trunc ([asz]ext x) -> x or ([asz]ext x) or (trunc x). |
||
| 655 | def trunc_ext_fold_matchinfo : GIDefMatchData<"std::pair<Register, unsigned>">; |
||
| 656 | def trunc_ext_fold: GICombineRule < |
||
| 657 | (defs root:$root, trunc_ext_fold_matchinfo:$matchinfo), |
||
| 658 | (match (wip_match_opcode G_TRUNC):$root, |
||
| 659 | [{ return Helper.matchCombineTruncOfExt(*${root}, ${matchinfo}); }]), |
||
| 660 | (apply [{ Helper.applyCombineTruncOfExt(*${root}, ${matchinfo}); }]) |
||
| 661 | >; |
||
| 662 | |||
| 663 | // Under certain conditions, transform: |
||
| 664 | // trunc (shl x, K) -> shl (trunc x), K// |
||
| 665 | // trunc ([al]shr x, K) -> (trunc ([al]shr (trunc x), K)) |
||
| 666 | def trunc_shift_matchinfo : GIDefMatchData<"std::pair<MachineInstr*, LLT>">; |
||
| 667 | def trunc_shift: GICombineRule < |
||
| 668 | (defs root:$root, trunc_shift_matchinfo:$matchinfo), |
||
| 669 | (match (wip_match_opcode G_TRUNC):$root, |
||
| 670 | [{ return Helper.matchCombineTruncOfShift(*${root}, ${matchinfo}); }]), |
||
| 671 | (apply [{ Helper.applyCombineTruncOfShift(*${root}, ${matchinfo}); }]) |
||
| 672 | >; |
||
| 673 | |||
| 674 | // Transform (mul x, -1) -> (sub 0, x) |
||
| 675 | def mul_by_neg_one: GICombineRule < |
||
| 676 | (defs root:$root), |
||
| 677 | (match (wip_match_opcode G_MUL):$root, |
||
| 678 | [{ return Helper.matchConstantOp(${root}->getOperand(2), -1); }]), |
||
| 679 | (apply [{ Helper.applyCombineMulByNegativeOne(*${root}); }]) |
||
| 680 | >; |
||
| 681 | |||
| 682 | // Fold (xor (and x, y), y) -> (and (not x), y) |
||
| 683 | def xor_of_and_with_same_reg_matchinfo : |
||
| 684 | GIDefMatchData<"std::pair<Register, Register>">; |
||
| 685 | def xor_of_and_with_same_reg: GICombineRule < |
||
| 686 | (defs root:$root, xor_of_and_with_same_reg_matchinfo:$matchinfo), |
||
| 687 | (match (wip_match_opcode G_XOR):$root, |
||
| 688 | [{ return Helper.matchXorOfAndWithSameReg(*${root}, ${matchinfo}); }]), |
||
| 689 | (apply [{ Helper.applyXorOfAndWithSameReg(*${root}, ${matchinfo}); }]) |
||
| 690 | >; |
||
| 691 | |||
| 692 | // Transform (ptr_add 0, x) -> (int_to_ptr x) |
||
| 693 | def ptr_add_with_zero: GICombineRule< |
||
| 694 | (defs root:$root), |
||
| 695 | (match (wip_match_opcode G_PTR_ADD):$root, |
||
| 696 | [{ return Helper.matchPtrAddZero(*${root}); }]), |
||
| 697 | (apply [{ Helper.applyPtrAddZero(*${root}); }])>; |
||
| 698 | |||
| 699 | def regs_small_vec : GIDefMatchData<"SmallVector<Register, 4>">; |
||
| 700 | def combine_insert_vec_elts_build_vector : GICombineRule< |
||
| 701 | (defs root:$root, regs_small_vec:$info), |
||
| 702 | (match (wip_match_opcode G_INSERT_VECTOR_ELT):$root, |
||
| 703 | [{ return Helper.matchCombineInsertVecElts(*${root}, ${info}); }]), |
||
| 704 | (apply [{ Helper.applyCombineInsertVecElts(*${root}, ${info}); }])>; |
||
| 705 | |||
| 706 | def load_or_combine : GICombineRule< |
||
| 707 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 708 | (match (wip_match_opcode G_OR):$root, |
||
| 709 | [{ return Helper.matchLoadOrCombine(*${root}, ${info}); }]), |
||
| 710 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 711 | |||
| 712 | |||
| 713 | def truncstore_merge_matcdata : GIDefMatchData<"MergeTruncStoresInfo">; |
||
| 714 | def truncstore_merge : GICombineRule< |
||
| 715 | (defs root:$root, truncstore_merge_matcdata:$info), |
||
| 716 | (match (wip_match_opcode G_STORE):$root, |
||
| 717 | [{ return Helper.matchTruncStoreMerge(*${root}, ${info}); }]), |
||
| 718 | (apply [{ Helper.applyTruncStoreMerge(*${root}, ${info}); }])>; |
||
| 719 | |||
| 720 | def extend_through_phis_matchdata: GIDefMatchData<"MachineInstr*">; |
||
| 721 | def extend_through_phis : GICombineRule< |
||
| 722 | (defs root:$root, extend_through_phis_matchdata:$matchinfo), |
||
| 723 | (match (wip_match_opcode G_PHI):$root, |
||
| 724 | [{ return Helper.matchExtendThroughPhis(*${root}, ${matchinfo}); }]), |
||
| 725 | (apply [{ Helper.applyExtendThroughPhis(*${root}, ${matchinfo}); }])>; |
||
| 726 | |||
| 727 | // Currently only the one combine above. |
||
| 728 | def insert_vec_elt_combines : GICombineGroup< |
||
| 729 | [combine_insert_vec_elts_build_vector]>; |
||
| 730 | |||
| 731 | def extract_vec_elt_build_vec : GICombineRule< |
||
| 732 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 733 | (match (wip_match_opcode G_EXTRACT_VECTOR_ELT):$root, |
||
| 734 | [{ return Helper.matchExtractVecEltBuildVec(*${root}, ${matchinfo}); }]), |
||
| 735 | (apply [{ Helper.applyExtractVecEltBuildVec(*${root}, ${matchinfo}); }])>; |
||
| 736 | |||
| 737 | // Fold away full elt extracts from a build_vector. |
||
| 738 | def extract_all_elts_from_build_vector_matchinfo : |
||
| 739 | GIDefMatchData<"SmallVector<std::pair<Register, MachineInstr*>>">; |
||
| 740 | def extract_all_elts_from_build_vector : GICombineRule< |
||
| 741 | (defs root:$root, extract_all_elts_from_build_vector_matchinfo:$matchinfo), |
||
| 742 | (match (wip_match_opcode G_BUILD_VECTOR):$root, |
||
| 743 | [{ return Helper.matchExtractAllEltsFromBuildVector(*${root}, ${matchinfo}); }]), |
||
| 744 | (apply [{ Helper.applyExtractAllEltsFromBuildVector(*${root}, ${matchinfo}); }])>; |
||
| 745 | |||
| 746 | def extract_vec_elt_combines : GICombineGroup<[ |
||
| 747 | extract_vec_elt_build_vec, |
||
| 748 | extract_all_elts_from_build_vector]>; |
||
| 749 | |||
| 750 | def funnel_shift_from_or_shift : GICombineRule< |
||
| 751 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 752 | (match (wip_match_opcode G_OR):$root, |
||
| 753 | [{ return Helper.matchOrShiftToFunnelShift(*${root}, ${info}); }]), |
||
| 754 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }]) |
||
| 755 | >; |
||
| 756 | |||
| 757 | def funnel_shift_to_rotate : GICombineRule< |
||
| 758 | (defs root:$root), |
||
| 759 | (match (wip_match_opcode G_FSHL, G_FSHR):$root, |
||
| 760 | [{ return Helper.matchFunnelShiftToRotate(*${root}); }]), |
||
| 761 | (apply [{ Helper.applyFunnelShiftToRotate(*${root}); }]) |
||
| 762 | >; |
||
| 763 | |||
| 764 | def rotate_out_of_range : GICombineRule< |
||
| 765 | (defs root:$root), |
||
| 766 | (match (wip_match_opcode G_ROTR, G_ROTL):$root, |
||
| 767 | [{ return Helper.matchRotateOutOfRange(*${root}); }]), |
||
| 768 | (apply [{ Helper.applyRotateOutOfRange(*${root}); }]) |
||
| 769 | >; |
||
| 770 | |||
| 771 | def icmp_to_true_false_known_bits : GICombineRule< |
||
| 772 | (defs root:$d, int64_matchinfo:$matchinfo), |
||
| 773 | (match (wip_match_opcode G_ICMP):$d, |
||
| 774 | [{ return Helper.matchICmpToTrueFalseKnownBits(*${d}, ${matchinfo}); }]), |
||
| 775 | (apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>; |
||
| 776 | |||
| 777 | def icmp_to_lhs_known_bits : GICombineRule< |
||
| 778 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 779 | (match (wip_match_opcode G_ICMP):$root, |
||
| 780 | [{ return Helper.matchICmpToLHSKnownBits(*${root}, ${info}); }]), |
||
| 781 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 782 | |||
| 783 | def redundant_binop_in_equality : GICombineRule< |
||
| 784 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 785 | (match (wip_match_opcode G_ICMP):$root, |
||
| 786 | [{ return Helper.matchRedundantBinOpInEquality(*${root}, ${info}); }]), |
||
| 787 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 788 | |||
| 789 | def and_or_disjoint_mask : GICombineRule< |
||
| 790 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 791 | (match (wip_match_opcode G_AND):$root, |
||
| 792 | [{ return Helper.matchAndOrDisjointMask(*${root}, ${info}); }]), |
||
| 793 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${info}); }])>; |
||
| 794 | |||
| 795 | def bitfield_extract_from_and : GICombineRule< |
||
| 796 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 797 | (match (wip_match_opcode G_AND):$root, |
||
| 798 | [{ return Helper.matchBitfieldExtractFromAnd(*${root}, ${info}); }]), |
||
| 799 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 800 | |||
| 801 | def funnel_shift_combines : GICombineGroup<[funnel_shift_from_or_shift, |
||
| 802 | funnel_shift_to_rotate]>; |
||
| 803 | |||
| 804 | def bitfield_extract_from_sext_inreg : GICombineRule< |
||
| 805 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 806 | (match (wip_match_opcode G_SEXT_INREG):$root, |
||
| 807 | [{ return Helper.matchBitfieldExtractFromSExtInReg(*${root}, ${info}); }]), |
||
| 808 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 809 | |||
| 810 | def bitfield_extract_from_shr : GICombineRule< |
||
| 811 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 812 | (match (wip_match_opcode G_ASHR, G_LSHR):$root, |
||
| 813 | [{ return Helper.matchBitfieldExtractFromShr(*${root}, ${info}); }]), |
||
| 814 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 815 | |||
| 816 | def bitfield_extract_from_shr_and : GICombineRule< |
||
| 817 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 818 | (match (wip_match_opcode G_ASHR, G_LSHR):$root, |
||
| 819 | [{ return Helper.matchBitfieldExtractFromShrAnd(*${root}, ${info}); }]), |
||
| 820 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 821 | |||
| 822 | def form_bitfield_extract : GICombineGroup<[bitfield_extract_from_sext_inreg, |
||
| 823 | bitfield_extract_from_and, |
||
| 824 | bitfield_extract_from_shr, |
||
| 825 | bitfield_extract_from_shr_and]>; |
||
| 826 | |||
| 827 | def udiv_by_const : GICombineRule< |
||
| 828 | (defs root:$root), |
||
| 829 | (match (wip_match_opcode G_UDIV):$root, |
||
| 830 | [{ return Helper.matchUDivByConst(*${root}); }]), |
||
| 831 | (apply [{ Helper.applyUDivByConst(*${root}); }])>; |
||
| 832 | |||
| 833 | def sdiv_by_const : GICombineRule< |
||
| 834 | (defs root:$root), |
||
| 835 | (match (wip_match_opcode G_SDIV):$root, |
||
| 836 | [{ return Helper.matchSDivByConst(*${root}); }]), |
||
| 837 | (apply [{ Helper.applySDivByConst(*${root}); }])>; |
||
| 838 | |||
| 839 | def intdiv_combines : GICombineGroup<[udiv_by_const, sdiv_by_const]>; |
||
| 840 | |||
| 841 | def reassoc_ptradd : GICombineRule< |
||
| 842 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 843 | (match (wip_match_opcode G_PTR_ADD):$root, |
||
| 844 | [{ return Helper.matchReassocPtrAdd(*${root}, ${matchinfo}); }]), |
||
| 845 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 846 | |||
| 847 | def reassocs : GICombineGroup<[reassoc_ptradd]>; |
||
| 848 | |||
| 849 | // Constant fold operations. |
||
| 850 | def constant_fold : GICombineRule< |
||
| 851 | (defs root:$d, apint_matchinfo:$matchinfo), |
||
| 852 | (match (wip_match_opcode G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR):$d, |
||
| 853 | [{ return Helper.matchConstantFold(*${d}, ${matchinfo}); }]), |
||
| 854 | (apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>; |
||
| 855 | |||
| 856 | def mulo_by_2: GICombineRule< |
||
| 857 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 858 | (match (wip_match_opcode G_UMULO, G_SMULO):$root, |
||
| 859 | [{ return Helper.matchMulOBy2(*${root}, ${matchinfo}); }]), |
||
| 860 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 861 | |||
| 862 | def mulo_by_0: GICombineRule< |
||
| 863 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 864 | (match (wip_match_opcode G_UMULO, G_SMULO):$root, |
||
| 865 | [{ return Helper.matchMulOBy0(*${root}, ${matchinfo}); }]), |
||
| 866 | (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; |
||
| 867 | |||
| 868 | def addo_by_0: GICombineRule< |
||
| 869 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 870 | (match (wip_match_opcode G_UADDO, G_SADDO):$root, |
||
| 871 | [{ return Helper.matchAddOBy0(*${root}, ${matchinfo}); }]), |
||
| 872 | (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; |
||
| 873 | |||
| 874 | // Transform (uadde x, y, 0) -> (uaddo x, y) |
||
| 875 | // (sadde x, y, 0) -> (saddo x, y) |
||
| 876 | // (usube x, y, 0) -> (usubo x, y) |
||
| 877 | // (ssube x, y, 0) -> (ssubo x, y) |
||
| 878 | def adde_to_addo: GICombineRule< |
||
| 879 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 880 | (match (wip_match_opcode G_UADDE, G_SADDE, G_USUBE, G_SSUBE):$root, |
||
| 881 | [{ return Helper.matchAddEToAddO(*${root}, ${matchinfo}); }]), |
||
| 882 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 883 | |||
| 884 | def mulh_to_lshr : GICombineRule< |
||
| 885 | (defs root:$root), |
||
| 886 | (match (wip_match_opcode G_UMULH):$root, |
||
| 887 | [{ return Helper.matchUMulHToLShr(*${root}); }]), |
||
| 888 | (apply [{ Helper.applyUMulHToLShr(*${root}); }])>; |
||
| 889 | |||
| 890 | def mulh_combines : GICombineGroup<[mulh_to_lshr]>; |
||
| 891 | |||
| 892 | def redundant_neg_operands: GICombineRule< |
||
| 893 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 894 | (match (wip_match_opcode G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMAD, G_FMA):$root, |
||
| 895 | [{ return Helper.matchRedundantNegOperands(*${root}, ${matchinfo}); }]), |
||
| 896 | (apply [{ Helper.applyBuildFnNoErase(*${root}, ${matchinfo}); }])>; |
||
| 897 | |||
| 898 | // Transform (fsub +-0.0, X) -> (fneg X) |
||
| 899 | def fsub_to_fneg: GICombineRule< |
||
| 900 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 901 | (match (wip_match_opcode G_FSUB):$root, |
||
| 902 | [{ return Helper.matchFsubToFneg(*${root}, ${matchinfo}); }]), |
||
| 903 | (apply [{ Helper.applyFsubToFneg(*${root}, ${matchinfo}); }])>; |
||
| 904 | |||
| 905 | // Transform (fadd x, (fmul y, z)) -> (fma y, z, x) |
||
| 906 | // (fadd x, (fmul y, z)) -> (fmad y, z, x) |
||
| 907 | // Transform (fadd (fmul x, y), z) -> (fma x, y, z) |
||
| 908 | // (fadd (fmul x, y), z) -> (fmad x, y, z) |
||
| 909 | def combine_fadd_fmul_to_fmad_or_fma: GICombineRule< |
||
| 910 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 911 | (match (wip_match_opcode G_FADD):$root, |
||
| 912 | [{ return Helper.matchCombineFAddFMulToFMadOrFMA(*${root}, |
||
| 913 | ${info}); }]), |
||
| 914 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 915 | |||
| 916 | // Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) |
||
| 917 | // -> (fmad (fpext x), (fpext y), z) |
||
| 918 | // Transform (fadd x, (fpext (fmul y, z))) -> (fma (fpext y), (fpext z), x) |
||
| 919 | // -> (fmad (fpext y), (fpext z), x) |
||
| 920 | def combine_fadd_fpext_fmul_to_fmad_or_fma: GICombineRule< |
||
| 921 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 922 | (match (wip_match_opcode G_FADD):$root, |
||
| 923 | [{ return Helper.matchCombineFAddFpExtFMulToFMadOrFMA(*${root}, |
||
| 924 | ${info}); }]), |
||
| 925 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 926 | |||
| 927 | // Transform (fadd (fma x, y, (fmul z, u)), v) -> (fma x, y, (fma z, u, v)) |
||
| 928 | // (fadd (fmad x, y, (fmul z, u)), v) -> (fmad x, y, (fmad z, u, v)) |
||
| 929 | // Transform (fadd v, (fma x, y, (fmul z, u))) -> (fma x, y, (fma z, u, v)) |
||
| 930 | // (fadd v, (fmad x, y, (fmul z, u))) -> (fmad x, y, (fmad z, u, v)) |
||
| 931 | def combine_fadd_fma_fmul_to_fmad_or_fma: GICombineRule< |
||
| 932 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 933 | (match (wip_match_opcode G_FADD):$root, |
||
| 934 | [{ return Helper.matchCombineFAddFMAFMulToFMadOrFMA(*${root}, |
||
| 935 | ${info}); }]), |
||
| 936 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 937 | |||
| 938 | // Transform (fadd (fma x, y, (fpext (fmul u, v))), z) -> |
||
| 939 | // (fma x, y, (fma (fpext u), (fpext v), z)) |
||
| 940 | def combine_fadd_fpext_fma_fmul_to_fmad_or_fma: GICombineRule< |
||
| 941 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 942 | (match (wip_match_opcode G_FADD):$root, |
||
| 943 | [{ return Helper.matchCombineFAddFpExtFMulToFMadOrFMAAggressive( |
||
| 944 | *${root}, ${info}); }]), |
||
| 945 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 946 | |||
| 947 | // Transform (fsub (fmul x, y), z) -> (fma x, y, -z) |
||
| 948 | // -> (fmad x, y, -z) |
||
| 949 | def combine_fsub_fmul_to_fmad_or_fma: GICombineRule< |
||
| 950 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 951 | (match (wip_match_opcode G_FSUB):$root, |
||
| 952 | [{ return Helper.matchCombineFSubFMulToFMadOrFMA(*${root}, |
||
| 953 | ${info}); }]), |
||
| 954 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 955 | |||
| 956 | // Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) |
||
| 957 | // (fsub x, (fneg (fmul, y, z))) -> (fma y, z, x) |
||
| 958 | def combine_fsub_fneg_fmul_to_fmad_or_fma: GICombineRule< |
||
| 959 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 960 | (match (wip_match_opcode G_FSUB):$root, |
||
| 961 | [{ return Helper.matchCombineFSubFNegFMulToFMadOrFMA(*${root}, |
||
| 962 | ${info}); }]), |
||
| 963 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 964 | |||
| 965 | // Transform (fsub (fpext (fmul x, y)), z) -> |
||
| 966 | // (fma (fpext x), (fpext y), (fneg z)) |
||
| 967 | def combine_fsub_fpext_fmul_to_fmad_or_fma: GICombineRule< |
||
| 968 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 969 | (match (wip_match_opcode G_FSUB):$root, |
||
| 970 | [{ return Helper.matchCombineFSubFpExtFMulToFMadOrFMA(*${root}, |
||
| 971 | ${info}); }]), |
||
| 972 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 973 | |||
| 974 | // Transform (fsub (fneg (fpext (fmul x, y))), z) -> |
||
| 975 | // (fneg (fma (fpext x), (fpext y), z)) |
||
| 976 | def combine_fsub_fpext_fneg_fmul_to_fmad_or_fma: GICombineRule< |
||
| 977 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 978 | (match (wip_match_opcode G_FSUB):$root, |
||
| 979 | [{ return Helper.matchCombineFSubFpExtFNegFMulToFMadOrFMA( |
||
| 980 | *${root}, ${info}); }]), |
||
| 981 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 982 | |||
| 983 | def combine_minmax_nan: GICombineRule< |
||
| 984 | (defs root:$root, unsigned_matchinfo:$info), |
||
| 985 | (match (wip_match_opcode G_FMINNUM, G_FMAXNUM, G_FMINIMUM, G_FMAXIMUM):$root, |
||
| 986 | [{ return Helper.matchCombineFMinMaxNaN(*${root}, ${info}); }]), |
||
| 987 | (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, ${info}); }])>; |
||
| 988 | |||
| 989 | // Transform (add x, (sub y, x)) -> y |
||
| 990 | // Transform (add (sub y, x), x) -> y |
||
| 991 | def add_sub_reg: GICombineRule < |
||
| 992 | (defs root:$root, register_matchinfo:$matchinfo), |
||
| 993 | (match (wip_match_opcode G_ADD):$root, |
||
| 994 | [{ return Helper.matchAddSubSameReg(*${root}, ${matchinfo}); }]), |
||
| 995 | (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, |
||
| 996 | ${matchinfo}); }])>; |
||
| 997 | |||
| 998 | def buildvector_identity_fold : GICombineRule< |
||
| 999 | (defs root:$build_vector, register_matchinfo:$matchinfo), |
||
| 1000 | (match (wip_match_opcode G_BUILD_VECTOR_TRUNC, G_BUILD_VECTOR):$build_vector, |
||
| 1001 | [{ return Helper.matchBuildVectorIdentityFold(*${build_vector}, ${matchinfo}); }]), |
||
| 1002 | (apply [{ Helper.replaceSingleDefInstWithReg(*${build_vector}, ${matchinfo}); }])>; |
||
| 1003 | |||
| 1004 | def trunc_buildvector_fold : GICombineRule< |
||
| 1005 | (defs root:$op, register_matchinfo:$matchinfo), |
||
| 1006 | (match (wip_match_opcode G_TRUNC):$op, |
||
| 1007 | [{ return Helper.matchTruncBuildVectorFold(*${op}, ${matchinfo}); }]), |
||
| 1008 | (apply [{ Helper.replaceSingleDefInstWithReg(*${op}, ${matchinfo}); }])>; |
||
| 1009 | |||
| 1010 | def trunc_lshr_buildvector_fold : GICombineRule< |
||
| 1011 | (defs root:$op, register_matchinfo:$matchinfo), |
||
| 1012 | (match (wip_match_opcode G_TRUNC):$op, |
||
| 1013 | [{ return Helper.matchTruncLshrBuildVectorFold(*${op}, ${matchinfo}); }]), |
||
| 1014 | (apply [{ Helper.replaceSingleDefInstWithReg(*${op}, ${matchinfo}); }])>; |
||
| 1015 | |||
| 1016 | // Transform: |
||
| 1017 | // (x + y) - y -> x |
||
| 1018 | // (x + y) - x -> y |
||
| 1019 | // x - (y + x) -> 0 - y |
||
| 1020 | // x - (x + z) -> 0 - z |
||
| 1021 | def sub_add_reg: GICombineRule < |
||
| 1022 | (defs root:$root, build_fn_matchinfo:$matchinfo), |
||
| 1023 | (match (wip_match_opcode G_SUB):$root, |
||
| 1024 | [{ return Helper.matchSubAddSameReg(*${root}, ${matchinfo}); }]), |
||
| 1025 | (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; |
||
| 1026 | |||
| 1027 | def bitcast_bitcast_fold : GICombineRule< |
||
| 1028 | (defs root:$dst), |
||
| 1029 | (match (G_BITCAST $dst, $src1):$op, (G_BITCAST $src1, $src0), |
||
| 1030 | [{ return MRI.getType(${src0}.getReg()) == MRI.getType(${dst}.getReg()); }]), |
||
| 1031 | (apply [{ Helper.replaceSingleDefInstWithReg(*${op}, ${src0}.getReg()); }])>; |
||
| 1032 | |||
| 1033 | def select_to_minmax: GICombineRule< |
||
| 1034 | (defs root:$root, build_fn_matchinfo:$info), |
||
| 1035 | (match (wip_match_opcode G_SELECT):$root, |
||
| 1036 | [{ return Helper.matchSimplifySelectToMinMax(*${root}, ${info}); }]), |
||
| 1037 | (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; |
||
| 1038 | |||
| 1039 | // FIXME: These should use the custom predicate feature once it lands. |
||
| 1040 | def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, |
||
| 1041 | undef_to_negative_one, |
||
| 1042 | binop_left_undef_to_zero, |
||
| 1043 | binop_right_undef_to_undef, |
||
| 1044 | unary_undef_to_zero, |
||
| 1045 | propagate_undef_any_op, |
||
| 1046 | propagate_undef_all_ops, |
||
| 1047 | propagate_undef_shuffle_mask, |
||
| 1048 | erase_undef_store, |
||
| 1049 | unmerge_undef, |
||
| 1050 | insert_extract_vec_elt_out_of_bounds]>; |
||
| 1051 | |||
| 1052 | def identity_combines : GICombineGroup<[select_same_val, right_identity_zero, |
||
| 1053 | binop_same_val, binop_left_to_zero, |
||
| 1054 | binop_right_to_zero, p2i_to_i2p, |
||
| 1055 | i2p_to_p2i, anyext_trunc_fold, |
||
| 1056 | fneg_fneg_fold, right_identity_one, |
||
| 1057 | add_sub_reg, buildvector_identity_fold, |
||
| 1058 | trunc_buildvector_fold, |
||
| 1059 | trunc_lshr_buildvector_fold, |
||
| 1060 | bitcast_bitcast_fold]>; |
||
| 1061 | |||
| 1062 | def const_combines : GICombineGroup<[constant_fp_op, const_ptradd_to_i2p, |
||
| 1063 | overlapping_and, mulo_by_2, mulo_by_0, |
||
| 1064 | addo_by_0, adde_to_addo, |
||
| 1065 | combine_minmax_nan]>; |
||
| 1066 | |||
| 1067 | def known_bits_simplifications : GICombineGroup<[ |
||
| 1068 | redundant_and, redundant_sext_inreg, redundant_or, urem_pow2_to_mask, |
||
| 1069 | zext_trunc_fold, icmp_to_true_false_known_bits, icmp_to_lhs_known_bits, |
||
| 1070 | sext_inreg_to_zext_inreg]>; |
||
| 1071 | |||
| 1072 | def width_reduction_combines : GICombineGroup<[reduce_shl_of_extend, |
||
| 1073 | narrow_binop_feeding_and]>; |
||
| 1074 | |||
| 1075 | def phi_combines : GICombineGroup<[extend_through_phis]>; |
||
| 1076 | |||
| 1077 | def select_combines : GICombineGroup<[select_undef_cmp, select_constant_cmp, |
||
| 1078 | select_to_logical]>; |
||
| 1079 | |||
| 1080 | def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl, add_p2i_to_ptradd, |
||
| 1081 | mul_by_neg_one, idempotent_prop]>; |
||
| 1082 | |||
| 1083 | def fma_combines : GICombineGroup<[combine_fadd_fmul_to_fmad_or_fma, |
||
| 1084 | combine_fadd_fpext_fmul_to_fmad_or_fma, combine_fadd_fma_fmul_to_fmad_or_fma, |
||
| 1085 | combine_fadd_fpext_fma_fmul_to_fmad_or_fma, combine_fsub_fmul_to_fmad_or_fma, |
||
| 1086 | combine_fsub_fneg_fmul_to_fmad_or_fma, combine_fsub_fpext_fmul_to_fmad_or_fma, |
||
| 1087 | combine_fsub_fpext_fneg_fmul_to_fmad_or_fma]>; |
||
| 1088 | |||
| 1089 | def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines, |
||
| 1090 | extract_vec_elt_combines, combines_for_extload, |
||
| 1091 | combine_indexed_load_store, undef_combines, identity_combines, phi_combines, |
||
| 1092 | simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, |
||
| 1093 | reassocs, ptr_add_immed_chain, |
||
| 1094 | shl_ashr_to_sext_inreg, sext_inreg_of_load, |
||
| 1095 | width_reduction_combines, select_combines, |
||
| 1096 | known_bits_simplifications, ext_ext_fold, |
||
| 1097 | not_cmp_fold, opt_brcond_by_inverting_cond, |
||
| 1098 | unmerge_merge, unmerge_cst, unmerge_dead_to_trunc, |
||
| 1099 | unmerge_zext_to_zext, merge_unmerge, trunc_ext_fold, trunc_shift, |
||
| 1100 | const_combines, xor_of_and_with_same_reg, ptr_add_with_zero, |
||
| 1101 | shift_immed_chain, shift_of_shifted_logic_chain, load_or_combine, |
||
| 1102 | truncstore_merge, div_rem_to_divrem, funnel_shift_combines, |
||
| 1103 | form_bitfield_extract, constant_fold, fabs_fneg_fold, |
||
| 1104 | intdiv_combines, mulh_combines, redundant_neg_operands, |
||
| 1105 | and_or_disjoint_mask, fma_combines, fold_binop_into_select, |
||
| 1106 | sub_add_reg, select_to_minmax, redundant_binop_in_equality, |
||
| 1107 | fsub_to_fneg, commute_constant_to_rhs]>; |
||
| 1108 | |||
| 1109 | // A combine group used to for prelegalizer combiners at -O0. The combines in |
||
| 1110 | // this group have been selected based on experiments to balance code size and |
||
| 1111 | // compile time performance. |
||
| 1112 | def optnone_combines : GICombineGroup<[trivial_combines, |
||
| 1113 | ptr_add_immed_chain, combines_for_extload, |
||
| 1114 | not_cmp_fold, opt_brcond_by_inverting_cond]>; |