-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[Wasm RyuJit] codegen for some intrinsics #124575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<TYP_COUNT>::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; | ||
|
Comment on lines
+1536
to
+1548
|
||
|
|
||
| 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. | ||
| // | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For example: case NI_System_Math_CopySign: // f32.copysign / f64.copysign
case NI_System_Math_MaxNative: // f32.max / f64.max
case NI_System_Math_MinNative: // f32.min / f64.mincase PackIntrinsicAndType(NI_System_Math_CopySign, TYP_FLOAT):
ins = INS_f32_copysign;
break;
case PackIntrinsicAndType(NI_System_Math_CopySign, TYP_DOUBLE):
ins = INS_f64_copysign;
break; |
||
| 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; | ||
|
Comment on lines
+8486
to
+8497
|
||
|
|
||
| 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 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instruction ins;is left uninitialized and then assigned in the switch. Some toolchains warn on this pattern even withunreached()in the default case. InitializinginstoINS_invalid(or similar) avoids potential build breaks from -Wmaybe-uninitialized and matches the pattern used in other backends.