diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index a23105ca5b1a1b..7be643600d93cb 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -605,6 +605,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) JITDUMP("Ignoring GT_MEMORYBARRIER; single-threaded codegen\n"); break; + case GT_INTRINSIC: + genIntrinsic(treeNode->AsIntrinsic()); + break; + default: #ifdef DEBUG NYIRAW(GenTree::OpName(treeNode->OperGet())); @@ -1471,6 +1475,109 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) WasmProduceReg(lea); } +//------------------------------------------------------------------------ +// PackIntrinsicAndType: Pack a intrinsic and var_types into a uint32_t +// +// Arguments: +// ni - a NamedIntrinsic to pack +// type - a var_types to pack +// +// Return Value: +// intrinsic and type packed into an integer that can be used as a switch value/case +// +static constexpr uint32_t PackIntrinsicAndType(NamedIntrinsic ni, var_types type) +{ + if ((type == TYP_BYREF) || (type == TYP_REF)) + { + type = TYP_I_IMPL; + } + const int shift1 = ConstLog2::value + 1; + return ((uint32_t)ni << shift1) | ((uint32_t)type); +} + +//--------------------------------------------------------------------- +// genIntrinsic - generate code for a given intrinsic +// +// Arguments +// treeNode - the GT_INTRINSIC node +// +// Return value: +// None +// +void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode) +{ + genConsumeOperands(treeNode); + + // Handle intrinsics that can be implemented by target-specific instructions + instruction ins; + switch (PackIntrinsicAndType(treeNode->gtIntrinsicName, treeNode->TypeGet())) + { + case PackIntrinsicAndType(NI_System_Math_Abs, TYP_FLOAT): + ins = INS_f32_abs; + break; + case PackIntrinsicAndType(NI_System_Math_Abs, TYP_DOUBLE): + ins = INS_f64_abs; + break; + + case PackIntrinsicAndType(NI_System_Math_Ceiling, TYP_FLOAT): + ins = INS_f32_ceil; + break; + case PackIntrinsicAndType(NI_System_Math_Ceiling, TYP_DOUBLE): + ins = INS_f64_ceil; + break; + + case PackIntrinsicAndType(NI_System_Math_Floor, TYP_FLOAT): + ins = INS_f32_floor; + break; + case PackIntrinsicAndType(NI_System_Math_Floor, TYP_DOUBLE): + ins = INS_f64_floor; + break; + + case PackIntrinsicAndType(NI_System_Math_Max, TYP_FLOAT): + ins = INS_f32_max; + break; + case PackIntrinsicAndType(NI_System_Math_Max, TYP_DOUBLE): + ins = INS_f64_max; + break; + + case PackIntrinsicAndType(NI_System_Math_Min, TYP_FLOAT): + ins = INS_f32_min; + break; + case PackIntrinsicAndType(NI_System_Math_Min, TYP_DOUBLE): + ins = INS_f64_min; + break; + + case PackIntrinsicAndType(NI_System_Math_Round, TYP_FLOAT): + ins = INS_f32_nearest; + break; + case PackIntrinsicAndType(NI_System_Math_Round, TYP_DOUBLE): + ins = INS_f64_nearest; + break; + + case PackIntrinsicAndType(NI_System_Math_Sqrt, TYP_FLOAT): + ins = INS_f32_sqrt; + break; + case PackIntrinsicAndType(NI_System_Math_Sqrt, TYP_DOUBLE): + ins = INS_f64_sqrt; + break; + + case PackIntrinsicAndType(NI_System_Math_Truncate, TYP_FLOAT): + ins = INS_f32_trunc; + break; + case PackIntrinsicAndType(NI_System_Math_Truncate, TYP_DOUBLE): + ins = INS_f64_trunc; + break; + + default: + assert(!"genIntrinsic: Unsupported intrinsic"); + unreached(); + } + + GetEmitter()->emitIns(ins); + + WasmProduceReg(treeNode); +} + //------------------------------------------------------------------------ // genCodeForLclAddr: Generates the code for GT_LCL_ADDR. // diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 62b79e697788ff..54d6ef04963f15 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8480,6 +8480,25 @@ bool Compiler::IsTargetIntrinsic(NamedIntrinsic intrinsicName) default: return false; } + +#elif defined(TARGET_WASM) + + // TODO-WASM-CQ: we can likely support more intrinsics here + switch (intrinsicName) + { + case NI_System_Math_Abs: + case NI_System_Math_Ceiling: + case NI_System_Math_Floor: + case NI_System_Math_Max: + case NI_System_Math_Min: + case NI_System_Math_Round: + case NI_System_Math_Sqrt: + case NI_System_Math_Truncate: + return true; + + default: + return false; + } #else // TODO: This portion of logic is not implemented for other arch. // The reason for returning true is that on all other arch the only intrinsic