Skip to content

Commit 573fa77

Browse files
authored
[TableGen][GlobalISel] Add rule-wide type inference (#66377)
The inference is trivial and leverages the MCOI OperandTypes encoded in CodeGenInstructions to infer types across patterns in a CombineRule. It's thus very limited and only supports CodeGenInstructions (but that's the main use case so it's fine). We only try to infer untyped operands in apply patterns when they're temp reg defs, or immediates. Inference always outputs a `GITypeOf<$x>` where $x is a named operand from a match pattern. This allows us to drop the `GITypeOf` in most cases without any errors.
1 parent 1146d96 commit 573fa77

File tree

6 files changed

+662
-144
lines changed

6 files changed

+662
-144
lines changed

llvm/include/llvm/Target/GenericOpcodes.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
class GenericInstruction : StandardPseudoInstruction {
1919
let isPreISelOpcode = true;
20+
21+
// When all variadic ops share a type with another operand,
22+
// this is the type they share. Used by MIR patterns type inference.
23+
TypedOperand variadicOpsType = ?;
2024
}
2125

2226
// Provide a variant of an instruction with the same operands, but
@@ -1228,6 +1232,7 @@ def G_UNMERGE_VALUES : GenericInstruction {
12281232
let OutOperandList = (outs type0:$dst0, variable_ops);
12291233
let InOperandList = (ins type1:$src);
12301234
let hasSideEffects = false;
1235+
let variadicOpsType = type0;
12311236
}
12321237

12331238
// Insert a smaller register into a larger one at the specified bit-index.
@@ -1245,6 +1250,7 @@ def G_MERGE_VALUES : GenericInstruction {
12451250
let OutOperandList = (outs type0:$dst);
12461251
let InOperandList = (ins type1:$src0, variable_ops);
12471252
let hasSideEffects = false;
1253+
let variadicOpsType = type1;
12481254
}
12491255

12501256
/// Create a vector from multiple scalar registers. No implicit
@@ -1254,6 +1260,7 @@ def G_BUILD_VECTOR : GenericInstruction {
12541260
let OutOperandList = (outs type0:$dst);
12551261
let InOperandList = (ins type1:$src0, variable_ops);
12561262
let hasSideEffects = false;
1263+
let variadicOpsType = type1;
12571264
}
12581265

12591266
/// Like G_BUILD_VECTOR, but truncates the larger operand types to fit the

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ def trunc_shift: GICombineRule <
796796
def mul_by_neg_one: GICombineRule <
797797
(defs root:$dst),
798798
(match (G_MUL $dst, $x, -1)),
799-
(apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
799+
(apply (G_SUB $dst, 0, $x))
800800
>;
801801

802802
// Fold (xor (and x, y), y) -> (and (not x), y)

llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def bad_imm_too_many_args : GICombineRule<
151151
(match (COPY $x, (i32 0, 0)):$d),
152152
(apply (COPY $x, $b):$d)>;
153153

154-
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: cannot parse immediate '(COPY 0)', 'COPY' is not a ValueType
154+
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: cannot parse immediate '(COPY 0)': unknown type 'COPY'
155155
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(COPY ?:$x, (COPY 0))
156156
def bad_imm_not_a_valuetype : GICombineRule<
157157
(defs root:$a),
@@ -186,7 +186,7 @@ def expected_op_name : GICombineRule<
186186
(match (G_FNEG $x, i32)),
187187
(apply (COPY $x, (i32 0)))>;
188188

189-
// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: invalid operand type: 'not_a_type' is not a ValueType
189+
// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: cannot parse operand type: unknown type 'not_a_type'
190190
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_FNEG ?:$x, not_a_type:$y)'
191191
def not_a_type;
192192
def bad_mo_type_not_a_valuetype : GICombineRule<
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
2+
// RUN: -gicombiner-debug-typeinfer -combiners=MyCombiner %s 2>&1 | \
3+
// RUN: FileCheck %s
4+
5+
// Checks reasoning of the inference rules.
6+
7+
include "llvm/Target/Target.td"
8+
include "llvm/Target/GlobalISel/Combine.td"
9+
10+
def MyTargetISA : InstrInfo;
11+
def MyTarget : Target { let InstructionSet = MyTargetISA; }
12+
13+
// CHECK: Rule Operand Type Equivalence Classes for inference_mul_by_neg_one:
14+
// CHECK-NEXT: Groups for __inference_mul_by_neg_one_match_0: [dst, x]
15+
// CHECK-NEXT: Groups for __inference_mul_by_neg_one_apply_0: [dst, x]
16+
// CHECK-NEXT: Final Type Equivalence Classes: [dst, x]
17+
// CHECK-NEXT: INFER: imm 0 -> GITypeOf<$x>
18+
// CHECK-NEXT: Apply patterns for rule inference_mul_by_neg_one after inference:
19+
// CHECK-NEXT: (CodeGenInstructionPattern name:__inference_mul_by_neg_one_apply_0 G_SUB operands:[<def>$dst, (GITypeOf<$x> 0), $x])
20+
def inference_mul_by_neg_one: GICombineRule <
21+
(defs root:$dst),
22+
(match (G_MUL $dst, $x, -1)),
23+
(apply (G_SUB $dst, 0, $x))
24+
>;
25+
26+
// CHECK: Rule Operand Type Equivalence Classes for infer_complex_tempreg:
27+
// CHECK-NEXT: Groups for __infer_complex_tempreg_match_0: [dst] [x, y, z]
28+
// CHECK-NEXT: Groups for __infer_complex_tempreg_apply_0: [tmp2] [x, y]
29+
// CHECK-NEXT: Groups for __infer_complex_tempreg_apply_1: [tmp, tmp2]
30+
// CHECK-NEXT: Groups for __infer_complex_tempreg_apply_2: [dst, tmp]
31+
// CHECK-NEXT: Final Type Equivalence Classes: [dst, tmp, tmp2] [x, y, z]
32+
// CHECK-NEXT: INFER: MachineOperand $tmp2 -> GITypeOf<$dst>
33+
// CHECK-NEXT: INFER: MachineOperand $tmp -> GITypeOf<$dst>
34+
// CHECK-NEXT: Apply patterns for rule infer_complex_tempreg after inference:
35+
// CHECK-NEXT: (CodeGenInstructionPattern name:__infer_complex_tempreg_apply_0 G_BUILD_VECTOR operands:[<def>GITypeOf<$dst>:$tmp2, $x, $y])
36+
// CHECK-NEXT: (CodeGenInstructionPattern name:__infer_complex_tempreg_apply_1 G_FNEG operands:[<def>GITypeOf<$dst>:$tmp, GITypeOf<$dst>:$tmp2])
37+
// CHECK-NEXT: (CodeGenInstructionPattern name:__infer_complex_tempreg_apply_2 G_FNEG operands:[<def>$dst, GITypeOf<$dst>:$tmp])
38+
def infer_complex_tempreg: GICombineRule <
39+
(defs root:$dst),
40+
(match (G_MERGE_VALUES $dst, $x, $y, $z)),
41+
(apply (G_BUILD_VECTOR $tmp2, $x, $y),
42+
(G_FNEG $tmp, $tmp2),
43+
(G_FNEG $dst, $tmp))
44+
>;
45+
46+
// CHECK: Rule Operand Type Equivalence Classes for infer_variadic_outs:
47+
// CHECK-NEXT: Groups for __infer_variadic_outs_match_0: [x, y] [vec]
48+
// CHECK-NEXT: Groups for __infer_variadic_outs_match_1: [dst, x]
49+
// CHECK-NEXT: Groups for __infer_variadic_outs_apply_0: [tmp, y]
50+
// CHECK-NEXT: Groups for __infer_variadic_outs_apply_1:
51+
// CHECK-NEXT: Final Type Equivalence Classes: [tmp, dst, x, y] [vec]
52+
// CHECK-NEXT: INFER: MachineOperand $tmp -> GITypeOf<$dst>
53+
// CHECK-NEXT: Apply patterns for rule infer_variadic_outs after inference:
54+
// CHECK-NEXT: (CodeGenInstructionPattern name:__infer_variadic_outs_apply_0 G_FNEG operands:[<def>GITypeOf<$dst>:$tmp, $y])
55+
// CHECK-NEXT: (CodeGenInstructionPattern name:__infer_variadic_outs_apply_1 COPY operands:[<def>$dst, GITypeOf<$dst>:$tmp])
56+
def infer_variadic_outs: GICombineRule <
57+
(defs root:$dst),
58+
(match (G_UNMERGE_VALUES $x, $y, $vec),
59+
(G_FNEG $dst, $x)),
60+
(apply (G_FNEG $tmp, $y),
61+
(COPY $dst, $tmp))
62+
>;
63+
64+
def MyCombiner: GICombiner<"GenMyCombiner", [
65+
inference_mul_by_neg_one,
66+
infer_complex_tempreg,
67+
infer_variadic_outs
68+
]>;

llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ include "llvm/Target/GlobalISel/Combine.td"
88
def MyTargetISA : InstrInfo;
99
def MyTarget : Target { let InstructionSet = MyTargetISA; }
1010

11-
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: invalid operand name format 'unknown' in GITypeOf: expected '$' followed by an operand name
11+
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: cannot parse immediate '(anonymous_7029 0)': invalid operand name format 'unknown' in GITypeOf: expected '$' followed by an operand name
12+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_ANYEXT ?:$dst, (anonymous_
1213
def NoDollarSign : GICombineRule<
1314
(defs root:$dst),
1415
(match (G_ZEXT $dst, $src)),
@@ -47,7 +48,9 @@ def InferredUseInMatch : GICombineRule<
4748
(match (G_ZEXT $dst, $src)),
4849
(apply (G_ANYEXT $dst, GITypeOf<"$dst">:$src))>;
4950

50-
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: conflicting types for operand 'src': first seen with 'i32' in '__InferenceConflict_match_0, now seen with 'GITypeOf<$dst>' in '__InferenceConflict_apply_0'
51+
// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: conflicting types for operand 'src': 'i32' vs 'GITypeOf<$dst>'
52+
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: note: 'src' seen with type 'GITypeOf<$dst>' in '__InferenceConflict_apply_0'
53+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: note: 'src' seen with type 'i32' in '__InferenceConflict_match_0'
5154
def InferenceConflict : GICombineRule<
5255
(defs root:$dst),
5356
(match (G_ZEXT $dst, i32:$src)),

0 commit comments

Comments
 (0)