Skip to content

Commit 311d849

Browse files
Thorsten Schüttyuxuanchen1997
Thorsten Schütt
authored andcommitted
[GlobalIsel] Add G_SCMP and G_UCMP instructions (#98894)
#83227
1 parent d2814a6 commit 311d849

File tree

10 files changed

+163
-16
lines changed

10 files changed

+163
-16
lines changed

llvm/docs/GlobalISel/GenericOpcode.rst

+20
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,26 @@ G_ICMP
348348
Perform integer comparison producing non-zero (true) or zero (false). It's
349349
target specific whether a true value is 1, ~0U, or some other non-zero value.
350350

351+
G_SCMP
352+
^^^^^^
353+
354+
Perform signed 3-way integer comparison producing -1 (smaller), 0 (equal), or 1 (larger).
355+
356+
.. code-block:: none
357+
358+
%5:_(s32) = G_SCMP %6, %2
359+
360+
361+
G_UCMP
362+
^^^^^^
363+
364+
Perform unsigned 3-way integer comparison producing -1 (smaller), 0 (equal), or 1 (larger).
365+
366+
.. code-block:: none
367+
368+
%7:_(s32) = G_UCMP %2, %6
369+
370+
351371
G_SELECT
352372
^^^^^^^^
353373

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

+28
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,34 @@ class MachineIRBuilder {
12731273
const SrcOp &Op0, const SrcOp &Op1,
12741274
std::optional<unsigned> Flags = std::nullopt);
12751275

1276+
/// Build and insert a \p Res = G_SCMP \p Op0, \p Op1
1277+
///
1278+
/// \pre setBasicBlock or setMI must have been called.
1279+
1280+
/// \pre \p Res must be a generic virtual register with scalar or
1281+
/// vector type. Typically this starts as s2 or <N x s2>.
1282+
/// \pre \p Op0 and Op1 must be generic virtual registers with the
1283+
/// same number of elements as \p Res. If \p Res is a scalar,
1284+
/// \p Op0 must be a scalar.
1285+
///
1286+
/// \return a MachineInstrBuilder for the newly created instruction.
1287+
MachineInstrBuilder buildSCmp(const DstOp &Res, const SrcOp &Op0,
1288+
const SrcOp &Op1);
1289+
1290+
/// Build and insert a \p Res = G_UCMP \p Op0, \p Op1
1291+
///
1292+
/// \pre setBasicBlock or setMI must have been called.
1293+
1294+
/// \pre \p Res must be a generic virtual register with scalar or
1295+
/// vector type. Typically this starts as s2 or <N x s2>.
1296+
/// \pre \p Op0 and Op1 must be generic virtual registers with the
1297+
/// same number of elements as \p Res. If \p Res is a scalar,
1298+
/// \p Op0 must be a scalar.
1299+
///
1300+
/// \return a MachineInstrBuilder for the newly created instruction.
1301+
MachineInstrBuilder buildUCmp(const DstOp &Res, const SrcOp &Op0,
1302+
const SrcOp &Op1);
1303+
12761304
/// Build and insert a \p Res = G_IS_FPCLASS \p Src, \p Mask
12771305
MachineInstrBuilder buildIsFPClass(const DstOp &Res, const SrcOp &Src,
12781306
unsigned Mask) {

llvm/include/llvm/Support/TargetOpcodes.def

+6
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ HANDLE_TARGET_OPCODE(G_ICMP)
503503
/// Generic floating-point comparison, also applicable to vectors.
504504
HANDLE_TARGET_OPCODE(G_FCMP)
505505

506+
/// Generic signed 3-way comparison.
507+
HANDLE_TARGET_OPCODE(G_SCMP)
508+
509+
/// Generic unsigned 3-way comparison.
510+
HANDLE_TARGET_OPCODE(G_UCMP)
511+
506512
/// Generic select.
507513
HANDLE_TARGET_OPCODE(G_SELECT)
508514

llvm/include/llvm/Target/GenericOpcodes.td

+14
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,20 @@ def G_FCMP : GenericInstruction {
430430
let hasSideEffects = false;
431431
}
432432

433+
// Generic signed three-way comparison.
434+
def G_SCMP : GenericInstruction {
435+
let OutOperandList = (outs type0:$dst);
436+
let InOperandList = (ins type1:$src1, type1:$src2);
437+
let hasSideEffects = false;
438+
}
439+
440+
// Generic unsigned three-way comparison.
441+
def G_UCMP : GenericInstruction {
442+
let OutOperandList = (outs type0:$dst);
443+
let InOperandList = (ins type1:$src1, type1:$src2);
444+
let hasSideEffects = false;
445+
}
446+
433447
// Generic select
434448
def G_SELECT : GenericInstruction {
435449
let OutOperandList = (outs type0:$dst);

llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,18 @@ MachineInstrBuilder MachineIRBuilder::buildFCmp(CmpInst::Predicate Pred,
911911
return buildInstr(TargetOpcode::G_FCMP, Res, {Pred, Op0, Op1}, Flags);
912912
}
913913

914+
MachineInstrBuilder MachineIRBuilder::buildSCmp(const DstOp &Res,
915+
const SrcOp &Op0,
916+
const SrcOp &Op1) {
917+
return buildInstr(TargetOpcode::G_SCMP, Res, {Op0, Op1});
918+
}
919+
920+
MachineInstrBuilder MachineIRBuilder::buildUCmp(const DstOp &Res,
921+
const SrcOp &Op0,
922+
const SrcOp &Op1) {
923+
return buildInstr(TargetOpcode::G_UCMP, Res, {Op0, Op1});
924+
}
925+
914926
MachineInstrBuilder
915927
MachineIRBuilder::buildSelect(const DstOp &Res, const SrcOp &Tst,
916928
const SrcOp &Op0, const SrcOp &Op1,

llvm/lib/CodeGen/MachineVerifier.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,36 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
15441544

15451545
break;
15461546
}
1547+
case TargetOpcode::G_SCMP:
1548+
case TargetOpcode::G_UCMP: {
1549+
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
1550+
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
1551+
LLT SrcTy2 = MRI->getType(MI->getOperand(2).getReg());
1552+
1553+
if (SrcTy.isPointerOrPointerVector() || SrcTy2.isPointerOrPointerVector()) {
1554+
report("Generic scmp/ucmp does not support pointers as operands", MI);
1555+
break;
1556+
}
1557+
1558+
if (DstTy.isPointerOrPointerVector()) {
1559+
report("Generic scmp/ucmp does not support pointers as a result", MI);
1560+
break;
1561+
}
1562+
1563+
if ((DstTy.isVector() != SrcTy.isVector()) ||
1564+
(DstTy.isVector() &&
1565+
DstTy.getElementCount() != SrcTy.getElementCount())) {
1566+
report("Generic vector scmp/ucmp must preserve number of lanes", MI);
1567+
break;
1568+
}
1569+
1570+
if (SrcTy != SrcTy2) {
1571+
report("Generic scmp/ucmp must have same input types", MI);
1572+
break;
1573+
}
1574+
1575+
break;
1576+
}
15471577
case TargetOpcode::G_EXTRACT: {
15481578
const MachineOperand &SrcOp = MI->getOperand(1);
15491579
if (!SrcOp.isReg()) {

llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir

+6
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,12 @@
351351
# DEBUG-NEXT: G_FCMP (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
352352
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
353353
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
354+
# DEBUG-NEXT: G_SCMP (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
355+
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
356+
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
357+
# DEBUG-NEXT: G_UCMP (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
358+
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
359+
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
354360
# DEBUG-NEXT: G_SELECT (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
355361
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
356362
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# RUN: not --crash llc -verify-machineinstrs -run-pass none -mtriple=arm64 -o /dev/null %s 2>&1 | FileCheck %s
2+
# REQUIRES: aarch64-registered-target
3+
4+
---
5+
name: test_uscmp
6+
body: |
7+
bb.0:
8+
9+
%2:_(p0) = G_IMPLICIT_DEF
10+
%3:_(p0) = G_IMPLICIT_DEF
11+
; CHECK: Generic scmp/ucmp does not support pointers as operands
12+
%4:_(s1) = G_SCMP %2, %3
13+
14+
%12:_(s64) = G_IMPLICIT_DEF
15+
%13:_(s64) = G_IMPLICIT_DEF
16+
; CHECK: Generic scmp/ucmp does not support pointers as a result
17+
%14:_(p0) = G_SCMP %12, %13
18+
19+
%23:_(<2 x s32>) = G_IMPLICIT_DEF
20+
%24:_(<2 x s32>) = G_IMPLICIT_DEF
21+
; CHECK: Generic vector scmp/ucmp must preserve number of lanes
22+
%5:_(s1) = G_UCMP %23, %24
23+
24+
%15:_(s32) = G_CONSTANT i32 0
25+
%16:_(s64) = G_CONSTANT i64 2
26+
; CHECK: Generic scmp/ucmp must have same input types
27+
%17:_(s1) = G_SCMP %15, %16
28+
29+
30+
31+
...

llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td

+15-15
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
8686
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
8787
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
8888
// CHECK-NEXT: GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2([[#LOWER:]]), GIMT_Encode2([[#UPPER:]]), /*)*//*default:*//*Label 4*/ GIMT_Encode4([[#DEFAULT:]]),
89-
// CHECK-NEXT: /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(410), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
90-
// CHECK-NEXT: /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(428), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
91-
// CHECK-NEXT: /*TargetOpcode::G_FNEG*//*Label 2*/ GIMT_Encode4(440), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
92-
// CHECK-NEXT: /*TargetOpcode::G_FABS*//*Label 3*/ GIMT_Encode4(452),
89+
// CHECK-NEXT: /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(418), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
90+
// CHECK-NEXT: /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(436), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
91+
// CHECK-NEXT: /*TargetOpcode::G_FNEG*//*Label 2*/ GIMT_Encode4(448), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
92+
// CHECK-NEXT: /*TargetOpcode::G_FABS*//*Label 3*/ GIMT_Encode4(460),
9393
// CHECK-NEXT: // Label 0: @[[#%u, mul(UPPER-LOWER, 4) + 10]]
94-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(427), // Rule ID 2 //
94+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(435), // Rule ID 2 //
9595
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
9696
// CHECK-NEXT: // MIs[0] x
9797
// CHECK-NEXT: // No operand predicates
@@ -101,40 +101,40 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
101101
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
102102
// CHECK-NEXT: // Combiner Rule #2: TwoMatchNoApply
103103
// CHECK-NEXT: GIR_EraseRootFromParent_Done,
104-
// CHECK-NEXT: // Label 5: @427
104+
// CHECK-NEXT: // Label 5: @435
105105
// CHECK-NEXT: GIM_Reject,
106-
// CHECK-NEXT: // Label 1: @428
107-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(439), // Rule ID 3 //
106+
// CHECK-NEXT: // Label 1: @436
107+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(447), // Rule ID 3 //
108108
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
109109
// CHECK-NEXT: // MIs[0] a
110110
// CHECK-NEXT: // No operand predicates
111111
// CHECK-NEXT: // MIs[0] y
112112
// CHECK-NEXT: // No operand predicates
113113
// CHECK-NEXT: // Combiner Rule #3: NoMatchTwoApply
114114
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
115-
// CHECK-NEXT: // Label 6: @439
115+
// CHECK-NEXT: // Label 6: @447
116116
// CHECK-NEXT: GIM_Reject,
117-
// CHECK-NEXT: // Label 2: @440
118-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(451), // Rule ID 1 //
117+
// CHECK-NEXT: // Label 2: @448
118+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(459), // Rule ID 1 //
119119
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
120120
// CHECK-NEXT: // MIs[0] a
121121
// CHECK-NEXT: // No operand predicates
122122
// CHECK-NEXT: // MIs[0] b
123123
// CHECK-NEXT: // No operand predicates
124124
// CHECK-NEXT: // Combiner Rule #1: TwoMatchTwoApply
125125
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
126-
// CHECK-NEXT: // Label 7: @451
126+
// CHECK-NEXT: // Label 7: @459
127127
// CHECK-NEXT: GIM_Reject,
128-
// CHECK-NEXT: // Label 3: @452
129-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(463), // Rule ID 0 //
128+
// CHECK-NEXT: // Label 3: @460
129+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(471), // Rule ID 0 //
130130
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
131131
// CHECK-NEXT: // MIs[0] a
132132
// CHECK-NEXT: // No operand predicates
133133
// CHECK-NEXT: // MIs[0] b
134134
// CHECK-NEXT: // No operand predicates
135135
// CHECK-NEXT: // Combiner Rule #0: OneMatchOneApply
136136
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
137-
// CHECK-NEXT: // Label 8: @463
137+
// CHECK-NEXT: // Label 8: @471
138138
// CHECK-NEXT: GIM_Reject,
139139
// CHECK-NEXT: // Label 4: @[[#%u, DEFAULT]]
140140
// CHECK-NEXT: GIM_Reject,

llvm/test/TableGen/GlobalISelEmitter.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3),
513513
// R00O-NEXT: GIM_Reject,
514514
// R00O: // Label [[DEFAULT_NUM]]: @[[DEFAULT]]
515515
// R00O-NEXT: GIM_Reject,
516-
// R00O-NEXT: }; // Size: 1808 bytes
516+
// R00O-NEXT: }; // Size: 1816 bytes
517517

518518
def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
519519
[(set GPR32:$dst,

0 commit comments

Comments
 (0)