1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
// RUN: -combiners=MyCombinerHelper -gicombiner-stop-after-build %s \
// RUN: -o %t.inc | FileCheck %s
include "llvm/Target/Target.td"
include "llvm/Target/GlobalISel/Combine.td"
def MyTargetISA : InstrInfo;
def MyTarget : Target { let InstructionSet = MyTargetISA; }
def dummy;
def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0)>;
class I<dag OOps, dag IOps, list<dag> Pat>
: Instruction {
let Namespace = "MyTarget";
let OutOperandList = OOps;
let InOperandList = IOps;
let Pattern = Pat;
}
def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def SUB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def TRUNC : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
def SEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
def ZEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
def Rule0 : GICombineRule<
(defs root:$d),
(match (MUL $t, $s1, $s2),
(SUB $d, $t, $s3)),
(apply [{ APPLY }])>;
def Rule1 : GICombineRule<
(defs root:$d),
(match (MOV $s1, $s2),
(MOV $d, $s1)),
(apply [{ APPLY }])>;
def Rule2 : GICombineRule<
(defs root:$d),
(match (MOV $d, $s)),
(apply [{ APPLY }])>;
def Rule3 : GICombineRule<
(defs root:$d),
(match (MUL $t, $s1, $s2),
(ADD $d, $t, $s3), [{ A }]),
(apply [{ APPLY }])>;
def Rule4 : GICombineRule<
(defs root:$d),
(match (ADD $d, $s1, $s2)),
(apply [{ APPLY }])>;
def Rule5 : GICombineRule<
(defs root:$d),
(match (SUB $d, $s1, $s2)),
(apply [{ APPLY }])>;
def Rule6 : GICombineRule<
(defs root:$d),
(match (SEXT $t, $s1),
(TRUNC $d, $t)),
(apply [{ APPLY }])>;
def Rule7 : GICombineRule<
(defs root:$d),
(match (ZEXT $t, $s1),
(TRUNC $d, $t)),
(apply [{ APPLY }])>;
def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
Rule0,
Rule1,
Rule2,
Rule3,
Rule4,
Rule5,
Rule6,
Rule7
]>;
// CHECK-LABEL: digraph "matchtree" {
// CHECK-DAG: Node[[N0:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[0].getOpcode()|4 partitions|Rule0,Rule1,Rule2,Rule3,Rule4,Rule5,Rule6,Rule7}"]
// CHECK-DAG: Node[[N1:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule0,Rule5}"]
// CHECK-DAG: Node[[N2:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule0,Rule5}"]
// CHECK-DAG: Node[[N3:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule0}"]
// CHECK-DAG: Node[[N4:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule5}"]
// CHECK-DAG: Node[[N5:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule5}"]
// CHECK-DAG: Node[[N6:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule1,Rule2}"]
// CHECK-DAG: Node[[N7:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule1,Rule2}"]
// CHECK-DAG: Node[[N8:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule1}"]
// CHECK-DAG: Node[[N9:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule2}"]
// CHECK-DAG: Node[[N10:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule2}"]
// CHECK-DAG: Node[[N11:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule3,Rule4}"]
// CHECK-DAG: Node[[N12:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule3,Rule4}"]
// CHECK-DAG: Node[[N13:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule3,Rule4}",color=red]
// CHECK-DAG: Node[[N14:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule4}"]
// CHECK-DAG: Node[[N15:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule4}"]
// CHECK-DAG: Node[[N16:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|1 partitions|Rule6,Rule7}"]
// CHECK-DAG: Node[[N17:(0x)?[0-9a-fA-F]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule6,Rule7}"]
// CHECK-DAG: Node[[N18:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule6}"]
// CHECK-DAG: Node[[N19:(0x)?[0-9a-fA-F]+]] [shape=record,label="{No partitioner|Rule7}"]
// The most important partitioner is on the first opcode:
// CHECK-DAG: Node[[N0]] -> Node[[N1]] [label="#0 MyTarget::SUB"]
// CHECK-DAG: Node[[N0]] -> Node[[N6]] [label="#1 MyTarget::MOV"]
// CHECK-DAG: Node[[N0]] -> Node[[N11]] [label="#2 MyTarget::ADD"]
// CHECK-DAG: Node[[N0]] -> Node[[N16]] [label="#3 MyTarget::TRUNC"]
// For, MI[0].getOpcode() == SUB, then has to determine whether it has a reg
// operand and follow that link. If it can't then Rule5 is the only choice as
// that rule is not constrained to a reg.
// CHECK-DAG: Node[[N1]] -> Node[[N2]] [label="#0 true"]
// CHECK-DAG: Node[[N1]] -> Node[[N5]] [label="#1 false"]
// For, MI[0].getOpcode() == SUB && MI[0].getOperand(1).isReg(), if MI[1] is a
// MUL then it must be either Rule0 or Rule5. Rule0 is fully tested so Rule5 is
// unreachable. If it's not MUL then it must be Rule5.
// CHECK-DAG: Node[[N2]] -> Node[[N3]] [label="#0 MyTarget::MUL"]
// CHECK-DAG: Node[[N2]] -> Node[[N4]] [label="#1 * or nullptr"]
// CHECK-DAG: Node[[N6]] -> Node[[N7]] [label="#0 true"]
// CHECK-DAG: Node[[N6]] -> Node[[N10]] [label="#1 false"]
// CHECK-DAG: Node[[N7]] -> Node[[N8]] [label="#0 MyTarget::MOV"]
// CHECK-DAG: Node[[N7]] -> Node[[N9]] [label="#1 * or nullptr"]
// CHECK-DAG: Node[[N11]] -> Node[[N12]] [label="#0 true"]
// CHECK-DAG: Node[[N11]] -> Node[[N15]] [label="#1 false"]
// CHECK-DAG: Node[[N12]] -> Node[[N13]] [label="#0 MyTarget::MUL"]
// CHECK-DAG: Node[[N12]] -> Node[[N14]] [label="#1 * or nullptr"]
// CHECK-DAG: Node[[N16]] -> Node[[N17]] [label="#0 true"]
// CHECK-DAG: Node[[N17]] -> Node[[N18]] [label="#0 MyTarget::SEXT"]
// CHECK-DAG: Node[[N17]] -> Node[[N19]] [label="#1 MyTarget::ZEXT"]
// CHECK-LABEL: {{^}$}}
|