forked from OSchip/llvm-project
[gicombiner] Add the MatchDag structure and parse instruction DAG's from the input
Summary: The MatchDag structure is a representation of the checks that need to be performed and the dependencies that limit when they can happen. There are two kinds of node in the MatchDag: * Instrs - Represent a MachineInstr * Predicates - Represent a check that needs to be performed (i.e. opcode, is register, same machine operand, etc.) and two kinds of edges: * (Traversal) Edges - Represent a register that can be traversed to find one instr from another * Predicate Dependency Edges - Indicate that a predicate requires a piece of information to be tested. For example, the matcher: (match (MOV $t, $s), (MOV $d, $t)) with MOV declared as an instruction of the form: %dst = MOV %src1 becomes the following MatchDag with the following instruction nodes: __anon0_0 // $t=getOperand(0), $s=getOperand(1) __anon0_1 // $d=getOperand(0), $t=getOperand(1) traversal edges: __anon0_1[src1] --[t]--> __anon0_0[dst] predicate nodes: <<$mi.getOpcode() == MOV>>:$__anonpred0_2 <<$mi.getOpcode() == MOV>>:$__anonpred0_3 and predicate dependencies: __anon0_0 ==> __anonpred0_2[mi] __anon0_0 ==> __anonpred0_3[mi] The result of this parse is currently unused but can be tested using -gicombiner-stop-after-parse as done in parse-match-pattern.td. The dump for testing includes a graphviz format dump to allow the rule to be viewed visually. Later on, these MatchDag's will be used to generate code and to build an efficient decision tree. Reviewers: volkan, bogner Reviewed By: volkan Subscribers: arsenm, mgorny, mgrang, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69077
This commit is contained in:
parent
268f37df6e
commit
390c8baa54
|
@ -53,6 +53,15 @@ def unknown_kind2 : GICombineRule<
|
|||
// CHECK-NEXT: def unknown_kind2 : GICombineRule<
|
||||
// CHECK: :[[@LINE-6]]:{{[0-9]+}}: error: Failed to parse rule
|
||||
|
||||
def multidef : GICombineRule<
|
||||
(defs root:$a),
|
||||
(match (MOV $a, $b),
|
||||
(MOV $a, $b)),
|
||||
(dummy)>;
|
||||
// CHECK: :[[@LINE-5]]:{{[0-9]+}}: error: Two different MachineInstrs cannot def the same vreg
|
||||
// CHECK-NEXT: def multidef : GICombineRule<
|
||||
// CHECK: :[[@LINE-7]]:{{[0-9]+}}: error: Failed to parse rule
|
||||
|
||||
def multidef_but_not_an_error: GICombineRule<
|
||||
(defs root:$a),
|
||||
(match (MOV $a, $b),
|
||||
|
@ -66,6 +75,7 @@ def MyCombiner: GICombinerHelper<"GenMyCombiner", [
|
|||
null_matcher,
|
||||
unknown_kind1,
|
||||
unknown_kind2,
|
||||
multidef
|
||||
// Rules omitted from a matcher can be as broken as you like. They will not be read.
|
||||
// multidef_but_not_an_error
|
||||
]>;
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
|
||||
// RUN: -combiners=MyCombiner -gicombiner-stop-after-parse %s \
|
||||
// RUN: -o /dev/null -debug 2>&1 | 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 MOV2 : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
|
||||
|
||||
def trivial : GICombineRule<
|
||||
(defs root:$d),
|
||||
(match (MOV $d, $s)),
|
||||
(apply [{ APPLY }])>;
|
||||
|
||||
// CHECK-LABEL: Parsed rule defs/match for 'trivial'
|
||||
|
||||
// The matchdag block is a fairly direct dump of the information that was read.
|
||||
// It's oriented towards the data structures within tablegen.
|
||||
// CHECK-NEXT: matchdag {
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon0_0 // $d=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred0_1
|
||||
// CHECK-NEXT: __anon0_0 ==> __anonpred0_1[mi]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
// The digraph block is a human-oriented dump of the information that was read.
|
||||
// Run it through graphviz to produce a nice DAG showing the matcher behaviour.
|
||||
// CHECK-NEXT: digraph "trivial" {
|
||||
// CHECK-NEXT: rankdir="BT"
|
||||
// CHECK-NEXT: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon0_0|MOV|Match starts here|$d=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Pred[[P1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred0_1|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:e -> Pred[[P1]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
def simple : GICombineRule<
|
||||
(defs root:$d),
|
||||
(match (MOV $t, $s),
|
||||
(MOV $d, $t)),
|
||||
(apply [{ APPLY }])>;
|
||||
|
||||
// CHECK-LABEL: Parsed rule defs/match for 'simple'
|
||||
|
||||
// CHECK-NEXT: matchdag {
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon1_0 // $t=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon1_2 // $d=getOperand(0), $t=getOperand(1)
|
||||
// CHECK-NEXT: __anon1_2[src1] --[t]--> __anon1_0[dst]
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred1_1
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred1_3
|
||||
// CHECK-NEXT: __anon1_0 ==> __anonpred1_1[mi]
|
||||
// CHECK-NEXT: __anon1_2 ==> __anonpred1_3[mi]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
// CHECK-NEXT: digraph "simple" {
|
||||
// CHECK-NEXT: rankdir="BT"
|
||||
// CHECK-NEXT: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon1_0|MOV|$t=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}"]
|
||||
// CHECK-NEXT: Node[[N2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon1_2|MOV|Match starts here|$d=getOperand(0), $t=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Node[[N1]]:d0:s [label="$t"]
|
||||
// CHECK-NEXT: Pred[[P1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred1_1|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred1_3|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:e -> Pred[[P1]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:e -> Pred[[P2]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
def multiroot : GICombineRule<
|
||||
(defs root:$d1, root:$d2),
|
||||
(match (MOV $s, $s2),
|
||||
(MOV $d1, $s),
|
||||
(MOV $d2, $s)),
|
||||
(apply [{ APPLY }])>;
|
||||
|
||||
// CHECK-LABEL: Parsed rule defs/match for 'multiroot'
|
||||
|
||||
// CHECK-NEXT: matchdag {
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon2_0 // $s=getOperand(0), $s2=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon2_2 // $d1=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon2_4 // $d2=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: __anon2_2[src1] --[s]--> __anon2_0[dst]
|
||||
// CHECK-NEXT: __anon2_4[src1] --[s]--> __anon2_0[dst]
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred2_1
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred2_3
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred2_5
|
||||
// CHECK-NEXT: <<$mi0 == $mi1>>:$__anonpred2_6
|
||||
// CHECK-NEXT: __anon2_0 ==> __anonpred2_1[mi]
|
||||
// CHECK-NEXT: __anon2_2 ==> __anonpred2_3[mi]
|
||||
// CHECK-NEXT: __anon2_4 ==> __anonpred2_5[mi]
|
||||
// CHECK-NEXT: __anon2_2[src1] ==> __anonpred2_6[mi0]
|
||||
// CHECK-NEXT: __anon2_4[src1] ==> __anonpred2_6[mi1]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
// CHECK-NEXT: digraph "multiroot" {
|
||||
// CHECK-NEXT: rankdir="BT"
|
||||
// CHECK-NEXT: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon2_0|MOV|$s=getOperand(0), $s2=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}"]
|
||||
// CHECK-NEXT: Node[[N2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon2_2|MOV|Match starts here|$d1=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Node[[N3:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon2_4|MOV|Match starts here|$d2=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Node[[N1]]:d0:s [label="$s"]
|
||||
// CHECK-NEXT: Node[[N3]]:s1:n -> Node[[N1]]:d0:s [label="$s"]
|
||||
// CHECK-NEXT: Pred[[P1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred2_1|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred2_3|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P3:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred2_5|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P4:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi0|<s2>#2 $mi1}|__anonpred2_6|$mi0 == $mi1|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi0|<d2>#2 $mi1}}",style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:e -> Pred[[P1]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:e -> Pred[[P2]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N3]]:e -> Pred[[P3]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Pred[[P4]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N3]]:s1:n -> Pred[[P4]]:d2:s [style=dotted]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
def nonstandardroot : GICombineRule<
|
||||
(defs root:$s),
|
||||
(match (MOV $s, $s2),
|
||||
(MOV $d1, $s),
|
||||
(MOV $d2, $s)),
|
||||
(apply [{ APPLY }])>;
|
||||
|
||||
// CHECK-LABEL: Parsed rule defs/match for 'nonstandardroot'
|
||||
|
||||
// CHECK-NEXT: matchdag {
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon3_0 // $s=getOperand(0), $s2=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon3_2 // $d1=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon3_4 // $d2=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: __anon3_2[src1] --[s]--> __anon3_0[dst]
|
||||
// CHECK-NEXT: __anon3_4[src1] --[s]--> __anon3_0[dst]
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred3_1
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred3_3
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred3_5
|
||||
// CHECK-NEXT: <<$mi0 == $mi1>>:$__anonpred3_6
|
||||
// CHECK-NEXT: __anon3_0 ==> __anonpred3_1[mi]
|
||||
// CHECK-NEXT: __anon3_2 ==> __anonpred3_3[mi]
|
||||
// CHECK-NEXT: __anon3_4 ==> __anonpred3_5[mi]
|
||||
// CHECK-NEXT: __anon3_2[src1] ==> __anonpred3_6[mi0]
|
||||
// CHECK-NEXT: __anon3_4[src1] ==> __anonpred3_6[mi1]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
// CHECK-NEXT: digraph "nonstandardroot" {
|
||||
// CHECK-NEXT: rankdir="BT"
|
||||
// CHECK-NEXT: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon3_0|MOV|Match starts here|$s=getOperand(0), $s2=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Node[[N2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon3_2|MOV|$d1=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}"]
|
||||
// CHECK-NEXT: Node[[N3:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon3_4|MOV|$d2=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}"]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Node[[N1]]:d0:s [label="$s"]
|
||||
// CHECK-NEXT: Node[[N3]]:s1:n -> Node[[N1]]:d0:s [label="$s"]
|
||||
// CHECK-NEXT: Pred[[P1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred3_1|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred3_3|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P3:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred3_5|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P4:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi0|<s2>#2 $mi1}|__anonpred3_6|$mi0 == $mi1|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi0|<d2>#2 $mi1}}",style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:e -> Pred[[P1]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:e -> Pred[[P2]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N3]]:e -> Pred[[P3]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Pred[[P4]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N3]]:s1:n -> Pred[[P4]]:d2:s [style=dotted]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
def multiref_use : GICombineRule<
|
||||
(defs root:$d1, root:$d2),
|
||||
(match (MOV $d1, $s),
|
||||
(MOV $d2, $s)),
|
||||
(apply [{ APPLY }])>;
|
||||
|
||||
// CHECK-LABEL: Parsed rule defs/match for 'multiref_use'
|
||||
|
||||
// CHECK-NEXT: matchdag {
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon4_0 // $d1=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: (MOV 0:dst<def>, 1:src1):$__anon4_2 // $d2=getOperand(0), $s=getOperand(1)
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred4_1
|
||||
// CHECK-NEXT: <<$mi.getOpcode() == MOV>>:$__anonpred4_3
|
||||
// CHECK-NEXT: <<$mi0 == $mi1>>:$__anonpred4_4
|
||||
// CHECK-NEXT: __anon4_0 ==> __anonpred4_1[mi]
|
||||
// CHECK-NEXT: __anon4_2 ==> __anonpred4_3[mi]
|
||||
// CHECK-NEXT: __anon4_0[src1] ==> __anonpred4_4[mi0]
|
||||
// CHECK-NEXT: __anon4_2[src1] ==> __anonpred4_4[mi1]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
// CHECK-NEXT: digraph "multiref_use" {
|
||||
// CHECK-NEXT: rankdir="BT"
|
||||
// CHECK-NEXT: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon4_0|MOV|Match starts here|$d1=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Node[[N2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $dst|<s1>#1 $src1}|__anon4_2|MOV|Match starts here|$d2=getOperand(0), $s=getOperand(1)|{{0x[0-9a-f]+}}|{<d0>#0 $dst|<d1>#1 $src1}}",color=red]
|
||||
// CHECK-NEXT: Pred[[P1:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred4_1|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P2:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi}|__anonpred4_3|$mi.getOpcode() == MOV|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi}}",style=dotted]
|
||||
// CHECK-NEXT: Pred[[P3:0x[0-9a-f]+]] [shape=record,label="{{[{]{}}<s0>#0 $$|<s1>#1 $mi0|<s2>#2 $mi1}|__anonpred4_4|$mi0 == $mi1|{{0x[0-9a-f]+}}|{<d0>#0 $$|<d1>#1 $mi0|<d2>#2 $mi1}}",style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:e -> Pred[[P1]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:e -> Pred[[P2]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N1]]:s1:n -> Pred[[P3]]:d1:s [style=dotted]
|
||||
// CHECK-NEXT: Node[[N2]]:s1:n -> Pred[[P3]]:d2:s [style=dotted]
|
||||
// CHECK-NEXT: {{^}$}}
|
||||
|
||||
def MyCombiner: GICombinerHelper<"GenMyCombiner", [
|
||||
trivial,
|
||||
simple,
|
||||
multiroot,
|
||||
nonstandardroot,
|
||||
multiref_use
|
||||
]>;
|
||||
|
||||
// Verify we're sharing operand lists correctly
|
||||
// CHECK-LABEL: GIMatchDagOperandListContext {
|
||||
// CHECK-NEXT: OperandLists {
|
||||
// CHECK-NEXT: 0:dst<def>, 1:src1
|
||||
// CHECK-NEXT: 0:$<def>, 1:mi
|
||||
// CHECK-NEXT: 0:$<def>, 1:mi0, 2:mi1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
|
@ -12,7 +12,9 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/StringMatcher.h"
|
||||
|
@ -20,6 +22,7 @@
|
|||
#include "CodeGenTarget.h"
|
||||
#include "GlobalISel/CodeExpander.h"
|
||||
#include "GlobalISel/CodeExpansions.h"
|
||||
#include "GlobalISel/GIMatchDag.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
@ -38,10 +41,25 @@ static cl::opt<bool> ShowExpansions(
|
|||
"gicombiner-show-expansions",
|
||||
cl::desc("Use C++ comments to indicate occurence of code expansion"),
|
||||
cl::cat(GICombinerEmitterCat));
|
||||
static cl::opt<bool> StopAfterParse(
|
||||
"gicombiner-stop-after-parse",
|
||||
cl::desc("Stop processing after parsing rules and dump state"),
|
||||
cl::cat(GICombinerEmitterCat));
|
||||
|
||||
namespace {
|
||||
typedef uint64_t RuleID;
|
||||
|
||||
// We're going to be referencing the same small strings quite a lot for operand
|
||||
// names and the like. Make their lifetime management simple with a global
|
||||
// string table.
|
||||
StringSet<> StrTab;
|
||||
|
||||
StringRef insertStrTab(StringRef S) {
|
||||
if (S.empty())
|
||||
return S;
|
||||
return StrTab.insert(S).first->first();
|
||||
}
|
||||
|
||||
class RootInfo {
|
||||
StringRef PatternSymbol;
|
||||
|
||||
|
@ -52,12 +70,28 @@ public:
|
|||
};
|
||||
|
||||
class CombineRule {
|
||||
struct VarInfo {
|
||||
const GIMatchDagInstr *N;
|
||||
const GIMatchDagOperand *Op;
|
||||
const DagInit *Matcher;
|
||||
|
||||
public:
|
||||
VarInfo(const GIMatchDagInstr *N, const GIMatchDagOperand *Op,
|
||||
const DagInit *Matcher)
|
||||
: N(N), Op(Op), Matcher(Matcher) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
/// A unique ID for this rule
|
||||
/// ID's are used for debugging and run-time disabling of rules among other
|
||||
/// things.
|
||||
RuleID ID;
|
||||
|
||||
/// A unique ID that can be used for anonymous objects belonging to this rule.
|
||||
/// Used to create unique names in makeNameForAnon*() without making tests
|
||||
/// overly fragile.
|
||||
unsigned UID = 0;
|
||||
|
||||
/// The record defining this rule.
|
||||
const Record &TheDef;
|
||||
|
||||
|
@ -67,21 +101,36 @@ protected:
|
|||
/// from the bottom of the function to the top.
|
||||
std::vector<RootInfo> Roots;
|
||||
|
||||
GIMatchDag MatchDag;
|
||||
|
||||
/// A block of arbitrary C++ to finish testing the match.
|
||||
/// FIXME: This is a temporary measure until we have actual pattern matching
|
||||
const CodeInit *MatchingFixupCode = nullptr;
|
||||
|
||||
bool parseInstructionMatcher(const CodeGenTarget &Target, StringInit *ArgName,
|
||||
const Init &Arg,
|
||||
StringMap<std::vector<VarInfo>> &NamedEdgeDefs,
|
||||
StringMap<std::vector<VarInfo>> &NamedEdgeUses);
|
||||
|
||||
public:
|
||||
CombineRule(const CodeGenTarget &Target, RuleID ID, const Record &R)
|
||||
: ID(ID), TheDef(R) {}
|
||||
CombineRule(const CodeGenTarget &Target, GIMatchDagContext &Ctx, RuleID ID,
|
||||
const Record &R)
|
||||
: ID(ID), TheDef(R), MatchDag(Ctx) {}
|
||||
CombineRule(const CombineRule &) = delete;
|
||||
|
||||
bool parseDefs();
|
||||
bool parseMatcher(const CodeGenTarget &Target);
|
||||
|
||||
RuleID getID() const { return ID; }
|
||||
unsigned allocUID() { return UID++; }
|
||||
StringRef getName() const { return TheDef.getName(); }
|
||||
const Record &getDef() const { return TheDef; }
|
||||
const CodeInit *getMatchingFixupCode() const { return MatchingFixupCode; }
|
||||
size_t getNumRoots() const { return Roots.size(); }
|
||||
|
||||
GIMatchDag &getMatchDag() { return MatchDag; }
|
||||
const GIMatchDag &getMatchDag() const { return MatchDag; }
|
||||
|
||||
using const_root_iterator = std::vector<RootInfo>::const_iterator;
|
||||
const_root_iterator roots_begin() const { return Roots.begin(); }
|
||||
const_root_iterator roots_end() const { return Roots.end(); }
|
||||
|
@ -111,6 +160,34 @@ static Record *getDefOfSubClass(const Init &N, StringRef Cls) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// A convenience function to check that an Init refers to a dag whose operator
|
||||
/// is a def that is a subclass of the given class and coerce it to a dag if it
|
||||
/// is. This is primarily useful for testing for subclasses of GIMatchKind and
|
||||
/// similar in DagInit's since DagInit's support any type inside them.
|
||||
static const DagInit *getDagWithOperatorOfSubClass(const Init &N,
|
||||
StringRef Cls) {
|
||||
if (const DagInit *I = dyn_cast<DagInit>(&N))
|
||||
if (I->getNumArgs() > 0)
|
||||
if (const DefInit *OpI = dyn_cast<DefInit>(I->getOperator()))
|
||||
if (OpI->getDef()->isSubClassOf(Cls))
|
||||
return I;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StringRef makeNameForAnonInstr(CombineRule &Rule) {
|
||||
return insertStrTab(
|
||||
to_string(format("__anon%d_%d", Rule.getID(), Rule.allocUID())));
|
||||
}
|
||||
|
||||
StringRef makeDebugName(CombineRule &Rule, StringRef Name) {
|
||||
return insertStrTab(Name.empty() ? makeNameForAnonInstr(Rule) : StringRef(Name));
|
||||
}
|
||||
|
||||
StringRef makeNameForAnonPredicate(CombineRule &Rule) {
|
||||
return insertStrTab(
|
||||
to_string(format("__anonpred%d_%d", Rule.getID(), Rule.allocUID())));
|
||||
}
|
||||
|
||||
bool CombineRule::parseDefs() {
|
||||
NamedRegionTimer T("parseDefs", "Time spent parsing the defs", "Rule Parsing",
|
||||
"Time spent on rule parsing", TimeRegions);
|
||||
|
@ -149,9 +226,66 @@ bool CombineRule::parseDefs() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Parse an (Instruction $a:Arg1, $b:Arg2, ...) matcher. Edges are formed
|
||||
// between matching operand names between different matchers.
|
||||
bool CombineRule::parseInstructionMatcher(
|
||||
const CodeGenTarget &Target, StringInit *ArgName, const Init &Arg,
|
||||
StringMap<std::vector<VarInfo>> &NamedEdgeDefs,
|
||||
StringMap<std::vector<VarInfo>> &NamedEdgeUses) {
|
||||
if (const DagInit *Matcher =
|
||||
getDagWithOperatorOfSubClass(Arg, "Instruction")) {
|
||||
auto &Instr =
|
||||
Target.getInstruction(Matcher->getOperatorAsDef(TheDef.getLoc()));
|
||||
|
||||
StringRef Name = ArgName ? ArgName->getValue() : "";
|
||||
|
||||
GIMatchDagInstr *N =
|
||||
MatchDag.addInstrNode(makeDebugName(*this, Name), insertStrTab(Name),
|
||||
MatchDag.getContext().makeOperandList(Instr));
|
||||
|
||||
N->setOpcodeAnnotation(&Instr);
|
||||
const auto &P = MatchDag.addPredicateNode<GIMatchDagOpcodePredicate>(
|
||||
makeNameForAnonPredicate(*this), Instr);
|
||||
MatchDag.addPredicateDependency(N, nullptr, P, &P->getOperandInfo()["mi"]);
|
||||
unsigned OpIdx = 0;
|
||||
for (const auto &NameInit : Matcher->getArgNames()) {
|
||||
StringRef Name = insertStrTab(NameInit->getAsUnquotedString());
|
||||
if (Name.empty())
|
||||
continue;
|
||||
N->assignNameToOperand(OpIdx, Name);
|
||||
|
||||
// Record the endpoints of any named edges. We'll add the cartesian
|
||||
// product of edges later.
|
||||
const auto &InstrOperand = N->getOperandInfo()[OpIdx];
|
||||
if (InstrOperand.isDef()) {
|
||||
NamedEdgeDefs.try_emplace(Name);
|
||||
NamedEdgeDefs[Name].emplace_back(N, &InstrOperand, Matcher);
|
||||
} else {
|
||||
NamedEdgeUses.try_emplace(Name);
|
||||
NamedEdgeUses[Name].emplace_back(N, &InstrOperand, Matcher);
|
||||
}
|
||||
|
||||
if (InstrOperand.isDef()) {
|
||||
if (find_if(Roots, [&](const RootInfo &X) {
|
||||
return X.getPatternSymbol() == Name;
|
||||
}) != Roots.end()) {
|
||||
N->setMatchRoot();
|
||||
}
|
||||
}
|
||||
|
||||
OpIdx++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
|
||||
NamedRegionTimer T("parseMatcher", "Time spent parsing the matcher",
|
||||
"Rule Parsing", "Time spent on rule parsing", TimeRegions);
|
||||
StringMap<std::vector<VarInfo>> NamedEdgeDefs;
|
||||
StringMap<std::vector<VarInfo>> NamedEdgeUses;
|
||||
DagInit *Matchers = TheDef.getValueAsDag("Match");
|
||||
|
||||
if (Matchers->getOperatorAsDef(TheDef.getLoc())->getName() != "match") {
|
||||
|
@ -167,6 +301,11 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
|
|||
// The match section consists of a list of matchers and predicates. Parse each
|
||||
// one and add the equivalent GIMatchDag nodes, predicates, and edges.
|
||||
for (unsigned I = 0; I < Matchers->getNumArgs(); ++I) {
|
||||
if (parseInstructionMatcher(Target, Matchers->getArgName(I),
|
||||
*Matchers->getArg(I), NamedEdgeDefs,
|
||||
NamedEdgeUses))
|
||||
continue;
|
||||
|
||||
|
||||
// Parse arbitrary C++ code we have in lieu of supporting MIR matching
|
||||
if (const CodeInit *CodeI = dyn_cast<CodeInit>(Matchers->getArg(I))) {
|
||||
|
@ -182,6 +321,63 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
|
|||
PrintNote("Pattern was `" + Matchers->getArg(I)->getAsString() + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the cartesian product of use -> def edges.
|
||||
bool FailedToAddEdges = false;
|
||||
for (const auto &NameAndDefs : NamedEdgeDefs) {
|
||||
if (NameAndDefs.getValue().size() > 1) {
|
||||
PrintError(TheDef.getLoc(),
|
||||
"Two different MachineInstrs cannot def the same vreg");
|
||||
for (const auto &NameAndDefOp : NameAndDefs.getValue())
|
||||
PrintNote("in " + to_string(*NameAndDefOp.N) + " created from " +
|
||||
to_string(*NameAndDefOp.Matcher) + "");
|
||||
FailedToAddEdges = true;
|
||||
}
|
||||
const auto &Uses = NamedEdgeUses[NameAndDefs.getKey()];
|
||||
for (const VarInfo &DefVar : NameAndDefs.getValue()) {
|
||||
for (const VarInfo &UseVar : Uses) {
|
||||
MatchDag.addEdge(insertStrTab(NameAndDefs.getKey()), UseVar.N, UseVar.Op,
|
||||
DefVar.N, DefVar.Op);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FailedToAddEdges)
|
||||
return false;
|
||||
|
||||
// If a variable is referenced in multiple use contexts then we need a
|
||||
// predicate to confirm they are the same operand. We can elide this if it's
|
||||
// also referenced in a def context and we're traversing the def-use chain
|
||||
// from the def to the uses but we can't know which direction we're going
|
||||
// until after reorientToRoots().
|
||||
for (const auto &NameAndUses : NamedEdgeUses) {
|
||||
const auto &Uses = NameAndUses.getValue();
|
||||
if (Uses.size() > 1) {
|
||||
const auto &LeadingVar = Uses.front();
|
||||
for (const auto &Var : ArrayRef<VarInfo>(Uses).drop_front()) {
|
||||
// Add a predicate for each pair until we've covered the whole
|
||||
// equivalence set. We could test the whole set in a single predicate
|
||||
// but that means we can't test any equivalence until all the MO's are
|
||||
// available which can lead to wasted work matching the DAG when this
|
||||
// predicate can already be seen to have failed.
|
||||
//
|
||||
// We have a similar problem due to the need to wait for a particular MO
|
||||
// before being able to test any of them. However, that is mitigated by
|
||||
// the order in which we build the DAG. We build from the roots outwards
|
||||
// so by using the first recorded use in all the predicates, we are
|
||||
// making the dependency on one of the earliest visited references in
|
||||
// the DAG. It's not guaranteed once the generated matcher is optimized
|
||||
// (because the factoring the common portions of rules might change the
|
||||
// visit order) but this should mean that these predicates depend on the
|
||||
// first MO to become available.
|
||||
const auto &P = MatchDag.addPredicateNode<GIMatchDagSameMOPredicate>(
|
||||
makeNameForAnonPredicate(*this));
|
||||
MatchDag.addPredicateDependency(LeadingVar.N, LeadingVar.Op, P,
|
||||
&P->getOperandInfo()["mi0"]);
|
||||
MatchDag.addPredicateDependency(Var.N, Var.Op, P,
|
||||
&P->getOperandInfo()["mi1"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -190,6 +386,8 @@ class GICombinerEmitter {
|
|||
const CodeGenTarget &Target;
|
||||
Record *Combiner;
|
||||
std::vector<std::unique_ptr<CombineRule>> Rules;
|
||||
GIMatchDagContext MatchDagCtx;
|
||||
|
||||
std::unique_ptr<CombineRule> makeCombineRule(const Record &R);
|
||||
|
||||
void gatherRules(std::vector<std::unique_ptr<CombineRule>> &ActiveRules,
|
||||
|
@ -246,12 +444,20 @@ void GICombinerEmitter::emitNameMatcher(raw_ostream &OS) const {
|
|||
std::unique_ptr<CombineRule>
|
||||
GICombinerEmitter::makeCombineRule(const Record &TheDef) {
|
||||
std::unique_ptr<CombineRule> Rule =
|
||||
std::make_unique<CombineRule>(Target, NumPatternTotal, TheDef);
|
||||
std::make_unique<CombineRule>(Target, MatchDagCtx, NumPatternTotal, TheDef);
|
||||
|
||||
if (!Rule->parseDefs())
|
||||
return nullptr;
|
||||
if (!Rule->parseMatcher(Target))
|
||||
return nullptr;
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Parsed rule defs/match for '" << Rule->getName() << "'\n";
|
||||
Rule->getMatchDag().dump();
|
||||
Rule->getMatchDag().writeDOTGraph(dbgs(), Rule->getName());
|
||||
});
|
||||
if (StopAfterParse)
|
||||
return Rule;
|
||||
|
||||
// For now, don't support multi-root rules. We'll come back to this later
|
||||
// once we have the algorithm changes to support it.
|
||||
if (Rule->getNumRoots() > 1) {
|
||||
|
@ -337,6 +543,12 @@ void GICombinerEmitter::generateCodeForRule(raw_ostream &OS,
|
|||
|
||||
void GICombinerEmitter::run(raw_ostream &OS) {
|
||||
gatherRules(Rules, Combiner->getValueAsListOfDefs("Rules"));
|
||||
if (StopAfterParse) {
|
||||
MatchDagCtx.print(errs());
|
||||
PrintNote(Combiner->getLoc(),
|
||||
"Terminating due to -gicombiner-stop-after-parse");
|
||||
return;
|
||||
}
|
||||
if (ErrorsPrinted)
|
||||
PrintFatalError(Combiner->getLoc(), "Failed to parse one or more rules");
|
||||
|
||||
|
|
|
@ -4,4 +4,10 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
llvm_add_library(LLVMTableGenGlobalISel STATIC DISABLE_LLVM_LINK_LLVM_DYLIB
|
||||
CodeExpander.cpp
|
||||
GIMatchDag.cpp
|
||||
GIMatchDagEdge.cpp
|
||||
GIMatchDagInstr.cpp
|
||||
GIMatchDagOperands.cpp
|
||||
GIMatchDagPredicate.cpp
|
||||
GIMatchDagPredicateDependencyEdge.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
//===- GIMatchDag.cpp - A DAG representation of a pattern to be matched ---===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDag.h"
|
||||
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "../CodeGenInstruction.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const {
|
||||
const auto writePorts = [&](StringRef Prefix,
|
||||
const GIMatchDagOperandList &Operands) {
|
||||
StringRef Separator = "";
|
||||
OS << "{";
|
||||
for (const auto &Op : enumerate(Operands)) {
|
||||
OS << Separator << "<" << Prefix << format("%d", Op.index()) << ">"
|
||||
<< "#" << Op.index() << " $" << Op.value().getName();
|
||||
Separator = "|";
|
||||
}
|
||||
OS << "}";
|
||||
};
|
||||
|
||||
OS << "digraph \"" << ID << "\" {\n"
|
||||
<< " rankdir=\"BT\"\n";
|
||||
for (const auto &N : InstrNodes) {
|
||||
OS << " " << format("Node%p", &*N) << " [shape=record,label=\"{";
|
||||
writePorts("s", N->getOperandInfo());
|
||||
OS << "|" << N->getName();
|
||||
if (N->getOpcodeAnnotation())
|
||||
OS << "|" << N->getOpcodeAnnotation()->TheDef->getName();
|
||||
if (N->isMatchRoot())
|
||||
OS << "|Match starts here";
|
||||
OS << "|";
|
||||
SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint;
|
||||
for (const auto &Assignment : N->user_assigned_operand_names())
|
||||
ToPrint.emplace_back(Assignment.first, Assignment.second);
|
||||
llvm::sort(ToPrint.begin(), ToPrint.end());
|
||||
StringRef Separator = "";
|
||||
for (const auto &Assignment : ToPrint) {
|
||||
OS << Separator << "$" << Assignment.second << "=getOperand("
|
||||
<< Assignment.first << ")";
|
||||
Separator = ", ";
|
||||
}
|
||||
OS << format("|%p|", &N);
|
||||
writePorts("d", N->getOperandInfo());
|
||||
OS << "}\"";
|
||||
if (N->isMatchRoot())
|
||||
OS << ",color=red";
|
||||
OS << "]\n";
|
||||
}
|
||||
|
||||
for (const auto &E : Edges) {
|
||||
const char *FromFmt = "Node%p:s%d:n";
|
||||
const char *ToFmt = "Node%p:d%d:s";
|
||||
if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
|
||||
std::swap(FromFmt, ToFmt);
|
||||
auto From = format(FromFmt, E->getFromMI(), E->getFromMO()->getIdx());
|
||||
auto To = format(ToFmt, E->getToMI(), E->getToMO()->getIdx());
|
||||
if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
|
||||
std::swap(From, To);
|
||||
|
||||
OS << " " << From << " -> " << To << " [label=\"$" << E->getName();
|
||||
if (E->getFromMO()->isDef() == E->getToMO()->isDef())
|
||||
OS << " INVALID EDGE!";
|
||||
OS << "\"";
|
||||
if (E->getFromMO()->isDef() == E->getToMO()->isDef())
|
||||
OS << ",color=red";
|
||||
else if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
|
||||
OS << ",dir=back,arrowtail=crow";
|
||||
OS << "]\n";
|
||||
}
|
||||
|
||||
for (const auto &N : PredicateNodes) {
|
||||
OS << " " << format("Pred%p", &*N) << " [shape=record,label=\"{";
|
||||
writePorts("s", N->getOperandInfo());
|
||||
OS << "|" << N->getName() << "|";
|
||||
N->printDescription(OS);
|
||||
OS << format("|%p|", &N);
|
||||
writePorts("d", N->getOperandInfo());
|
||||
OS << "}\",style=dotted]\n";
|
||||
}
|
||||
|
||||
for (const auto &E : PredicateDependencies) {
|
||||
const char *FromMIFmt = "Node%p:e";
|
||||
const char *FromMOFmt = "Node%p:s%d:n";
|
||||
const char *ToFmt = "Pred%p:d%d:s";
|
||||
auto To = format(ToFmt, E->getPredicate(), E->getPredicateOp()->getIdx());
|
||||
auto Style = "[style=dotted]";
|
||||
if (E->getRequiredMO()) {
|
||||
auto From =
|
||||
format(FromMOFmt, E->getRequiredMI(), E->getRequiredMO()->getIdx());
|
||||
OS << " " << From << " -> " << To << " " << Style << "\n";
|
||||
continue;
|
||||
}
|
||||
auto From = format(FromMIFmt, E->getRequiredMI());
|
||||
OS << " " << From << " -> " << To << " " << Style << "\n";
|
||||
}
|
||||
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void GIMatchDag::print(raw_ostream &OS) const {
|
||||
OS << "matchdag {\n";
|
||||
for (const auto &N : InstrNodes) {
|
||||
OS << " ";
|
||||
N->print(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
for (const auto &E : Edges) {
|
||||
OS << " ";
|
||||
E->print(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
for (const auto &P : PredicateNodes) {
|
||||
OS << " ";
|
||||
P->print(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
for (const auto &D : PredicateDependencies) {
|
||||
OS << " ";
|
||||
D->print(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS, const GIMatchDag &G) {
|
||||
G.print(OS);
|
||||
return OS;
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
//===- GIMatchDag.h - Represent a DAG to be matched -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAG_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAG_H
|
||||
|
||||
#include "GIMatchDagEdge.h"
|
||||
#include "GIMatchDagInstr.h"
|
||||
#include "GIMatchDagOperands.h"
|
||||
#include "GIMatchDagPredicate.h"
|
||||
#include "GIMatchDagPredicateDependencyEdge.h"
|
||||
|
||||
namespace llvm {
|
||||
class GIMatchDag;
|
||||
|
||||
/// This class manages lifetimes for data associated with the GIMatchDag object.
|
||||
class GIMatchDagContext {
|
||||
GIMatchDagOperandListContext OperandListCtx;
|
||||
|
||||
public:
|
||||
const GIMatchDagOperandList &makeEmptyOperandList() {
|
||||
return OperandListCtx.makeEmptyOperandList();
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList &makeOperandList(const CodeGenInstruction &I) {
|
||||
return OperandListCtx.makeOperandList(I);
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList &makeMIPredicateOperandList() {
|
||||
return OperandListCtx.makeMIPredicateOperandList();
|
||||
}
|
||||
|
||||
|
||||
const GIMatchDagOperandList &makeTwoMOPredicateOperandList() {
|
||||
return OperandListCtx.makeTwoMOPredicateOperandList();
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const {
|
||||
OperandListCtx.print(OS);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
class GIMatchDag {
|
||||
public:
|
||||
using InstrNodesVec = std::vector<std::unique_ptr<GIMatchDagInstr>>;
|
||||
using EdgesVec = std::vector<std::unique_ptr<GIMatchDagEdge>>;
|
||||
using PredicateNodesVec = std::vector<std::unique_ptr<GIMatchDagPredicate>>;
|
||||
|
||||
using PredicateDependencyEdgesVec =
|
||||
std::vector<std::unique_ptr<GIMatchDagPredicateDependencyEdge>>;
|
||||
|
||||
protected:
|
||||
GIMatchDagContext &Ctx;
|
||||
InstrNodesVec InstrNodes;
|
||||
PredicateNodesVec PredicateNodes;
|
||||
EdgesVec Edges;
|
||||
PredicateDependencyEdgesVec PredicateDependencies;
|
||||
std::vector<GIMatchDagInstr *> MatchRoots;
|
||||
|
||||
public:
|
||||
GIMatchDag(GIMatchDagContext &Ctx)
|
||||
: Ctx(Ctx), InstrNodes(), PredicateNodes(), Edges(),
|
||||
PredicateDependencies() {}
|
||||
GIMatchDag(const GIMatchDag &) = delete;
|
||||
|
||||
GIMatchDagContext &getContext() const { return Ctx; }
|
||||
|
||||
template <class... Args> GIMatchDagInstr *addInstrNode(Args &&... args) {
|
||||
auto Obj =
|
||||
std::make_unique<GIMatchDagInstr>(*this, std::forward<Args>(args)...);
|
||||
auto ObjRaw = Obj.get();
|
||||
InstrNodes.push_back(std::move(Obj));
|
||||
return ObjRaw;
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
T *addPredicateNode(Args &&... args) {
|
||||
auto Obj = std::make_unique<T>(getContext(), std::forward<Args>(args)...);
|
||||
auto ObjRaw = Obj.get();
|
||||
PredicateNodes.push_back(std::move(Obj));
|
||||
return ObjRaw;
|
||||
}
|
||||
|
||||
template <class... Args> GIMatchDagEdge *addEdge(Args &&... args) {
|
||||
auto Obj = std::make_unique<GIMatchDagEdge>(std::forward<Args>(args)...);
|
||||
auto ObjRaw = Obj.get();
|
||||
Edges.push_back(std::move(Obj));
|
||||
return ObjRaw;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
GIMatchDagPredicateDependencyEdge *addPredicateDependency(Args &&... args) {
|
||||
auto Obj = std::make_unique<GIMatchDagPredicateDependencyEdge>(
|
||||
std::forward<Args>(args)...);
|
||||
auto ObjRaw = Obj.get();
|
||||
PredicateDependencies.push_back(std::move(Obj));
|
||||
return ObjRaw;
|
||||
}
|
||||
|
||||
void addMatchRoot(GIMatchDagInstr *N) { MatchRoots.push_back(N); }
|
||||
|
||||
LLVM_DUMP_METHOD void print(raw_ostream &OS) const;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
|
||||
void writeDOTGraph(raw_ostream &OS, StringRef ID) const;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const GIMatchDag &G);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAG_H
|
|
@ -0,0 +1,20 @@
|
|||
//===- GIMatchDagEdge.cpp - An edge describing a def/use lookup -----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDagEdge.h"
|
||||
#include "GIMatchDagInstr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
LLVM_DUMP_METHOD void GIMatchDagEdge::print(raw_ostream &OS) const {
|
||||
OS << getFromMI()->getName() << "[" << getFromMO()->getName() << "] --["
|
||||
<< Name << "]--> " << getToMI()->getName() << "[" << getToMO()->getName()
|
||||
<< "]";
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
//===- GIMatchDagEdge.h - Represent a shared operand list for nodes -------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGEDGE_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAGEDGE_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
class GIMatchDagInstr;
|
||||
class GIMatchDagOperand;
|
||||
|
||||
/// Represents an edge that connects two instructions together via a pair of
|
||||
/// operands. For example:
|
||||
/// %a = FOO ...
|
||||
/// %0 = BAR %a
|
||||
/// %1 = BAZ %a
|
||||
/// would have two edges for %a like so:
|
||||
/// BAR:Op#1 --[a]----> Op#0:FOO
|
||||
/// ^
|
||||
/// BAZ:Op#1 --[a]------/
|
||||
/// Ideally, all edges in the DAG are from a use to a def as this is a many
|
||||
/// to one edge but edges from defs to uses are supported too.
|
||||
class GIMatchDagEdge {
|
||||
/// The name of the edge. For example,
|
||||
/// (FOO $a, $b, $c)
|
||||
/// (BAR $d, $e, $a)
|
||||
/// will create an edge named 'a' to connect FOO to BAR. Although the name
|
||||
/// refers to the edge, the canonical value of 'a' is the operand that defines
|
||||
/// it.
|
||||
StringRef Name;
|
||||
const GIMatchDagInstr *FromMI;
|
||||
const GIMatchDagOperand *FromMO;
|
||||
const GIMatchDagInstr *ToMI;
|
||||
const GIMatchDagOperand *ToMO;
|
||||
|
||||
public:
|
||||
GIMatchDagEdge(StringRef Name, const GIMatchDagInstr *FromMI, const GIMatchDagOperand *FromMO,
|
||||
const GIMatchDagInstr *ToMI, const GIMatchDagOperand *ToMO)
|
||||
: Name(Name), FromMI(FromMI), FromMO(FromMO), ToMI(ToMI), ToMO(ToMO) {}
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
const GIMatchDagInstr *getFromMI() const { return FromMI; }
|
||||
const GIMatchDagOperand *getFromMO() const { return FromMO; }
|
||||
const GIMatchDagInstr *getToMI() const { return ToMI; }
|
||||
const GIMatchDagOperand *getToMO() const { return ToMO; }
|
||||
|
||||
LLVM_DUMP_METHOD void print(raw_ostream &OS) const;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const GIMatchDagEdge &E);
|
||||
|
||||
} // end namespace llvm
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGEDGE_H
|
|
@ -0,0 +1,48 @@
|
|||
//===- GIMatchDagInstr.cpp - A shared operand list for nodes --------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDagInstr.h"
|
||||
#include "../CodeGenInstruction.h"
|
||||
#include "GIMatchDag.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void GIMatchDagInstr::print(raw_ostream &OS) const {
|
||||
OS << "(";
|
||||
if (const auto *Annotation = getOpcodeAnnotation())
|
||||
OS << Annotation->TheDef->getName();
|
||||
else
|
||||
OS << "<unknown>";
|
||||
OS << " ";
|
||||
OperandInfo.print(OS);
|
||||
OS << "):$" << Name;
|
||||
if (!UserAssignedNamesForOperands.empty()) {
|
||||
OS << " // ";
|
||||
SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint;
|
||||
for (const auto &Assignment : UserAssignedNamesForOperands)
|
||||
ToPrint.emplace_back(Assignment.first, Assignment.second);
|
||||
llvm::sort(ToPrint.begin(), ToPrint.end());
|
||||
StringRef Separator = "";
|
||||
for (const auto &Assignment : ToPrint) {
|
||||
OS << Separator << "$" << Assignment.second << "=getOperand("
|
||||
<< Assignment.first << ")";
|
||||
Separator = ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GIMatchDagInstr::setMatchRoot() {
|
||||
IsMatchRoot = true;
|
||||
Dag.addMatchRoot(this);
|
||||
}
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS, const GIMatchDagInstr &N) {
|
||||
N.print(OS);
|
||||
return OS;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//===- GIMatchDagInstr.h - Represent a instruction to be matched ----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGINSTR_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAGINSTR_H
|
||||
|
||||
#include "GIMatchDagOperands.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace llvm {
|
||||
class GIMatchDag;
|
||||
|
||||
/// Represents an instruction in the match DAG. This object knows very little
|
||||
/// about the actual instruction to be matched as the bulk of that is in
|
||||
/// predicates that are associated with the match DAG. It merely knows the names
|
||||
/// and indices of any operands that need to be matched in order to allow edges
|
||||
/// to link to them.
|
||||
///
|
||||
/// Instances of this class objects are owned by the GIMatchDag and are not
|
||||
/// shareable between instances of GIMatchDag. This is because the Name,
|
||||
/// IsMatchRoot, and OpcodeAnnotation are likely to differ between GIMatchDag
|
||||
/// instances.
|
||||
class GIMatchDagInstr {
|
||||
public:
|
||||
using const_user_assigned_operand_names_iterator =
|
||||
DenseMap<unsigned, StringRef>::const_iterator;
|
||||
|
||||
protected:
|
||||
/// The match DAG this instruction belongs to.
|
||||
GIMatchDag &Dag;
|
||||
|
||||
/// The name of the instruction in the pattern. For example:
|
||||
/// (FOO $a, $b, $c):$name
|
||||
/// will cause name to be assigned to this member. Anonymous instructions will
|
||||
/// have a name assigned for debugging purposes.
|
||||
StringRef Name;
|
||||
|
||||
/// The name of the instruction in the pattern as assigned by the user. For
|
||||
/// example:
|
||||
/// (FOO $a, $b, $c):$name
|
||||
/// will cause name to be assigned to this member. If a name is not provided,
|
||||
/// this will be empty. This name is used to bind variables from rules to the
|
||||
/// matched instruction.
|
||||
StringRef UserAssignedName;
|
||||
|
||||
/// The name of each operand (if any) that was assigned by the user. For
|
||||
/// example:
|
||||
/// (FOO $a, $b, $c):$name
|
||||
/// will cause {0, "a"}, {1, "b"}, {2, "c} to be inserted into this map.
|
||||
DenseMap<unsigned, StringRef> UserAssignedNamesForOperands;
|
||||
|
||||
/// The operand list for this instruction. This object may be shared with
|
||||
/// other instructions of a similar 'shape'.
|
||||
const GIMatchDagOperandList &OperandInfo;
|
||||
|
||||
/// For debugging purposes, it's helpful to have access to a description of
|
||||
/// the Opcode. However, this object shouldn't use it for more than debugging
|
||||
/// output since predicates are expected to be handled outside the DAG.
|
||||
CodeGenInstruction *OpcodeAnnotation = 0;
|
||||
|
||||
/// When true, this instruction will be a starting point for a match attempt.
|
||||
bool IsMatchRoot = false;
|
||||
|
||||
public:
|
||||
GIMatchDagInstr(GIMatchDag &Dag, StringRef Name, StringRef UserAssignedName,
|
||||
const GIMatchDagOperandList &OperandInfo)
|
||||
: Dag(Dag), Name(Name), UserAssignedName(UserAssignedName),
|
||||
OperandInfo(OperandInfo) {}
|
||||
|
||||
const GIMatchDagOperandList &getOperandInfo() const { return OperandInfo; }
|
||||
StringRef getName() const { return Name; }
|
||||
void assignNameToOperand(unsigned Idx, StringRef Name) {
|
||||
assert(UserAssignedNamesForOperands[Idx].empty() && "Cannot assign twice");
|
||||
UserAssignedNamesForOperands[Idx] = Name;
|
||||
}
|
||||
|
||||
const_user_assigned_operand_names_iterator
|
||||
user_assigned_operand_names_begin() const {
|
||||
return UserAssignedNamesForOperands.begin();
|
||||
}
|
||||
const_user_assigned_operand_names_iterator
|
||||
user_assigned_operand_names_end() const {
|
||||
return UserAssignedNamesForOperands.end();
|
||||
}
|
||||
iterator_range<const_user_assigned_operand_names_iterator>
|
||||
user_assigned_operand_names() const {
|
||||
return make_range(user_assigned_operand_names_begin(),
|
||||
user_assigned_operand_names_end());
|
||||
}
|
||||
|
||||
/// Mark this instruction as being a root of the match. This means that the
|
||||
/// matcher will start from this node when attempting to match MIR.
|
||||
void setMatchRoot();
|
||||
bool isMatchRoot() const { return IsMatchRoot; }
|
||||
|
||||
void setOpcodeAnnotation(CodeGenInstruction *I) { OpcodeAnnotation = I; }
|
||||
CodeGenInstruction *getOpcodeAnnotation() const { return OpcodeAnnotation; }
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const GIMatchDagInstr &N);
|
||||
|
||||
} // end namespace llvm
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGINSTR_H
|
|
@ -0,0 +1,153 @@
|
|||
//===- GIMatchDagOperands.cpp - A shared operand list for nodes -----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDagOperands.h"
|
||||
|
||||
#include "../CodeGenInstruction.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void GIMatchDagOperand::Profile(FoldingSetNodeID &ID) const {
|
||||
Profile(ID, Idx, Name, IsDef);
|
||||
}
|
||||
|
||||
void GIMatchDagOperand::Profile(FoldingSetNodeID &ID, size_t Idx,
|
||||
StringRef Name, bool IsDef) {
|
||||
ID.AddInteger(Idx);
|
||||
ID.AddString(Name);
|
||||
ID.AddBoolean(IsDef);
|
||||
}
|
||||
|
||||
void GIMatchDagOperandList::add(StringRef Name, unsigned Idx, bool IsDef) {
|
||||
assert(Idx == Operands.size() && "Operands added in wrong order");
|
||||
Operands.emplace_back(Operands.size(), Name, IsDef);
|
||||
OperandsByName.try_emplace(Operands.back().getName(), Operands.size() - 1);
|
||||
}
|
||||
|
||||
void GIMatchDagOperandList::Profile(FoldingSetNodeID &ID) const {
|
||||
for (const auto &I : enumerate(Operands))
|
||||
GIMatchDagOperand::Profile(ID, I.index(), I.value().getName(),
|
||||
I.value().isDef());
|
||||
}
|
||||
|
||||
void GIMatchDagOperandList::print(raw_ostream &OS) const {
|
||||
if (Operands.empty()) {
|
||||
OS << "<empty>";
|
||||
return;
|
||||
}
|
||||
StringRef Separator = "";
|
||||
for (const auto &I : Operands) {
|
||||
OS << Separator << I.getIdx() << ":" << I.getName();
|
||||
if (I.isDef())
|
||||
OS << "<def>";
|
||||
Separator = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList::value_type &GIMatchDagOperandList::
|
||||
operator[](StringRef K) const {
|
||||
const auto &I = OperandsByName.find(K);
|
||||
assert(I != OperandsByName.end() && "Operand not found by name");
|
||||
return Operands[I->second];
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList &
|
||||
GIMatchDagOperandListContext::makeEmptyOperandList() {
|
||||
FoldingSetNodeID ID;
|
||||
|
||||
void *InsertPoint;
|
||||
GIMatchDagOperandList *Value =
|
||||
OperandLists.FindNodeOrInsertPos(ID, InsertPoint);
|
||||
if (Value)
|
||||
return *Value;
|
||||
|
||||
std::unique_ptr<GIMatchDagOperandList> NewValue =
|
||||
std::make_unique<GIMatchDagOperandList>();
|
||||
OperandLists.InsertNode(NewValue.get(), InsertPoint);
|
||||
OperandListsOwner.push_back(std::move(NewValue));
|
||||
return *OperandListsOwner.back().get();
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList &
|
||||
GIMatchDagOperandListContext::makeOperandList(const CodeGenInstruction &I) {
|
||||
FoldingSetNodeID ID;
|
||||
for (unsigned i = 0; i < I.Operands.size(); ++i)
|
||||
GIMatchDagOperand::Profile(ID, i, I.Operands[i].Name,
|
||||
i < I.Operands.NumDefs);
|
||||
|
||||
void *InsertPoint;
|
||||
GIMatchDagOperandList *Value =
|
||||
OperandLists.FindNodeOrInsertPos(ID, InsertPoint);
|
||||
if (Value)
|
||||
return *Value;
|
||||
|
||||
std::unique_ptr<GIMatchDagOperandList> NewValue =
|
||||
std::make_unique<GIMatchDagOperandList>();
|
||||
for (unsigned i = 0; i < I.Operands.size(); ++i)
|
||||
NewValue->add(I.Operands[i].Name, i, i < I.Operands.NumDefs);
|
||||
OperandLists.InsertNode(NewValue.get(), InsertPoint);
|
||||
OperandListsOwner.push_back(std::move(NewValue));
|
||||
return *OperandListsOwner.back().get();
|
||||
}
|
||||
|
||||
const GIMatchDagOperandList &
|
||||
GIMatchDagOperandListContext::makeMIPredicateOperandList() {
|
||||
FoldingSetNodeID ID;
|
||||
GIMatchDagOperand::Profile(ID, 0, "$", true);
|
||||
GIMatchDagOperand::Profile(ID, 1, "mi", false);
|
||||
|
||||
void *InsertPoint;
|
||||
GIMatchDagOperandList *Value =
|
||||
OperandLists.FindNodeOrInsertPos(ID, InsertPoint);
|
||||
if (Value)
|
||||
return *Value;
|
||||
|
||||
std::unique_ptr<GIMatchDagOperandList> NewValue =
|
||||
std::make_unique<GIMatchDagOperandList>();
|
||||
NewValue->add("$", 0, true);
|
||||
NewValue->add("mi", 1, false);
|
||||
OperandLists.InsertNode(NewValue.get(), InsertPoint);
|
||||
OperandListsOwner.push_back(std::move(NewValue));
|
||||
return *OperandListsOwner.back().get();
|
||||
}
|
||||
|
||||
|
||||
const GIMatchDagOperandList &
|
||||
GIMatchDagOperandListContext::makeTwoMOPredicateOperandList() {
|
||||
FoldingSetNodeID ID;
|
||||
GIMatchDagOperand::Profile(ID, 0, "$", true);
|
||||
GIMatchDagOperand::Profile(ID, 1, "mi0", false);
|
||||
GIMatchDagOperand::Profile(ID, 2, "mi1", false);
|
||||
|
||||
void *InsertPoint;
|
||||
GIMatchDagOperandList *Value =
|
||||
OperandLists.FindNodeOrInsertPos(ID, InsertPoint);
|
||||
if (Value)
|
||||
return *Value;
|
||||
|
||||
std::unique_ptr<GIMatchDagOperandList> NewValue =
|
||||
std::make_unique<GIMatchDagOperandList>();
|
||||
NewValue->add("$", 0, true);
|
||||
NewValue->add("mi0", 1, false);
|
||||
NewValue->add("mi1", 2, false);
|
||||
OperandLists.InsertNode(NewValue.get(), InsertPoint);
|
||||
OperandListsOwner.push_back(std::move(NewValue));
|
||||
return *OperandListsOwner.back().get();
|
||||
}
|
||||
|
||||
void GIMatchDagOperandListContext::print(raw_ostream &OS) const {
|
||||
OS << "GIMatchDagOperandListContext {\n"
|
||||
<< " OperandLists {\n";
|
||||
for (const auto &I : OperandLists) {
|
||||
OS << " ";
|
||||
I.print(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
OS << " }\n"
|
||||
<< "}\n";
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
//===- GIMatchDagOperands.h - Represent a shared operand list for nodes ---===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGOPERANDS_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAGOPERANDS_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class CodeGenInstruction;
|
||||
/// Describes an operand of a MachineInstr w.r.t the DAG Matching. This
|
||||
/// information is derived from CodeGenInstruction::Operands but is more
|
||||
/// readily available for context-less access as we don't need to know which
|
||||
/// instruction it's used with or know how many defs that instruction had.
|
||||
///
|
||||
/// There may be multiple GIMatchDagOperand's with the same contents. However,
|
||||
/// they are uniqued within the set of instructions that have the same overall
|
||||
/// operand list. For example, given:
|
||||
/// Inst1 operands ($dst:<def>, $src1, $src2)
|
||||
/// Inst2 operands ($dst:<def>, $src1, $src2)
|
||||
/// Inst3 operands ($dst:<def>, $src)
|
||||
/// $src1 will have a single instance of GIMatchDagOperand shared by Inst1 and
|
||||
/// Inst2, as will $src2. $dst however, will have two instances one shared
|
||||
/// between Inst1 and Inst2 and one unique to Inst3. We could potentially
|
||||
/// fully de-dupe the GIMatchDagOperand instances but the saving is not expected
|
||||
/// to be worth the overhead.
|
||||
///
|
||||
/// The result of this is that the address of the object can be relied upon to
|
||||
/// trivially identify commonality between two instructions which will be useful
|
||||
/// when generating the matcher. When the pointers differ, the contents can be
|
||||
/// inspected instead.
|
||||
class GIMatchDagOperand {
|
||||
unsigned Idx;
|
||||
StringRef Name;
|
||||
bool IsDef;
|
||||
|
||||
public:
|
||||
GIMatchDagOperand(unsigned Idx, StringRef Name, bool IsDef)
|
||||
: Idx(Idx), Name(Name), IsDef(IsDef) {}
|
||||
|
||||
unsigned getIdx() const { return Idx; }
|
||||
StringRef getName() const { return Name; }
|
||||
bool isDef() const { return IsDef; }
|
||||
|
||||
/// This object isn't a FoldingSetNode but it's part of one. See FoldingSet
|
||||
/// for details on the Profile function.
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
|
||||
/// A helper that behaves like Profile() but is also usable without the object.
|
||||
/// We use size_t here to match enumerate<...>::index(). If we don't match
|
||||
/// that the hashes won't be equal.
|
||||
static void Profile(FoldingSetNodeID &ID, size_t Idx, StringRef Name,
|
||||
bool IsDef);
|
||||
};
|
||||
|
||||
/// A list of GIMatchDagOperands for an instruction without any association with
|
||||
/// a particular instruction.
|
||||
///
|
||||
/// An important detail to be aware of with this class is that they are shared
|
||||
/// with other instructions of a similar 'shape'. For example, all the binary
|
||||
/// instructions are likely to share a single GIMatchDagOperandList. This is
|
||||
/// primarily a memory optimization as it's fairly common to have a large number
|
||||
/// of instructions but only a few 'shapes'.
|
||||
///
|
||||
/// See GIMatchDagOperandList::Profile() for the details on how they are folded.
|
||||
class GIMatchDagOperandList : public FoldingSetNode {
|
||||
public:
|
||||
using value_type = GIMatchDagOperand;
|
||||
|
||||
protected:
|
||||
using vector_type = SmallVector<GIMatchDagOperand, 3>;
|
||||
|
||||
public:
|
||||
using iterator = vector_type::iterator;
|
||||
using const_iterator = vector_type::const_iterator;
|
||||
|
||||
protected:
|
||||
vector_type Operands;
|
||||
StringMap<unsigned> OperandsByName;
|
||||
|
||||
public:
|
||||
void add(StringRef Name, unsigned Idx, bool IsDef);
|
||||
|
||||
/// See FoldingSet for details.
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
|
||||
iterator begin() { return Operands.begin(); }
|
||||
const_iterator begin() const { return Operands.begin(); }
|
||||
iterator end() { return Operands.end(); }
|
||||
const_iterator end() const { return Operands.end(); }
|
||||
|
||||
const value_type &operator[](unsigned I) const { return Operands[I]; }
|
||||
const value_type &operator[](StringRef K) const;
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
/// This is the portion of GIMatchDagContext that directly relates to
|
||||
/// GIMatchDagOperandList and GIMatchDagOperandList.
|
||||
class GIMatchDagOperandListContext {
|
||||
FoldingSet<GIMatchDagOperandList> OperandLists;
|
||||
std::vector<std::unique_ptr<GIMatchDagOperandList>> OperandListsOwner;
|
||||
|
||||
public:
|
||||
const GIMatchDagOperandList &makeEmptyOperandList();
|
||||
const GIMatchDagOperandList &makeOperandList(const CodeGenInstruction &I);
|
||||
const GIMatchDagOperandList &makeMIPredicateOperandList();
|
||||
const GIMatchDagOperandList &makeTwoMOPredicateOperandList();
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGOPERANDS_H
|
|
@ -0,0 +1,53 @@
|
|||
//===- GIMatchDagPredicate.cpp - Represent a predicate to check -----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDagPredicate.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
|
||||
#include "GIMatchDagOperands.h"
|
||||
#include "../CodeGenInstruction.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void GIMatchDagPredicate::print(raw_ostream &OS) const {
|
||||
OS << "<<";
|
||||
printDescription(OS);
|
||||
OS << ">>:$" << Name;
|
||||
}
|
||||
|
||||
void GIMatchDagPredicate::printDescription(raw_ostream &OS) const { OS << ""; }
|
||||
|
||||
GIMatchDagOpcodePredicate::GIMatchDagOpcodePredicate(
|
||||
GIMatchDagContext &Ctx, StringRef Name, const CodeGenInstruction &Instr)
|
||||
: GIMatchDagPredicate(GIMatchDagPredicateKind_Opcode, Name,
|
||||
Ctx.makeMIPredicateOperandList()),
|
||||
Instr(Instr) {}
|
||||
|
||||
void GIMatchDagOpcodePredicate::printDescription(raw_ostream &OS) const {
|
||||
OS << "$mi.getOpcode() == " << Instr.TheDef->getName();
|
||||
}
|
||||
|
||||
GIMatchDagSameMOPredicate::GIMatchDagSameMOPredicate(GIMatchDagContext &Ctx,
|
||||
StringRef Name)
|
||||
: GIMatchDagPredicate(GIMatchDagPredicateKind_SameMO, Name,
|
||||
Ctx.makeTwoMOPredicateOperandList()) {}
|
||||
|
||||
void GIMatchDagSameMOPredicate::printDescription(raw_ostream &OS) const {
|
||||
OS << "$mi0 == $mi1";
|
||||
}
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS, const GIMatchDagPredicate &N) {
|
||||
N.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS,
|
||||
const GIMatchDagOpcodePredicate &N) {
|
||||
N.print(OS);
|
||||
return OS;
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
//===- GIMatchDagPredicate - Represent a predicate to check ---------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATE_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATE_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "GIMatchDag.h"
|
||||
namespace llvm {
|
||||
class CodeGenInstruction;
|
||||
class GIMatchDagOperandList;
|
||||
class GIMatchDagContext;
|
||||
class raw_ostream;
|
||||
|
||||
/// Represents a predicate on the match DAG. This records the details of the
|
||||
/// predicate. The dependencies are stored in the GIMatchDag as edges.
|
||||
///
|
||||
/// Instances of this class objects are owned by the GIMatchDag and are not
|
||||
/// shareable between instances of GIMatchDag.
|
||||
class GIMatchDagPredicate {
|
||||
public:
|
||||
enum GIMatchDagPredicateKind {
|
||||
GIMatchDagPredicateKind_Opcode,
|
||||
GIMatchDagPredicateKind_SameMO,
|
||||
};
|
||||
|
||||
protected:
|
||||
const GIMatchDagPredicateKind Kind;
|
||||
|
||||
/// The name of the predicate. For example:
|
||||
/// (FOO $a:s32, $b, $c)
|
||||
/// will cause 's32' to be assigned to this member for the $a predicate.
|
||||
/// Similarly, the opcode predicate will cause 'FOO' to be assigned to this
|
||||
/// member. Anonymous instructions will have a name assigned for debugging
|
||||
/// purposes.
|
||||
StringRef Name;
|
||||
|
||||
/// The operand list for this predicate. This object may be shared with
|
||||
/// other predicates of a similar 'shape'.
|
||||
const GIMatchDagOperandList &OperandInfo;
|
||||
|
||||
public:
|
||||
GIMatchDagPredicate(GIMatchDagPredicateKind Kind, StringRef Name,
|
||||
const GIMatchDagOperandList &OperandInfo)
|
||||
: Kind(Kind), Name(Name), OperandInfo(OperandInfo) {}
|
||||
virtual ~GIMatchDagPredicate() {}
|
||||
|
||||
GIMatchDagPredicateKind getKind() const { return Kind; }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
const GIMatchDagOperandList &getOperandInfo() const { return OperandInfo; }
|
||||
|
||||
virtual void print(raw_ostream &OS) const;
|
||||
virtual void printDescription(raw_ostream &OS) const;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
virtual LLVM_DUMP_METHOD void dump() const { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
class GIMatchDagOpcodePredicate : public GIMatchDagPredicate {
|
||||
const CodeGenInstruction &Instr;
|
||||
|
||||
public:
|
||||
GIMatchDagOpcodePredicate(GIMatchDagContext &Ctx, StringRef Name,
|
||||
const CodeGenInstruction &Instr);
|
||||
|
||||
static bool classof(const GIMatchDagPredicate *P) {
|
||||
return P->getKind() == GIMatchDagPredicateKind_Opcode;
|
||||
}
|
||||
|
||||
const CodeGenInstruction *getInstr() const { return &Instr; }
|
||||
|
||||
void printDescription(raw_ostream &OS) const override;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
virtual LLVM_DUMP_METHOD void dump() const override { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
class GIMatchDagSameMOPredicate : public GIMatchDagPredicate {
|
||||
public:
|
||||
GIMatchDagSameMOPredicate(GIMatchDagContext &Ctx, StringRef Name);
|
||||
|
||||
static bool classof(const GIMatchDagPredicate *P) {
|
||||
return P->getKind() == GIMatchDagPredicateKind_SameMO;
|
||||
}
|
||||
|
||||
void printDescription(raw_ostream &OS) const override;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
virtual LLVM_DUMP_METHOD void dump() const override { print(errs()); }
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const GIMatchDagPredicate &N);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const GIMatchDagOpcodePredicate &N);
|
||||
|
||||
} // end namespace llvm
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATE_H
|
|
@ -0,0 +1,35 @@
|
|||
//===- GIMatchDagPredicateDependencyEdge.cpp - Have inputs before check ---===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GIMatchDagPredicateDependencyEdge.h"
|
||||
|
||||
#include "GIMatchDagInstr.h"
|
||||
#include "GIMatchDagPredicate.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
LLVM_DUMP_METHOD void
|
||||
GIMatchDagPredicateDependencyEdge::print(raw_ostream &OS) const {
|
||||
OS << getRequiredMI()->getName();
|
||||
if (getRequiredMO())
|
||||
OS << "[" << getRequiredMO()->getName() << "]";
|
||||
OS << " ==> " << getPredicate()->getName() << "["
|
||||
<< getPredicateOp()->getName() << "]";
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void GIMatchDagPredicateDependencyEdge::dump() const {
|
||||
print(errs());
|
||||
}
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
|
||||
raw_ostream &llvm::operator<<(raw_ostream &OS,
|
||||
const GIMatchDagPredicateDependencyEdge &E) {
|
||||
E.print(OS);
|
||||
return OS;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//===- GIMatchDagPredicateDependencyEdge - Ensure predicates have inputs --===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATEEDGE_H
|
||||
#define LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATEEDGE_H
|
||||
|
||||
#include "GIMatchDagOperands.h"
|
||||
|
||||
namespace llvm {
|
||||
class GIMatchDag;
|
||||
class GIMatchDagInstr;
|
||||
class GIMatchDagEdge;
|
||||
class GIMatchDagPredicate;
|
||||
|
||||
/// Represents a dependency that must be met to evaluate a predicate.
|
||||
///
|
||||
/// Instances of this class objects are owned by the GIMatchDag and are not
|
||||
/// shareable between instances of GIMatchDag.
|
||||
class GIMatchDagPredicateDependencyEdge {
|
||||
/// The MI that must be available in order to test the predicate.
|
||||
const GIMatchDagInstr *RequiredMI;
|
||||
/// The MO that must be available in order to test the predicate. May be
|
||||
/// nullptr when only the MI is required.
|
||||
const GIMatchDagOperand *RequiredMO;
|
||||
/// The Predicate that requires information from RequiredMI/RequiredMO.
|
||||
const GIMatchDagPredicate *Predicate;
|
||||
/// The Predicate operand that requires information from
|
||||
/// RequiredMI/RequiredMO.
|
||||
const GIMatchDagOperand *PredicateOp;
|
||||
|
||||
public:
|
||||
GIMatchDagPredicateDependencyEdge(const GIMatchDagInstr *RequiredMI,
|
||||
const GIMatchDagOperand *RequiredMO,
|
||||
const GIMatchDagPredicate *Predicate,
|
||||
const GIMatchDagOperand *PredicateOp)
|
||||
: RequiredMI(RequiredMI), RequiredMO(RequiredMO), Predicate(Predicate),
|
||||
PredicateOp(PredicateOp) {}
|
||||
|
||||
const GIMatchDagInstr *getRequiredMI() const { return RequiredMI; }
|
||||
const GIMatchDagOperand *getRequiredMO() const { return RequiredMO; }
|
||||
const GIMatchDagPredicate *getPredicate() const { return Predicate; }
|
||||
const GIMatchDagOperand *getPredicateOp() const { return PredicateOp; }
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS,
|
||||
const GIMatchDagPredicateDependencyEdge &N);
|
||||
|
||||
} // end namespace llvm
|
||||
#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAGPREDICATEEDGE_H
|
Loading…
Reference in New Issue