diff --git a/mlir/include/mlir/Conversion/ArithCommon/AttrToLLVMConverter.h b/mlir/include/mlir/Conversion/ArithCommon/AttrToLLVMConverter.h index 7020e24517d0..fccfe4897114 100644 --- a/mlir/include/mlir/Conversion/ArithCommon/AttrToLLVMConverter.h +++ b/mlir/include/mlir/Conversion/ArithCommon/AttrToLLVMConverter.h @@ -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 +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 getAttrs() const { return convertedAttr.getAttrs(); } + Attribute getPropAttr() const { return propertiesAttr; } + +private: + NamedAttrList convertedAttr; + DictionaryAttr propertiesAttr; +}; + template class AttrConverterConstrainedFPToLLVM { static_assert(TargetOp::template hasTrait< diff --git a/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td b/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td index c8754954c181..c372038a8d43 100644 --- a/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td +++ b/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td @@ -1172,7 +1172,8 @@ def Arith_RemFOp : Arith_FloatBinaryOp<"remf"> { // ExtUIOp //===----------------------------------------------------------------------===// -def Arith_ExtUIOp : Arith_IToICastOp<"extui"> { +def Arith_ExtUIOp : + Arith_IToICastOp<"extui", [DeclareOpInterfaceMethods]> { 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]> { 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; } diff --git a/mlir/include/mlir/Dialect/Arith/IR/ArithOpsInterfaces.td b/mlir/include/mlir/Dialect/Arith/IR/ArithOpsInterfaces.td index 82d6c9ad6b03..d1b8e250cdb5 100644 --- a/mlir/include/mlir/Dialect/Arith/IR/ArithOpsInterfaces.td +++ b/mlir/include/mlir/Dialect/Arith/IR/ArithOpsInterfaces.td @@ -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(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(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. diff --git a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp index 220826dc5f3a..178dcd419264 100644 --- a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp +++ b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp @@ -104,7 +104,8 @@ using ExtFOpLowering = VectorConvertToLLVMPattern; using ExtUIOpLowering = - VectorConvertToLLVMPattern; + VectorConvertToLLVMPattern; using FPToSIOpLowering = VectorConvertToLLVMPattern; using UIToFPOpLowering = VectorConvertToLLVMPattern; using XOrIOpLowering = VectorConvertToLLVMPattern; diff --git a/mlir/lib/Dialect/Arith/IR/ArithCanonicalization.td b/mlir/lib/Dialect/Arith/IR/ArithCanonicalization.td index e256915933a7..8be2af5cb3cf 100644 --- a/mlir/lib/Dialect/Arith/IR/ArithCanonicalization.td +++ b/mlir/lib/Dialect/Arith/IR/ArithCanonicalization.td @@ -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> $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> $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> $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> $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, "default rounding mode"> $rmf)]>; //===----------------------------------------------------------------------===// diff --git a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir index b53c52d75c0a..7ae27a884d5d 100644 --- a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir +++ b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir @@ -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) // CHECK: %[[V1:.*]] = builtin.unrealized_conversion_cast %[[ARG]] : memref to !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> diff --git a/mlir/test/Dialect/Arith/canonicalize.mlir b/mlir/test/Dialect/Arith/canonicalize.mlir index 18e0d2d2ea3c..52f4a54feeba 100644 --- a/mlir/test/Dialect/Arith/canonicalize.mlir +++ b/mlir/test/Dialect/Arith/canonicalize.mlir @@ -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( diff --git a/mlir/test/Dialect/Arith/ops.mlir b/mlir/test/Dialect/Arith/ops.mlir index 58eadfda1706..9541cecb489f 100644 --- a/mlir/test/Dialect/Arith/ops.mlir +++ b/mlir/test/Dialect/Arith/ops.mlir @@ -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