Revert "[Matrix] Tighten LangRef definitions and Verifier checks."

This reverts commit f4d29d6e8c.

Hm, some build bot failures, reverting it while I investigate that.
This commit is contained in:
Sjoerd Meijer 2020-07-12 19:19:25 +01:00
parent f4d29d6e8c
commit 4ff7ed3310
3 changed files with 61 additions and 217 deletions

View File

@ -15524,7 +15524,6 @@ The argument to this intrinsic must be a vector of floating-point values.
Syntax:
"""""""
This is an overloaded intrinsic.
::
@ -15549,20 +15548,17 @@ Matrix Intrinsics
-----------------
Operations on matrixes requiring shape information (like number of rows/columns
or the memory layout) can be expressed using the matrix intrinsics. These
intrinsics require matrix dimensions to be passed as immediate arguments, and
matrixes are passed and returned as vectors. This means that for a ``R`` x
``C`` matrix, element ``i`` of column ``j`` is at index ``j * R + i`` in the
corresponding vector, with indices starting at 0. Currently column-major layout
is assumed. The intrinsics support both integer and floating point matrixes.
or the memory layout) can be expressed using the matrix intrinsics. Matrixes are
embedded in a flat vector and the intrinsics take the dimensions as arguments.
Currently column-major layout is assumed. The intrinsics support both integer
and floating point matrixes.
'``llvm.matrix.transpose.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
This is an overloaded intrinsic.
::
@ -15571,24 +15567,21 @@ This is an overloaded intrinsic.
Overview:
"""""""""
The '``llvm.matrix.transpose.*``' intrinsics treat %In as a <Rows> x <Cols> matrix
and return the transposed matrix in the result vector.
The '``llvm.matrix.transpose.*``' intrinsic treats %In as containing a matrix
with <Rows> rows and <Cols> columns and returns the transposed matrix embedded in
the result vector.
Arguments:
""""""""""
First argument %In is vector that corresponds to a <Rows> x <Cols> matrix.
Thus, arguments <Rows> and <Cols> correspond to the number of rows and columns,
respectively, and must be positive, constant integers. The returned vector must
have <Rows> * <Cols> elements, and have the same float or integer element type
as %In.
The <Rows> and <Cols> arguments must be constant integers. The vector argument
%In and the returned vector must have <Rows> * <Cols> elements.
'``llvm.matrix.multiply.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
This is an overloaded intrinsic.
::
@ -15597,19 +15590,18 @@ This is an overloaded intrinsic.
Overview:
"""""""""
The '``llvm.matrix.multiply.*``' intrinsics treat %A as a <OuterRows> x <Inner>
matrix, %B as a <Inner> x <OuterColumns> matrix, and multiplies them. The result
matrix is returned in the result vector.
The '``llvm.matrix.multiply.*``' intrinsic treats %A as a matrix with <OuterRows>
rows and <Inner> columns, %B as a matrix with <Inner> rows and <OuterColumns>
columns and multiplies them. The result matrix is returned embedded in the
result vector.
Arguments:
""""""""""
The first vector argument %A corresponds to a matrix with <OuterRows> * <Inner>
elements, and the second argument %B to a matrix with <Inner> * <OuterColumns>
elements. Arguments <OuterRows>, <Inner> and <OuterColumns> must be positive,
constant integers. The returned vector must have <OuterRows> * <OuterColumns>
elements. Vectors %A, %B, and the returned vector all have the same float or
integer element type.
The <OuterRows>, <Inner> and <OuterColumns> arguments must be constant
integers. The vector argument %A must have <OuterRows> * <Inner> elements, %B
must have <Inner> * <OuterColumns> elements and the returned vector must have
<OuterRows> * <OuterColumns> elements.
'``llvm.matrix.column.major.load.*``' Intrinsic
@ -15617,7 +15609,6 @@ integer element type.
Syntax:
"""""""
This is an overloaded intrinsic.
::
@ -15627,26 +15618,22 @@ This is an overloaded intrinsic.
Overview:
"""""""""
The '``llvm.matrix.column.major.load.*``' intrinsics load a <Rows> x <Cols>
matrix using a stride of %Stride to compute the start address of the different
columns. This allows for convenient loading of sub matrixes. If <IsVolatile>
is true, the intrinsic is considered a :ref:`volatile memory access
<volatile>`. The result matrix is returned in the result vector. If the %Ptr
argument is known to be aligned to some boundary, this can be specified as an
attribute on the argument.
The '``llvm.matrix.column.major.load.*``' intrinsic loads a matrix with <Rows>
rows and <Cols> columns, using a stride of %Stride between columns. For two
consecutive columns A and B, %Stride refers to the distance (the number of
elements) between the start of column A and the start of column B. The result
matrix is returned embedded in the result vector. This allows for convenient
loading of sub matrixes. If <IsVolatile> is true, the intrinsic is considered
a :ref:`volatile memory access <volatile>`.
If the %Ptr argument is known to be aligned to some boundary, this can be
specified as an attribute on the argument.
Arguments:
""""""""""
The first argument %Ptr is a pointer type to the returned vector type, and
correponds to the start address to load from. The second argument %Stride is a
postive, constant integer with %Stride ``>=`` <Rows>. %Stride is used to compute
the column memory addresses. I.e., for a column ``C``, its start memory
addresses is calculated with %Ptr + ``C`` * %Stride. The third Argument
<IsVolatile> is a boolean value. The fourth and fifth arguments, <Rows> and
<Cols>, correspond to the number of rows and columns, respectively, and must be
positive, constant integers. The returned vector must have <Rows> * <Cols>
elements.
The <IsVolatile>, <Rows> and <Cols> arguments must be constant integers. The
returned vector must have <Rows> * <Cols> elements. %Stride must be >= <Rows>.
The :ref:`align <attr_align>` parameter attribute can be provided
for the %Ptr arguments.
@ -15666,10 +15653,12 @@ Syntax:
Overview:
"""""""""
The '``llvm.matrix.column.major.store.*``' intrinsics store the <Rows> x <Cols>
matrix in %In to memory using a stride of %Stride between columns. If
<IsVolatile> is true, the intrinsic is considered a :ref:`volatile memory
access <volatile>`.
The '``llvm.matrix.column.major.store.*``' intrinsic stores the matrix with
<Rows> rows and <Cols> columns embedded in %In, using a stride of %Stride
between columns. For two consecutive columns A and B, %Stride refers to the
distance (the number of elements) between the start of column A and the start
of column B. If <IsVolatile> is true, the intrinsic is considered a
:ref:`volatile memory access <volatile>`.
If the %Ptr argument is known to be aligned to some boundary, this can be
specified as an attribute on the argument.
@ -15677,15 +15666,8 @@ specified as an attribute on the argument.
Arguments:
""""""""""
The first argument %In is a vector that corresponds to a <Rows> x <Cols> matrix
to be stored to memory. The second argument %Ptr is a pointer to the vector
type of %In, and is the start address of the matrix in memory. The third
argument %Stride is a positive, constant integer with %Stride ``>=`` <Rows>.
%Stride is used to compute the column memory addresses. I.e., for a column
``C``, its start memory addresses is calculated with %Ptr + ``C`` * %Stride.
The fourth argument <IsVolatile> is a boolean value. The arguments <Rows> and
<Cols> correspond to the number of rows and columns, respectively, and must be
positive, constant integers.
The <IsVolatile>, <Rows>, <Cols> arguments must be constant integers. The
vector argument %In must have <Rows> * <Cols> elements. %Stride must be >= <Rows>.
The :ref:`align <attr_align>` parameter attribute can be provided
for the %Ptr arguments.

View File

@ -5006,77 +5006,36 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
case Intrinsic::matrix_transpose:
case Intrinsic::matrix_column_major_load:
case Intrinsic::matrix_column_major_store: {
Function *IF = Call.getCalledFunction();
ConstantInt *Stride = nullptr;
ConstantInt *NumRows;
ConstantInt *NumColumns;
VectorType *ResultTy;
Type *Op0ElemTy = nullptr;
Type *Op1ElemTy = nullptr;
VectorType *TypeToCheck;
switch (ID) {
case Intrinsic::matrix_multiply:
NumRows = cast<ConstantInt>(Call.getArgOperand(2));
NumColumns = cast<ConstantInt>(Call.getArgOperand(4));
ResultTy = cast<VectorType>(Call.getType());
Op0ElemTy =
cast<VectorType>(Call.getArgOperand(0)->getType())->getElementType();
Op1ElemTy =
cast<VectorType>(Call.getArgOperand(1)->getType())->getElementType();
TypeToCheck = cast<VectorType>(Call.getType());
break;
case Intrinsic::matrix_transpose:
NumRows = cast<ConstantInt>(Call.getArgOperand(1));
NumColumns = cast<ConstantInt>(Call.getArgOperand(2));
ResultTy = cast<VectorType>(Call.getType());
Op0ElemTy =
cast<VectorType>(Call.getArgOperand(0)->getType())->getElementType();
TypeToCheck = cast<VectorType>(Call.getType());
break;
case Intrinsic::matrix_column_major_load: {
Stride = dyn_cast<ConstantInt>(Call.getArgOperand(1));
case Intrinsic::matrix_column_major_load:
NumRows = cast<ConstantInt>(Call.getArgOperand(3));
NumColumns = cast<ConstantInt>(Call.getArgOperand(4));
ResultTy = cast<VectorType>(Call.getType());
auto *VecTy = cast<VectorType>(
cast<PointerType>(Call.getArgOperand(0)->getType())->getElementType());
Op0ElemTy = VecTy->getElementType();
}
TypeToCheck = cast<VectorType>(Call.getType());
break;
case Intrinsic::matrix_column_major_store: {
Stride = dyn_cast<ConstantInt>(Call.getArgOperand(2));
case Intrinsic::matrix_column_major_store:
NumRows = cast<ConstantInt>(Call.getArgOperand(4));
NumColumns = cast<ConstantInt>(Call.getArgOperand(5));
ResultTy = cast<VectorType>(Call.getArgOperand(0)->getType());
Op0ElemTy =
cast<VectorType>(Call.getArgOperand(0)->getType())->getElementType();
auto *VecTy = cast<VectorType>(
cast<PointerType>(Call.getArgOperand(1)->getType())->getElementType());
Op1ElemTy = VecTy->getElementType();
}
TypeToCheck = cast<VectorType>(Call.getArgOperand(0)->getType());
break;
default:
llvm_unreachable("unexpected intrinsic");
}
Assert(ResultTy->getElementType()->isIntegerTy() ||
ResultTy->getElementType()->isFloatingPointTy(),
"Result type must be an integer or floating-point type!", IF);
Assert(ResultTy->getElementType() == Op0ElemTy,
"Vector element type mismatch of the result and first operand "
"vector!", IF);
if (Op1ElemTy)
Assert(ResultTy->getElementType() == Op1ElemTy,
"Vector element type mismatch of the result and second operand "
"vector!", IF);
Assert(ResultTy->getNumElements() ==
Assert(TypeToCheck->getNumElements() ==
NumRows->getZExtValue() * NumColumns->getZExtValue(),
"Result of a matrix operation does not fit in the returned vector!");
if (Stride)
Assert(Stride->getZExtValue() >= NumRows->getZExtValue(),
"Stride must be greater or equal than the number of rows!", IF);
"result of a matrix operation does not fit in the returned vector");
break;
}
};

View File

@ -3,9 +3,9 @@
declare <4 x float> @llvm.matrix.transpose.v4f32(<4 x float>, i32, i32)
define <4 x float> @transpose(<4 x float> %m, i32 %arg) {
; CHECK: assembly parsed, but does not verify as correct!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg
; CHECK-NEXT: %result.3 = call <4 x float> @llvm.matrix.transpose.v4f32(<4 x float> %result.2, i32 %arg, i32 2)
@ -22,9 +22,9 @@ define <4 x float> @transpose(<4 x float> %m, i32 %arg) {
declare <4 x float> @llvm.matrix.multiply.v4f32.v4f32.v4f32(<4 x float>, <4 x float>, i32, i32, i32)
define <4 x float> @multiply(<4 x float> %m, i32 %arg) {
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg
; CHECK-NEXT: %result.3 = call <4 x float> @llvm.matrix.multiply.v4f32.v4f32.v4f32(<4 x float> %result.2, <4 x float> %m, i32 %arg, i32 2, i32 1)
@ -38,9 +38,9 @@ define <4 x float> @multiply(<4 x float> %m, i32 %arg) {
declare <4 x float> @llvm.matrix.column.major.load.v4f32.p0v4f32(<4 x float>*, i64, i1, i32, i32)
declare <6 x float> @llvm.matrix.column.major.load.v6f32.p0v6f32(<6 x float>*, i64, i1, i32, i32)
define <4 x float> @column.major_load(<4 x float>* %m, <6 x float>* %n, i32 %arg) {
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: immarg operand has non-immediate parameter
; CHECK-NEXT: i32 %arg
; CHECK-NEXT: %result.3 = call <6 x float> @llvm.matrix.column.major.load.v6f32.p0v6f32(<6 x float>* %n, i64 2, i1 true, i32 3, i32 %arg)
@ -54,110 +54,13 @@ define <4 x float> @column.major_load(<4 x float>* %m, <6 x float>* %n, i32 %arg
declare void @llvm.matrix.column.major.store.v4f32.p0v4f32(<4 x float>, <4 x float>*, i64, i1, i32, i32)
declare void @llvm.matrix.column.major.store.v6f32.p0v6f32(<6 x float>, <6 x float>*, i64, i1, i32, i32)
define void @column.major_store(<4 x float>* %m, <6 x float>* %n, i64 %arg) {
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: Result of a matrix operation does not fit in the returned vector!
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
; CHECK-NEXT: result of a matrix operation does not fit in the returned vector
call void @llvm.matrix.column.major.store.v4f32.p0v4f32(<4 x float> zeroinitializer, <4 x float>* %m, i64 0, i1 false, i32 0, i32 0)
call void @llvm.matrix.column.major.store.v4f32.p0v4f32(<4 x float> zeroinitializer, <4 x float>* %m, i64 2, i1 false, i32 1, i32 2)
call void @llvm.matrix.column.major.store.v6f32.p0v6f32(<6 x float> zeroinitializer, <6 x float>* %n, i64 2, i1 false, i32 3, i32 3)
call void @llvm.matrix.column.major.store.v6f32.p0v6f32(<6 x float> zeroinitializer, <6 x float>* %n, i64 %arg, i1 false, i32 3, i32 3)
ret void
}
declare <4 x float> @llvm.matrix.transpose.v4f32.v4i32(<4 x i32>, i32, i32)
declare <4 x i32> @llvm.matrix.transpose.v4i32.v4f32(<4 x float>, i32, i32)
define <4 x float> @transpose_mixed_types(<4 x float> %fvec, <4 x i32> %ivec, i32 %arg) {
;
; CHECK-NEXT: Intrinsic has incorrect argument type!
; CHECK-NEXT: <4 x float> (<4 x i32>, i32, i32)* @llvm.matrix.transpose.v4f32.v4i32
; CHECK-NEXT: Intrinsic has incorrect argument type!
; CHECK-NEXT: <4 x i32> (<4 x float>, i32, i32)* @llvm.matrix.transpose.v4i32.v4f32
;
%result.0 = call <4 x float> @llvm.matrix.transpose.v4f32.v4i32(<4 x i32> %ivec, i32 0, i32 0)
%result.1 = call <4 x i32> @llvm.matrix.transpose.v4i32.v4f32(<4 x float> %result.0, i32 3, i32 2)
ret <4 x float> %result.0
}
declare <4 x i32> @llvm.matrix.multiply.v4i32.v4f32.v4f32(<4 x float>, <4 x float>, i32, i32, i32)
declare <4 x float> @llvm.matrix.multiply.v4f32.v4i32.v4f32(<4 x i32>, <4 x float>, i32, i32, i32)
declare <4 x float> @llvm.matrix.multiply.v4f32.v4f32.v4i32(<4 x float>, <4 x i32>, i32, i32, i32)
declare <4 x float> @llvm.matrix.multiply.v4f32.v4i32.v4i32(<4 x i32>, <4 x i32>, i32, i32, i32)
define <4 x float> @multiply_mixed_types(<4 x i32> %ivec, <4 x float> %fvec, i32 %arg) {
;
; CHECK-NEXT: Vector element type mismatch of the result and first operand vector!
; CHECK-NEXT: <4 x i32> (<4 x float>, <4 x float>, i32, i32, i32)* @llvm.matrix.multiply.v4i32.v4f32.v4f32
; CHECK-NEXT: Vector element type mismatch of the result and first operand vector!
; CHECK-NEXT: <4 x float> (<4 x i32>, <4 x float>, i32, i32, i32)* @llvm.matrix.multiply.v4f32.v4i32.v4f32
; CHECK-NEXT: Vector element type mismatch of the result and second operand vector!
; CHECK-NEXT: <4 x float> (<4 x float>, <4 x i32>, i32, i32, i32)* @llvm.matrix.multiply.v4f32.v4f32.v4i32
; CHECK-NEXT: Vector element type mismatch of the result and first operand vector!
; CHECK-NEXT: <4 x float> (<4 x i32>, <4 x i32>, i32, i32, i32)* @llvm.matrix.multiply.v4f32.v4i32.v4i32
;
%result.0 = call <4 x i32> @llvm.matrix.multiply.v4i32.v4f32.v4f32(<4 x float> %fvec, <4 x float> %fvec, i32 2, i32 2, i32 2)
%result.1 = call <4 x float> @llvm.matrix.multiply.v4f32.v4i32.v4f32(<4 x i32> %result.0, <4 x float> %fvec, i32 2, i32 2, i32 2)
%result.2 = call <4 x float> @llvm.matrix.multiply.v4f32.v4f32.v4i32(<4 x float> %fvec, <4 x i32> %ivec, i32 2, i32 2, i32 2)
%result.3 = call <4 x float> @llvm.matrix.multiply.v4f32.v4i32.v4i32(<4 x i32> %ivec, <4 x i32> %ivec, i32 2, i32 2, i32 2)
ret <4 x float> %result.3
}
declare <4 x float> @llvm.matrix.column.major.load.v4f32.p0v4i32(<4 x i32>*, i64, i1, i32, i32)
declare <4 x i32> @llvm.matrix.column.major.load.v4i32.p0v4f32(<4 x float>*, i64, i1, i32, i32)
define <4 x float> @column.major_load_mixed_types(<4 x i32>* %m, <4 x float>* %n, i32 %arg) {
;
; CHECK-NEXT: Vector element type mismatch of the result and first operand vector!
; CHECK-NEXT: <4 x float> (<4 x i32>*, i64, i1, i32, i32)* @llvm.matrix.column.major.load.v4f32.p0v4i32
; CHECK-NEXT: Vector element type mismatch of the result and first operand vector!
; CHECK-NEXT: <4 x i32> (<4 x float>*, i64, i1, i32, i32)* @llvm.matrix.column.major.load.v4i32.p0v4f32
;
%result.0 = call <4 x float> @llvm.matrix.column.major.load.v4f32.p0v4i32(<4 x i32>* %m, i64 2, i1 false, i32 2, i32 2)
%result.1 = call <4 x i32> @llvm.matrix.column.major.load.v4i32.p0v4f32(<4 x float>* %n, i64 2, i1 false, i32 2, i32 2)
ret <4 x float> %result.0
}
declare void @llvm.matrix.column.major.store.v4i32.p0v4f32(<4 x i32>, <4 x float>*, i64, i1, i32, i32)
declare void @llvm.matrix.column.major.store.v4f32.p0v4i32(<4 x float>, <4 x i32>*, i64, i1, i32, i32)
define void @column.major_store_mixed_types(<4 x float>* %m, <4 x i32>* %n, i64 %arg) {
;
; CHECK-NEXT: Vector element type mismatch of the result and second operand vector!
; CHECK-NEXT: void (<4 x i32>, <4 x float>*, i64, i1, i32, i32)* @llvm.matrix.column.major.store.v4i32.p0v4f32
; CHECK-NEXT: Vector element type mismatch of the result and second operand vector!
; CHECK-NEXT: void (<4 x float>, <4 x i32>*, i64, i1, i32, i32)* @llvm.matrix.column.major.store.v4f32.p0v4i32
;
call void @llvm.matrix.column.major.store.v4i32.p0v4f32(<4 x i32> zeroinitializer, <4 x float>* %m, i64 2, i1 false, i32 2, i32 2)
call void @llvm.matrix.column.major.store.v4f32.p0v4i32(<4 x float> zeroinitializer, <4 x i32>* %n, i64 2, i1 false, i32 2, i32 2)
ret void
}
declare void @llvm.matrix.column.major.store.v4f32p0.p0v4f32(<4 x float*>, <4 x float>*, i64, i1, i32, i32)
define void @column.major_store_non_int_float_type(<4 x float>* %m, <4 x float>* %n, i64 %arg) {
;
; CHECK-NEXT: Result type must be an integer or floating-point type!
; CHECK-NEXT: void (<4 x float*>, <4 x float>*, i64, i1, i32, i32)* @llvm.matrix.column.major.store.v4p0f32.p0v4f32
;
call void @llvm.matrix.column.major.store.v4f32p0.p0v4f32(<4 x float*> zeroinitializer, <4 x float>* %n, i64 2, i1 false, i32 2, i32 2)
ret void
}
define <4 x float> @column.major_load_stride_too_small(<4 x float>* %m, i32 %arg) {
;
; CHECK-NEXT: Stride must be greater or equal than the number of rows!
; CHECK-NEXT: <4 x float> (<4 x float>*, i64, i1, i32, i32)* @llvm.matrix.column.major.load.v4f32.p0v4f32
;
%result.1 = call <4 x float> @llvm.matrix.column.major.load.v4f32.p0v4f32(<4 x float>* %m, i64 1, i1 false, i32 2, i32 2)
ret <4 x float> %result.1
}
define void @column.major_store_stride_too_small(<4 x float>* %m, i64 %arg) {
;
; CHECK-NEXT: Stride must be greater or equal than the number of rows!
; CHECK-NEXT: void (<4 x float>, <4 x float>*, i64, i1, i32, i32)* @llvm.matrix.column.major.store.v4f32.p0v4f32
;
call void @llvm.matrix.column.major.store.v4f32.p0v4f32(<4 x float> zeroinitializer, <4 x float>* %m, i64 1, i1 false, i32 2, i32 2)
ret void
}