[mlir][arith] Add nneg to extui and uitofp. (#183165)

This patchset adds missing the missing flag nneg (non-negative) to extui
and uitofp which denotes that the operand is known to be non-negative.
Semantics for this flag mirrors LLVM semantics.

[From:](https://discourse.llvm.org/t/rfc-add-zext-nneg-flag/73914) 

> If the nneg flag is set, and the zext argument is negative, the result
is a poison value.
> A corollary is that replacing a zext nneg with sext is a refinement.


[and](https://discourse.llvm.org/t/rfc-support-nneg-flag-with-uitofp/77988):

> uitofp nneg iN %x to fM returns poison if %x is negative
> A corollary is that uitofp nneg iN %x to fM is equivilent to sitofp iN
%x to fM.

* Adds ArithNonNegFlagInterface
* Adds AttrConvertNonNegToLLVM 
* Updates definitions of arith.extui and arith.uitofp to declare
ArithNonNegFlagInterface
* Updates canonicalization patterns to propagate nneg where applicable
* Adds roundtrip, lowering, and canonicalization tests.

Assisted-by: claude
This commit is contained in:
Erick Ochoa Lopez 2026-02-25 13:54:44 -05:00 committed by GitHub
parent 09d7b890e0
commit 81afd93a51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 315 additions and 17 deletions

View File

@ -111,6 +111,29 @@ private:
DictionaryAttr propertiesAttr;
};
// Attribute converter that populates a NamedAttrList by removing the nonNeg
// attribute from the source operation attributes, and setting it as a property
// on the target LLVM operation.
template <typename SourceOp, typename TargetOp>
class AttrConvertNonNegToLLVM {
public:
AttrConvertNonNegToLLVM(SourceOp srcOp) {
convertedAttr = NamedAttrList{srcOp->getAttrs()};
if (!convertedAttr.erase("nonNeg"))
return;
MLIRContext *ctx = srcOp.getOperation()->getContext();
Builder b(ctx);
NamedAttribute attr{"nonNeg", b.getUnitAttr()};
propertiesAttr = b.getDictionaryAttr(ArrayRef(attr));
}
ArrayRef<NamedAttribute> getAttrs() const { return convertedAttr.getAttrs(); }
Attribute getPropAttr() const { return propertiesAttr; }
private:
NamedAttrList convertedAttr;
DictionaryAttr propertiesAttr;
};
template <typename SourceOp, typename TargetOp>
class AttrConverterConstrainedFPToLLVM {
static_assert(TargetOp::template hasTrait<

View File

@ -1172,7 +1172,8 @@ def Arith_RemFOp : Arith_FloatBinaryOp<"remf"> {
// ExtUIOp
//===----------------------------------------------------------------------===//
def Arith_ExtUIOp : Arith_IToICastOp<"extui"> {
def Arith_ExtUIOp :
Arith_IToICastOp<"extui", [DeclareOpInterfaceMethods<ArithNonNegFlagInterface>]> {
let summary = "integer zero extension operation";
let description = [{
The integer zero extension operation takes an integer input of
@ -1180,6 +1181,11 @@ def Arith_ExtUIOp : Arith_IToICastOp<"extui"> {
bit-width must be larger than the input bit-width (N > M).
The top-most (N - M) bits of the output are filled with zeros.
When the `nneg` flag is present, the operand is assumed to have
the most significant bit set to 0. In this case, zero extension is
equivalent to sign extension. When this assumption is violated, the
result is poison.
Example:
```mlir
@ -1189,9 +1195,17 @@ def Arith_ExtUIOp : Arith_IToICastOp<"extui"> {
%4 = arith.extui %3 : i3 to i6 // %4 is 0b000010
%5 = arith.extui %0 : vector<2 x i32> to vector<2 x i64>
// Zero extension with nneg flag.
%6 = arith.extui %3 nneg : i3 to i6
```
}];
let arguments = (ins SignlessFixedWidthIntegerLike:$in, UnitAttr:$nonNeg);
let results = (outs SignlessFixedWidthIntegerLike:$out);
let assemblyFormat = [{
$in (`nneg` $nonNeg^)? attr-dict `:` type($in) `to` type($out)
}];
let hasFolder = 1;
let hasVerifier = 1;
}
@ -1477,13 +1491,35 @@ def Arith_ScalingTruncFOp
// UIToFPOp
//===----------------------------------------------------------------------===//
def Arith_UIToFPOp : Arith_IToFCastOp<"uitofp"> {
def Arith_UIToFPOp :
Arith_IToFCastOp<"uitofp", [DeclareOpInterfaceMethods<ArithNonNegFlagInterface>]> {
let summary = "cast from unsigned integer type to floating-point";
let description = [{
Cast from a value interpreted as unsigned integer to the corresponding
floating-point value. If the value cannot be exactly represented, it is
rounded using the default rounding mode. When operating on vectors, casts
elementwise.
When the `nneg` flag is present, the operand is assumed to have
the most significant bit set to 0. In this case, zero extension is
equivalent to sign extension. When this assumption is violated, the
result is poison.
Example:
```mlir
// Without nneg flag.
%0 = arith.uitofp %a : i32 to f64
// With nneg flag.
%1 = arith.uitofp %a nneg : i32 to f64
```
}];
let arguments = (ins SignlessFixedWidthIntegerLike:$in, UnitAttr:$nonNeg);
let results = (outs FloatLike:$out);
let assemblyFormat = [{
$in (`nneg` $nonNeg^)? attr-dict `:` type($in) `to` type($out)
}];
let hasFolder = 1;
}

View File

@ -106,6 +106,53 @@ def ArithIntegerOverflowFlagsInterface : OpInterface<"ArithIntegerOverflowFlagsI
];
}
def ArithNonNegFlagInterface : OpInterface<"ArithNonNegFlagInterface"> {
let description = [{
Access to op non-negative (nneg) flag.
}];
let cppNamespace = "::mlir::arith";
let methods = [
InterfaceMethod<
/*desc=*/ "Returns whether the operation has the nneg flag set",
/*returnType=*/ "bool",
/*methodName=*/ "getNonNeg",
/*args=*/ (ins),
/*methodBody=*/ [{}],
/*defaultImpl=*/ [{
auto op = cast<ConcreteOp>(this->getOperation());
return op.getNonNegAttr() != nullptr;
}]
>,
InterfaceMethod<
/*desc=*/ "Set the nneg flag for the operation",
/*returnType=*/ "void",
/*methodName=*/ "setNonNeg",
/*args=*/ (ins "bool":$nonNeg),
/*methodBody=*/ [{}],
/*defaultImpl=*/ [{
auto op = cast<ConcreteOp>(this->getOperation());
if (nonNeg)
op.setNonNegAttr(UnitAttr::get(op->getContext()));
else
op.removeNonNegAttr();
}]
>,
StaticInterfaceMethod<
/*desc=*/ [{Returns the name of the NonNeg flag attribute for
the operation}],
/*returnType=*/ "StringRef",
/*methodName=*/ "getNonNegFlagAttrName",
/*args=*/ (ins),
/*methodBody=*/ [{}],
/*defaultImpl=*/ [{
return "nonNeg";
}]
>
];
}
def ArithRoundingModeInterface : OpInterface<"ArithRoundingModeInterface"> {
let description = [{
Access to op rounding mode.

View File

@ -104,7 +104,8 @@ using ExtFOpLowering = VectorConvertToLLVMPattern<arith::ExtFOp, LLVM::FPExtOp,
using ExtSIOpLowering =
VectorConvertToLLVMPattern<arith::ExtSIOp, LLVM::SExtOp>;
using ExtUIOpLowering =
VectorConvertToLLVMPattern<arith::ExtUIOp, LLVM::ZExtOp>;
VectorConvertToLLVMPattern<arith::ExtUIOp, LLVM::ZExtOp,
arith::AttrConvertNonNegToLLVM>;
using FPToSIOpLowering =
VectorConvertToLLVMPattern<arith::FPToSIOp, LLVM::FPToSIOp,
AttrConvertPassThrough,
@ -187,7 +188,7 @@ using TruncIOpLowering =
arith::AttrConvertOverflowToLLVM>;
using UIToFPOpLowering =
VectorConvertToLLVMPattern<arith::UIToFPOp, LLVM::UIToFPOp,
AttrConvertPassThrough,
arith::AttrConvertNonNegToLLVM,
/*FailOnUnsupportedFP=*/true>;
using XOrIOpLowering = VectorConvertToLLVMPattern<arith::XOrIOp, LLVM::XOrOp>;

View File

@ -218,8 +218,12 @@ def XOrINotCmpI :
(Arith_CmpIOp (InvertPredicate $pred), $a, $b)>;
// xor extui(x), extui(y) -> extui(xor(x,y))
// XOR preserves nneg only if both operands are non-negative: xor of two values
// with sign bit 0 has sign bit 0.
def XOrIOfExtUI :
Pat<(Arith_XOrIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)), (Arith_ExtUIOp (Arith_XOrIOp $x, $y)),
Pat<(Arith_XOrIOp (Arith_ExtUIOp $x, $nneg1), (Arith_ExtUIOp $y, $nneg2)),
(Arith_ExtUIOp (Arith_XOrIOp $x, $y),
(NativeCodeCall<"($0 && $1) ? $0 : UnitAttr()"> $nneg1, $nneg2)),
[(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>;
// xor extsi(x), extsi(y) -> extsi(xor(x,y))
@ -245,8 +249,8 @@ def CmpIExtSI :
// cmpi(== or !=, a ext iNN, b ext iNN) == cmpi(== or !=, a, b)
def CmpIExtUI :
Pat<(Arith_CmpIOp $pred,
(Arith_ExtUIOp $a),
(Arith_ExtUIOp $b)),
(Arith_ExtUIOp $a, $nneg1),
(Arith_ExtUIOp $b, $nneg2)),
(Arith_CmpIOp $pred, $a, $b),
[(Constraint<CPred<"$0.getType() == $1.getType()">> $a, $b),
(Constraint<
@ -306,7 +310,8 @@ def IndexCastUIOfIndexCastUI :
// index_castui(extui(x)) -> index_castui(x)
def IndexCastUIOfExtUI :
Pat<(Arith_IndexCastUIOp (Arith_ExtUIOp $x)), (Arith_IndexCastUIOp $x)>;
Pat<(Arith_IndexCastUIOp (Arith_ExtUIOp $x, $nneg)),
(Arith_IndexCastUIOp $x)>;
//===----------------------------------------------------------------------===//
@ -323,16 +328,20 @@ def BitcastOfBitcast :
// extsi(extui(x iN : iM) : iL) -> extui(x : iL)
def ExtSIOfExtUI :
Pat<(Arith_ExtSIOp (Arith_ExtUIOp $x)), (Arith_ExtUIOp $x)>;
Pat<(Arith_ExtSIOp (Arith_ExtUIOp $x, $nneg)),
(Arith_ExtUIOp $x, $nneg)>;
//===----------------------------------------------------------------------===//
// AndIOp
//===----------------------------------------------------------------------===//
// and extui(x), extui(y) -> extui(and(x,y))
// AND can only clear bits, so if either operand is non-negative (sign bit 0),
// the result also has sign bit 0. Preserves nneg if either operand has it.
def AndOfExtUI :
Pat<(Arith_AndIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)),
(Arith_ExtUIOp (Arith_AndIOp $x, $y)),
Pat<(Arith_AndIOp (Arith_ExtUIOp $x, $nneg1), (Arith_ExtUIOp $y, $nneg2)),
(Arith_ExtUIOp (Arith_AndIOp $x, $y),
(NativeCodeCall<"$0 ? $0 : $1"> $nneg1, $nneg2)),
[(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>;
// and extsi(x), extsi(y) -> extsi(and(x,y))
@ -346,9 +355,12 @@ def AndOfExtSI :
//===----------------------------------------------------------------------===//
// or extui(x), extui(y) -> extui(or(x,y))
// OR preserves nneg only if both operands are non-negative: or of two values
// with sign bit 0 has sign bit 0.
def OrOfExtUI :
Pat<(Arith_OrIOp (Arith_ExtUIOp $x), (Arith_ExtUIOp $y)),
(Arith_ExtUIOp (Arith_OrIOp $x, $y)),
Pat<(Arith_OrIOp (Arith_ExtUIOp $x, $nneg1), (Arith_ExtUIOp $y, $nneg2)),
(Arith_ExtUIOp (Arith_OrIOp $x, $y),
(NativeCodeCall<"($0 && $1) ? $0 : UnitAttr()"> $nneg1, $nneg2)),
[(Constraint<CPred<"$0.getType() == $1.getType()">> $x, $y)]>;
// or extsi(x), extsi(y) -> extsi(or(x,y))
@ -381,8 +393,8 @@ def TruncIExtSIToExtSI :
// trunci(extui(x)) -> extui(x), when only the zero-extension bits are truncated
def TruncIExtUIToExtUI :
Pat<(Arith_TruncIOp:$tr (Arith_ExtUIOp:$ext $x), $overflow),
(Arith_ExtUIOp $x),
Pat<(Arith_TruncIOp:$tr (Arith_ExtUIOp:$ext $x, $nneg), $overflow),
(Arith_ExtUIOp $x, $nneg),
[(ValueWiderThan $ext, $tr),
(ValueWiderThan $tr, $x)]>;
@ -405,8 +417,8 @@ def TruncFSIToFPToSIToFP :
// truncf(uitofp(x)) -> uitofp(x) if default rounding mode.
def TruncFUIToFPToUIToFP :
Pat<(Arith_TruncFOp:$tr (Arith_UIToFPOp:$fp $x), $rmf, $fmf),
(Arith_UIToFPOp $x),
Pat<(Arith_TruncFOp:$tr (Arith_UIToFPOp:$fp $x, $nneg), $rmf, $fmf),
(Arith_UIToFPOp $x, $nneg),
[(Constraint<CPred<"$0 == nullptr">, "default rounding mode"> $rmf)]>;
//===----------------------------------------------------------------------===//

View File

@ -754,6 +754,30 @@ func.func @ops_supporting_exact(i32, i32) {
// -----
// CHECK-LABEL: @ops_supporting_nneg
func.func @ops_supporting_nneg(%arg0: i32) {
// CHECK: llvm.zext nneg %{{.*}} : i32 to i64
%0 = arith.extui %arg0 nneg : i32 to i64
// CHECK: llvm.uitofp nneg %{{.*}} : i32 to f32
%1 = arith.uitofp %arg0 nneg : i32 to f32
return
}
// -----
// CHECK-LABEL: @ops_nneg_not_set
func.func @ops_nneg_not_set(%arg0: i32) {
// CHECK: llvm.zext %{{.*}} : i32 to i64
// CHECK-NOT: nneg
%0 = arith.extui %arg0 : i32 to i64
// CHECK: llvm.uitofp %{{.*}} : i32 to f32
// CHECK-NOT: nneg
%1 = arith.uitofp %arg0 : i32 to f32
return
}
// -----
// CHECK-LABEL: func @memref_bitcast
// CHECK-SAME: (%[[ARG:.*]]: memref<?xi16>)
// CHECK: %[[V1:.*]] = builtin.unrealized_conversion_cast %[[ARG]] : memref<?xi16> to !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>

View File

@ -366,6 +366,15 @@ func.func @extSIOfExtUI(%arg0: i1) -> i64 {
return %ext2 : i64
}
// CHECK-LABEL: @extSIOfExtUI_nneg
// CHECK: %[[res:.+]] = arith.extui %arg0 nneg : i1 to i64
// CHECK: return %[[res]]
func.func @extSIOfExtUI_nneg(%arg0: i1) -> i64 {
%ext1 = arith.extui %arg0 nneg : i1 to i8
%ext2 = arith.extsi %ext1 : i8 to i64
return %ext2 : i64
}
// CHECK-LABEL: @extUIOfExtUI
// CHECK: %[[res:.+]] = arith.extui %arg0 : i1 to i64
// CHECK: return %[[res]]
@ -490,6 +499,39 @@ func.func @andOfExtUI(%arg0: i8, %arg1: i8) -> i64 {
return %res : i64
}
// CHECK-LABEL: @andOfExtUI_nneg_lhs
// CHECK: %[[comb:.+]] = arith.andi %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] nneg : i8 to i64
// CHECK: return %[[ext]]
func.func @andOfExtUI_nneg_lhs(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 : i8 to i64
%res = arith.andi %ext0, %ext1 : i64
return %res : i64
}
// CHECK-LABEL: @andOfExtUI_nneg_rhs
// CHECK: %[[comb:.+]] = arith.andi %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] nneg : i8 to i64
// CHECK: return %[[ext]]
func.func @andOfExtUI_nneg_rhs(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 : i8 to i64
%ext1 = arith.extui %arg1 nneg : i8 to i64
%res = arith.andi %ext0, %ext1 : i64
return %res : i64
}
// CHECK-LABEL: @andOfExtUI_nneg_both
// CHECK: %[[comb:.+]] = arith.andi %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] nneg : i8 to i64
// CHECK: return %[[ext]]
func.func @andOfExtUI_nneg_both(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 nneg : i8 to i64
%res = arith.andi %ext0, %ext1 : i64
return %res : i64
}
// CHECK-LABEL: @orOfExtSI
// CHECK: %[[comb:.+]] = arith.ori %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extsi %[[comb]] : i8 to i64
@ -512,6 +554,29 @@ func.func @orOfExtUI(%arg0: i8, %arg1: i8) -> i64 {
return %res : i64
}
// CHECK-LABEL: @orOfExtUI_nneg_both
// CHECK: %[[comb:.+]] = arith.ori %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] nneg : i8 to i64
// CHECK: return %[[ext]]
func.func @orOfExtUI_nneg_both(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 nneg : i8 to i64
%res = arith.ori %ext0, %ext1 : i64
return %res : i64
}
// CHECK-LABEL: @orOfExtUI_nneg_mixed
// CHECK: %[[comb:.+]] = arith.ori %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] : i8 to i64
// CHECK-NOT: nneg
// CHECK: return %[[ext]]
func.func @orOfExtUI_nneg_mixed(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 : i8 to i64
%res = arith.ori %ext0, %ext1 : i64
return %res : i64
}
// -----
// CHECK-LABEL: @indexCastOfSignExtend
@ -532,6 +597,15 @@ func.func @indexCastUIOfUnsignedExtend(%arg0: i8) -> index {
return %idx : index
}
// CHECK-LABEL: @indexCastUIOfUnsignedExtend_nneg
// CHECK: %[[res:.+]] = arith.index_castui %arg0 : i8 to index
// CHECK: return %[[res]]
func.func @indexCastUIOfUnsignedExtend_nneg(%arg0: i8) -> index {
%ext = arith.extui %arg0 nneg : i8 to i16
%idx = arith.index_castui %ext : i16 to index
return %idx : index
}
// CHECK-LABEL: @indexCastFold
// CHECK: %[[res:.*]] = arith.constant -2 : index
// CHECK: return %[[res]]
@ -771,6 +845,26 @@ func.func @truncSitofpConstrained(%arg0: i32) -> f32 {
return %trunc : f32
}
// CHECK-LABEL: @truncUitofp
// CHECK: %[[UITOFP:.*]] = arith.uitofp %[[ARG0:.*]] : i32 to f32
// CHECK-NOT: truncf
// CHECK: return %[[UITOFP]]
func.func @truncUitofp(%arg0: i32) -> f32 {
%uitofp = arith.uitofp %arg0 : i32 to f64
%trunc = arith.truncf %uitofp : f64 to f32
return %trunc : f32
}
// CHECK-LABEL: @truncUitofp_nneg
// CHECK: %[[UITOFP:.*]] = arith.uitofp %[[ARG0:.*]] nneg : i32 to f32
// CHECK-NOT: truncf
// CHECK: return %[[UITOFP]]
func.func @truncUitofp_nneg(%arg0: i32) -> f32 {
%uitofp = arith.uitofp %arg0 nneg : i32 to f64
%trunc = arith.truncf %uitofp : f64 to f32
return %trunc : f32
}
// TODO: We should also add a test for not folding arith.extf on information loss.
// This may happen when extending f8E5M2FNUZ to f16.
@ -812,6 +906,16 @@ func.func @truncExtui3(%arg0: i8) -> i16 {
return %trunci : i16
}
// CHECK-LABEL: @truncExtui3_nneg
// CHECK: %[[ARG0:.+]]: i8
// CHECK: %[[CST:.*]] = arith.extui %[[ARG0:.+]] nneg : i8 to i16
// CHECK: return %[[CST:.*]] : i16
func.func @truncExtui3_nneg(%arg0: i8) -> i16 {
%extui = arith.extui %arg0 nneg : i8 to i32
%trunci = arith.trunci %extui : i32 to i16
return %trunci : i16
}
// CHECK-LABEL: @truncExtuiVector
// CHECK: %[[ARG0:.+]]: vector<2xi32>
// CHECK: %[[CST:.*]] = arith.trunci %[[ARG0:.+]] : vector<2xi32> to vector<2xi16>
@ -1817,6 +1921,29 @@ func.func @xorOfExtUI(%arg0: i8, %arg1: i8) -> i64 {
return %res : i64
}
// CHECK-LABEL: @xorOfExtUI_nneg_both
// CHECK: %[[comb:.+]] = arith.xori %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] nneg : i8 to i64
// CHECK: return %[[ext]]
func.func @xorOfExtUI_nneg_both(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 nneg : i8 to i64
%res = arith.xori %ext0, %ext1 : i64
return %res : i64
}
// CHECK-LABEL: @xorOfExtUI_nneg_mixed
// CHECK: %[[comb:.+]] = arith.xori %arg0, %arg1 : i8
// CHECK: %[[ext:.+]] = arith.extui %[[comb]] : i8 to i64
// CHECK-NOT: nneg
// CHECK: return %[[ext]]
func.func @xorOfExtUI_nneg_mixed(%arg0: i8, %arg1: i8) -> i64 {
%ext0 = arith.extui %arg0 nneg : i8 to i64
%ext1 = arith.extui %arg1 : i8 to i64
%res = arith.xori %ext0, %ext1 : i64
return %res : i64
}
// -----
// CHECK-LABEL: @bitcastSameType(

View File

@ -625,6 +625,20 @@ func.func @test_extui_scalable_vector(%arg0 : vector<[8]xi32>) -> vector<[8]xi64
return %0 : vector<[8]xi64>
}
// CHECK-LABEL: test_extui_nneg
// CHECK: arith.extui %{{.*}} nneg : i32 to i64
func.func @test_extui_nneg(%arg0 : i32) -> i64 {
%0 = arith.extui %arg0 nneg : i32 to i64
return %0 : i64
}
// CHECK-LABEL: test_extui_nneg_vector
// CHECK: arith.extui %{{.*}} nneg : vector<8xi32> to vector<8xi64>
func.func @test_extui_nneg_vector(%arg0 : vector<8xi32>) -> vector<8xi64> {
%0 = arith.extui %arg0 nneg : vector<8xi32> to vector<8xi64>
return %0 : vector<8xi64>
}
// CHECK-LABEL: test_extsi
func.func @test_extsi(%arg0 : i32) -> i64 {
%0 = arith.extsi %arg0 : i32 to i64
@ -761,6 +775,20 @@ func.func @test_uitofp_scalable_vector(%arg0 : vector<[8]xi32>) -> vector<[8]xf3
return %0 : vector<[8]xf32>
}
// CHECK-LABEL: test_uitofp_nneg
// CHECK: arith.uitofp %{{.*}} nneg : i32 to f32
func.func @test_uitofp_nneg(%arg0 : i32) -> f32 {
%0 = arith.uitofp %arg0 nneg : i32 to f32
return %0 : f32
}
// CHECK-LABEL: test_uitofp_nneg_vector
// CHECK: arith.uitofp %{{.*}} nneg : vector<8xi32> to vector<8xf32>
func.func @test_uitofp_nneg_vector(%arg0 : vector<8xi32>) -> vector<8xf32> {
%0 = arith.uitofp %arg0 nneg : vector<8xi32> to vector<8xf32>
return %0 : vector<8xf32>
}
// CHECK-LABEL: test_sitofp
func.func @test_sitofp(%arg0 : i16) -> f64 {
%0 = arith.sitofp %arg0 : i16 to f64