diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 610f66fb0db276..f891804787da42 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -622,7 +622,7 @@ void CodeGen::genIntrinsic(GenTree* treeNode) assert(varTypeIsFloating(srcNode)); assert(srcNode->TypeGet() == treeNode->TypeGet()); - // Right now only Abs/Ceiling/Floor/Round/Sqrt are treated as math intrinsics. + // Right now only Abs/Ceiling/Floor/Truncate/Round/Sqrt are treated as math intrinsics. // switch (treeNode->AsIntrinsic()->gtIntrinsicName) { @@ -642,6 +642,11 @@ void CodeGen::genIntrinsic(GenTree* treeNode) GetEmitter()->emitInsBinary(INS_frintm, emitActualTypeSize(treeNode), treeNode, srcNode); break; + case NI_System_Math_Truncate: + genConsumeOperands(treeNode->AsOp()); + GetEmitter()->emitInsBinary(INS_frintz, emitActualTypeSize(treeNode), treeNode, srcNode); + break; + case NI_System_Math_Round: genConsumeOperands(treeNode->AsOp()); GetEmitter()->emitInsBinary(INS_frintn, emitActualTypeSize(treeNode), treeNode, srcNode); diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 6c4c34542e4b46..21342bce4c688f 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -7027,7 +7027,7 @@ void CodeGen::genSSE2BitwiseOp(GenTree* treeNode) // ii) treeNode oper is a GT_INTRINSIC // iii) treeNode type is a floating point type // iv) treeNode is not used from memory -// v) tree oper is NI_System_Math{F}_Round, _Ceiling, or _Floor +// v) tree oper is NI_System_Math{F}_Round, _Ceiling, _Floor, or _Truncate // vi) caller of this routine needs to call genProduceReg() void CodeGen::genSSE41RoundOp(GenTreeOp* treeNode) { @@ -7055,7 +7055,7 @@ void CodeGen::genSSE41RoundOp(GenTreeOp* treeNode) unsigned ival = 0; - // v) tree oper is NI_System_Math{F}_Round, _Ceiling, or _Floor + // v) tree oper is NI_System_Math{F}_Round, _Ceiling, _Floor, or _Truncate switch (treeNode->AsIntrinsic()->gtIntrinsicName) { case NI_System_Math_Round: @@ -7070,6 +7070,10 @@ void CodeGen::genSSE41RoundOp(GenTreeOp* treeNode) ival = 9; break; + case NI_System_Math_Truncate: + ival = 11; + break; + default: ins = INS_invalid; assert(!"genSSE41RoundOp: unsupported intrinsic"); @@ -7197,6 +7201,7 @@ void CodeGen::genIntrinsic(GenTree* treeNode) case NI_System_Math_Ceiling: case NI_System_Math_Floor: + case NI_System_Math_Truncate: case NI_System_Math_Round: genSSE41RoundOp(treeNode->AsOp()); break; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1b99f5171cef08..bb69349329857b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -3735,6 +3735,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) case NI_System_Math_Sqrt: case NI_System_Math_Tan: case NI_System_Math_Tanh: + case NI_System_Math_Truncate: { // Giving intrinsics a large fixed execution cost is because we'd like to CSE // them, even if they are implemented by calls. This is different from modeling @@ -10764,6 +10765,9 @@ void Compiler::gtDispTree(GenTree* tree, case NI_System_Math_Tanh: printf(" tanh"); break; + case NI_System_Math_Truncate: + printf(" truncate"); + break; case NI_System_Object_GetType: printf(" objGetType"); break; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index ac361b08e8eb5f..736a638c72d3bc 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4424,6 +4424,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_Math_Sqrt: case NI_System_Math_Tan: case NI_System_Math_Tanh: + case NI_System_Math_Truncate: { retNode = impMathIntrinsic(method, sig, callType, ni, tailCall); break; @@ -5070,6 +5071,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Math_Tanh; } + else if (strcmp(methodName, "Truncate") == 0) + { + result = NI_System_Math_Truncate; + } } else if (strcmp(className, "GC") == 0) { @@ -20425,7 +20430,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) switch (intrinsicName) { // AMD64/x86 has SSE2 instructions to directly compute sqrt/abs and SSE4.1 - // instructions to directly compute round/ceiling/floor. + // instructions to directly compute round/ceiling/floor/truncate. case NI_System_Math_Abs: case NI_System_Math_Sqrt: @@ -20433,6 +20438,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) case NI_System_Math_Ceiling: case NI_System_Math_Floor: + case NI_System_Math_Truncate: case NI_System_Math_Round: return compOpportunisticallyDependsOn(InstructionSet_SSE41); @@ -20448,6 +20454,7 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) case NI_System_Math_Abs: case NI_System_Math_Ceiling: case NI_System_Math_Floor: + case NI_System_Math_Truncate: case NI_System_Math_Round: case NI_System_Math_Sqrt: return true; @@ -20521,6 +20528,7 @@ bool Compiler::IsMathIntrinsic(NamedIntrinsic intrinsicName) case NI_System_Math_Sqrt: case NI_System_Math_Tan: case NI_System_Math_Tanh: + case NI_System_Math_Truncate: { assert((intrinsicName > NI_SYSTEM_MATH_START) && (intrinsicName < NI_SYSTEM_MATH_END)); return true; diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 663ac0cec3f6cb..46b48c4a8a9393 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -5275,7 +5275,8 @@ void Lowering::ContainCheckIntrinsic(GenTreeOp* node) NamedIntrinsic intrinsicName = node->AsIntrinsic()->gtIntrinsicName; if ((intrinsicName == NI_System_Math_Ceiling) || (intrinsicName == NI_System_Math_Floor) || - (intrinsicName == NI_System_Math_Round) || (intrinsicName == NI_System_Math_Sqrt)) + (intrinsicName == NI_System_Math_Truncate) || (intrinsicName == NI_System_Math_Round) || + (intrinsicName == NI_System_Math_Sqrt)) { GenTree* op1 = node->gtGetOp1(); diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 3091700df42226..522f3d709c980e 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -329,6 +329,7 @@ int LinearScan::BuildNode(GenTree* tree) noway_assert((tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Abs) || (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Ceiling) || (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Floor) || + (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Truncate) || (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Round) || (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Math_Sqrt)); diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index e679f00b3bca33..e0eb5e9c0680fd 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -1817,6 +1817,7 @@ int LinearScan::BuildIntrinsic(GenTree* tree) case NI_System_Math_Ceiling: case NI_System_Math_Floor: + case NI_System_Math_Truncate: case NI_System_Math_Round: case NI_System_Math_Sqrt: break; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 68ea721ae48180..d864c3f7baeda9 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -43,6 +43,7 @@ enum NamedIntrinsic : unsigned short NI_System_Math_Sqrt, NI_System_Math_Tan, NI_System_Math_Tanh, + NI_System_Math_Truncate, NI_SYSTEM_MATH_END, NI_System_Collections_Generic_Comparer_get_Default, diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index be8f65e608c677..89aa710662acd6 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -5294,6 +5294,10 @@ ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, NamedIntrinsic gtMathFN res = tanh(arg0Val); break; + case NI_System_Math_Truncate: + res = trunc(arg0Val); + break; + default: // the above are the only math intrinsics at the time of this writing. unreached(); @@ -5398,6 +5402,10 @@ ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, NamedIntrinsic gtMathFN res = tanhf(arg0Val); break; + case NI_System_Math_Truncate: + res = truncf(arg0Val); + break; + default: // the above are the only math intrinsics at the time of this writing. unreached(); @@ -5552,6 +5560,9 @@ ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, NamedIntrinsic gtMathFN case NI_System_Math_Tanh: vnf = VNF_Tanh; break; + case NI_System_Math_Truncate: + vnf = VNF_Truncate; + break; default: unreached(); // the above are the only math intrinsics at the time of this writing. } diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index f82c2ff603d07e..47135a0f734a3b 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -101,6 +101,7 @@ ValueNumFuncDef(Sinh, 1, false, false, false) ValueNumFuncDef(Sqrt, 1, false, false, false) ValueNumFuncDef(Tan, 1, false, false, false) ValueNumFuncDef(Tanh, 1, false, false, false) +ValueNumFuncDef(Truncate, 1, false, false, false) ValueNumFuncDef(ManagedThreadId, 0, false, false, false) diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index db22c68fde053a..6c25d6c769ca35 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -4222,6 +4222,7 @@ PALIMPORT double __cdecl sinh(double); PALIMPORT double __cdecl sqrt(double); PALIMPORT double __cdecl tan(double); PALIMPORT double __cdecl tanh(double); +PALIMPORT double __cdecl trunc(double); PALIMPORT int __cdecl _finitef(float); PALIMPORT int __cdecl _isnanf(float); @@ -4254,6 +4255,7 @@ PALIMPORT float __cdecl sinhf(float); PALIMPORT float __cdecl sqrtf(float); PALIMPORT float __cdecl tanf(float); PALIMPORT float __cdecl tanhf(float); +PALIMPORT float __cdecl truncf(float); #endif // !PAL_STDCPP_COMPAT #ifndef PAL_STDCPP_COMPAT diff --git a/src/coreclr/pal/src/include/pal/palinternal.h b/src/coreclr/pal/src/include/pal/palinternal.h index ff3703c6ae4f7f..e9c4129f1798c0 100644 --- a/src/coreclr/pal/src/include/pal/palinternal.h +++ b/src/coreclr/pal/src/include/pal/palinternal.h @@ -221,6 +221,7 @@ function_name() to call the system's implementation #define sqrt DUMMY_sqrt #define tan DUMMY_tan #define tanh DUMMY_tanh +#define trunc DUMMY_trunc #define ceilf DUMMY_ceilf #define cosf DUMMY_cosf #define coshf DUMMY_coshf @@ -233,6 +234,7 @@ function_name() to call the system's implementation #define sqrtf DUMMY_sqrtf #define tanf DUMMY_tanf #define tanhf DUMMY_tanhf +#define truncf DUMMY_truncf /* RAND_MAX needed to be renamed to avoid duplicate definition when including stdlib.h header files. PAL_RAND_MAX should have the same value as RAND_MAX @@ -464,6 +466,7 @@ function_name() to call the system's implementation #undef sqrt #undef tan #undef tanh +#undef trunc #undef acosf #undef acoshf #undef asinf @@ -492,6 +495,7 @@ function_name() to call the system's implementation #undef sqrtf #undef tanf #undef tanhf +#undef truncf #undef rand #undef srand #undef errno diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index a929322173585c..896f07cf855322 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1452,6 +1452,7 @@ public static decimal Truncate(decimal d) return decimal.Truncate(d); } + [Intrinsic] public static unsafe double Truncate(double d) { ModF(d, &d); diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index 2c4d7dce969d34..f4cde2dc7f71a2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -508,6 +508,7 @@ public static int Sign(float x) return Math.Sign(x); } + [Intrinsic] public static unsafe float Truncate(float x) { ModF(x, &x);