Skip to content

Commit 276847a

Browse files
authored
[LangRef][IR] Add 3-way compare intrinsics llvm.scmp/llvm.ucmp (llvm#83227)
This PR adds the `[us]cmp` intrinsics to the LangRef, `Intrinsics.td` and some tests to the IRVerifier. RFC: https://discourse.llvm.org/t/rfc-add-3-way-comparison-intrinsics/76685
1 parent a8bda0b commit 276847a

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

llvm/docs/LangRef.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14574,6 +14574,63 @@ The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
1457414574
integer element type. The argument types must match each other, and the return
1457514575
type must match the argument type.
1457614576

14577+
.. _int_scmp:
14578+
14579+
'``llvm.scmp.*``' Intrinsic
14580+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
14581+
14582+
Syntax:
14583+
"""""""
14584+
14585+
This is an overloaded intrinsic. You can use ``@llvm.scmp`` on any
14586+
integer bit width or any vector of integer elements.
14587+
14588+
::
14589+
14590+
declare i2 @llvm.scmp.i2.i32(i32 %a, i32 %b)
14591+
declare <4 x i32> @llvm.scmp.v4i32.v4i32(<4 x i32> %a, <4 x i32> %b)
14592+
14593+
Overview:
14594+
"""""""""
14595+
14596+
Return ``-1`` if ``%a`` is signed less than ``%b``, ``0`` if they are equal, and
14597+
``1`` if ``%a`` is signed greater than ``%b``. Vector intrinsics operate on a per-element basis.
14598+
14599+
Arguments:
14600+
""""""""""
14601+
14602+
The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
14603+
integer element type. The argument types must match each other, and the return
14604+
type must be at least as wide as ``i2``, to hold the three possible return values.
14605+
14606+
.. _int_ucmp:
14607+
14608+
'``llvm.ucmp.*``' Intrinsic
14609+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
14610+
14611+
Syntax:
14612+
"""""""
14613+
14614+
This is an overloaded intrinsic. You can use ``@llvm.ucmp`` on any
14615+
integer bit width or any vector of integer elements.
14616+
14617+
::
14618+
14619+
declare i2 @llvm.ucmp.i2.i32(i32 %a, i32 %b)
14620+
declare <4 x i32> @llvm.ucmp.v4i32.v4i32(<4 x i32> %a, <4 x i32> %b)
14621+
14622+
Overview:
14623+
"""""""""
14624+
14625+
Return ``-1`` if ``%a`` is unsigned less than ``%b``, ``0`` if they are equal, and
14626+
``1`` if ``%a`` is unsigned greater than ``%b``. Vector intrinsics operate on a per-element basis.
14627+
14628+
Arguments:
14629+
""""""""""
14630+
14631+
The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
14632+
integer element type. The argument types must match each other, and the return
14633+
type must be at least as wide as ``i2``, to hold the three possible return values.
1457714634

1457814635
.. _int_memcpy:
1457914636

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,12 @@ def int_umax : DefaultAttrsIntrinsic<
15281528
def int_umin : DefaultAttrsIntrinsic<
15291529
[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>],
15301530
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
1531+
def int_scmp : DefaultAttrsIntrinsic<
1532+
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
1533+
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
1534+
def int_ucmp : DefaultAttrsIntrinsic<
1535+
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
1536+
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
15311537

15321538
//===------------------------- Memory Use Markers -------------------------===//
15331539
//

llvm/lib/IR/Verifier.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5265,6 +5265,29 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
52655265
}
52665266
break;
52675267
}
5268+
case Intrinsic::ucmp:
5269+
case Intrinsic::scmp: {
5270+
Type *SrcTy = Call.getOperand(0)->getType();
5271+
Type *DestTy = Call.getType();
5272+
5273+
Check(DestTy->getScalarSizeInBits() >= 2,
5274+
"result type must be at least 2 bits wide", Call);
5275+
5276+
bool IsDestTypeVector = DestTy->isVectorTy();
5277+
Check(SrcTy->isVectorTy() == IsDestTypeVector,
5278+
"ucmp/scmp argument and result types must both be either vector or "
5279+
"scalar types",
5280+
Call);
5281+
if (IsDestTypeVector) {
5282+
auto SrcVecLen = cast<VectorType>(SrcTy)->getElementCount();
5283+
auto DestVecLen = cast<VectorType>(DestTy)->getElementCount();
5284+
Check(SrcVecLen == DestVecLen,
5285+
"return type and arguments must have the same number of "
5286+
"elements",
5287+
Call);
5288+
}
5289+
break;
5290+
}
52685291
case Intrinsic::coro_id: {
52695292
auto *InfoArg = Call.getArgOperand(3)->stripPointerCasts();
52705293
if (isa<ConstantPointerNull>(InfoArg))

llvm/test/Verifier/intrinsic-cmp.ll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: not opt -S -passes=verify 2>&1 < %s | FileCheck %s
2+
3+
define void @matching_vector_lens(<4 x i32> %arg1, <4 x i32> %arg2) {
4+
; CHECK: return type and arguments must have the same number of elements
5+
%res = call <8 x i32> @llvm.scmp.v8i32.v4i32(<4 x i32> %arg1, <4 x i32> %arg2)
6+
ret void
7+
}
8+
9+
define void @result_len_is_at_least_2bits_wide(i32 %arg1, i32 %arg2) {
10+
; CHECK: result type must be at least 2 bits wide
11+
%res2 = call i1 @llvm.scmp.i1.i32(i32 %arg1, i32 %arg2)
12+
ret void
13+
}
14+
15+
define void @both_args_are_vecs_or_neither(<4 x i32> %arg1, i32 %arg2) {
16+
; CHECK: ucmp/scmp argument and result types must both be either vector or scalar types
17+
%res3 = call i2 @llvm.scmp.i2.v4i32(<4 x i32> %arg1, <4 x i32> %arg1)
18+
; CHECK: ucmp/scmp argument and result types must both be either vector or scalar types
19+
%res4 = call <4 x i32> @llvm.scmp.v4i32.i32(i32 %arg2, i32 %arg2)
20+
ret void
21+
}
22+

0 commit comments

Comments
 (0)