Skip to content

Commit

Permalink
[LangRef][IR] Add 3-way compare intrinsics llvm.scmp/llvm.ucmp (#83227)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
miguelraz authored Mar 18, 2024
1 parent a8bda0b commit 276847a
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
57 changes: 57 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14574,6 +14574,63 @@ The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
integer element type. The argument types must match each other, and the return
type must match the argument type.

.. _int_scmp:

'``llvm.scmp.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

This is an overloaded intrinsic. You can use ``@llvm.scmp`` on any
integer bit width or any vector of integer elements.

::

declare i2 @llvm.scmp.i2.i32(i32 %a, i32 %b)
declare <4 x i32> @llvm.scmp.v4i32.v4i32(<4 x i32> %a, <4 x i32> %b)

Overview:
"""""""""

Return ``-1`` if ``%a`` is signed less than ``%b``, ``0`` if they are equal, and
``1`` if ``%a`` is signed greater than ``%b``. Vector intrinsics operate on a per-element basis.

Arguments:
""""""""""

The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
integer element type. The argument types must match each other, and the return
type must be at least as wide as ``i2``, to hold the three possible return values.

.. _int_ucmp:

'``llvm.ucmp.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

This is an overloaded intrinsic. You can use ``@llvm.ucmp`` on any
integer bit width or any vector of integer elements.

::

declare i2 @llvm.ucmp.i2.i32(i32 %a, i32 %b)
declare <4 x i32> @llvm.ucmp.v4i32.v4i32(<4 x i32> %a, <4 x i32> %b)

Overview:
"""""""""

Return ``-1`` if ``%a`` is unsigned less than ``%b``, ``0`` if they are equal, and
``1`` if ``%a`` is unsigned greater than ``%b``. Vector intrinsics operate on a per-element basis.

Arguments:
""""""""""

The arguments (``%a`` and ``%b``) may be of any integer type or a vector with
integer element type. The argument types must match each other, and the return
type must be at least as wide as ``i2``, to hold the three possible return values.

.. _int_memcpy:

Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,12 @@ def int_umax : DefaultAttrsIntrinsic<
def int_umin : DefaultAttrsIntrinsic<
[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
def int_scmp : DefaultAttrsIntrinsic<
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
def int_ucmp : DefaultAttrsIntrinsic<
[llvm_anyint_ty], [llvm_anyint_ty, LLVMMatchType<1>],
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;

//===------------------------- Memory Use Markers -------------------------===//
//
Expand Down
23 changes: 23 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5265,6 +5265,29 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
}
break;
}
case Intrinsic::ucmp:
case Intrinsic::scmp: {
Type *SrcTy = Call.getOperand(0)->getType();
Type *DestTy = Call.getType();

Check(DestTy->getScalarSizeInBits() >= 2,
"result type must be at least 2 bits wide", Call);

bool IsDestTypeVector = DestTy->isVectorTy();
Check(SrcTy->isVectorTy() == IsDestTypeVector,
"ucmp/scmp argument and result types must both be either vector or "
"scalar types",
Call);
if (IsDestTypeVector) {
auto SrcVecLen = cast<VectorType>(SrcTy)->getElementCount();
auto DestVecLen = cast<VectorType>(DestTy)->getElementCount();
Check(SrcVecLen == DestVecLen,
"return type and arguments must have the same number of "
"elements",
Call);
}
break;
}
case Intrinsic::coro_id: {
auto *InfoArg = Call.getArgOperand(3)->stripPointerCasts();
if (isa<ConstantPointerNull>(InfoArg))
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/Verifier/intrinsic-cmp.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: not opt -S -passes=verify 2>&1 < %s | FileCheck %s

define void @matching_vector_lens(<4 x i32> %arg1, <4 x i32> %arg2) {
; CHECK: return type and arguments must have the same number of elements
%res = call <8 x i32> @llvm.scmp.v8i32.v4i32(<4 x i32> %arg1, <4 x i32> %arg2)
ret void
}

define void @result_len_is_at_least_2bits_wide(i32 %arg1, i32 %arg2) {
; CHECK: result type must be at least 2 bits wide
%res2 = call i1 @llvm.scmp.i1.i32(i32 %arg1, i32 %arg2)
ret void
}

define void @both_args_are_vecs_or_neither(<4 x i32> %arg1, i32 %arg2) {
; CHECK: ucmp/scmp argument and result types must both be either vector or scalar types
%res3 = call i2 @llvm.scmp.i2.v4i32(<4 x i32> %arg1, <4 x i32> %arg1)
; CHECK: ucmp/scmp argument and result types must both be either vector or scalar types
%res4 = call <4 x i32> @llvm.scmp.v4i32.i32(i32 %arg2, i32 %arg2)
ret void
}

0 comments on commit 276847a

Please sign in to comment.