Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
JIT, AOT preinit, and CoreLib: Saturate float/double conversions to small integral types#128604
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
5f042fc0d43c8030c6aec308186199629b2f36debb84a48abaf1068c9e2ae481486caaf57b586d6b33d3154bb7cc56595adb398bf867f217a5c5f12cbcbd695515e6bbeedfdd71abf12c804a6aa8dee91761543844c24072f97daf2b1509a02c3bf1ca75a0bd0a797f48dbe177d50b6dcc4f6a6File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -3344,11 +3344,6 @@ void emitter::emitIns_R_R_I_I(instruction ins, | ||
| int msb = lsb + width - 1; | ||
| int imm = 0; /* combined immediate */ | ||
| assert((lsb >= 0) && (lsb <= 31)); // required for encodings | ||
| assert((width > 0) && (width <= 32)); // required for encodings | ||
| assert((msb >= 0) && (msb <= 31)); // required for encodings | ||
| assert(msb >= lsb); // required for encodings | ||
| /* Figure out the encoding format of the instruction */ | ||
| switch (ins) | ||
| { | ||
| @@ -3357,6 +3352,10 @@ void emitter::emitIns_R_R_I_I(instruction ins, | ||
| assert(reg2 != REG_PC); | ||
| assert(insDoesNotSetFlags(flags)); | ||
| assert((lsb >= 0) && (lsb <= 31)); // required for encoding | ||
| assert((width > 0) && (width <= 32)); // required for encoding | ||
| assert((msb >= 0) && (msb <= 31)); // required for encoding | ||
| assert(msb >= lsb); // required for encoding | ||
| imm = (lsb << 5) | msb; | ||
| fmt = IF_T2_D0; | ||
| @@ -3369,12 +3368,44 @@ void emitter::emitIns_R_R_I_I(instruction ins, | ||
| assert(reg2 != REG_PC); | ||
| assert(insDoesNotSetFlags(flags)); | ||
| assert((lsb >= 0) && (lsb <= 31)); // required for encoding | ||
| assert((width > 0) && (width <= 32)); // required for encoding | ||
| assert((msb >= 0) && (msb <= 31)); // required for encoding | ||
| assert(msb >= lsb); // required for encoding | ||
| imm = (lsb << 5) | (width - 1); | ||
| fmt = IF_T2_D0; | ||
| sf = INS_FLAGS_NOT_SET; | ||
| break; | ||
| case INS_ssat: | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // imm1 = shift amount (must be 0 for no shift), imm2 = saturation bits N (1-32) | ||
| // Encoding: sat_imm field = N-1 stored in bits[4:0]; no shift (sh=0, imm5=0). | ||
| assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. | ||
| assert(reg2 != REG_PC); | ||
| assert(insDoesNotSetFlags(flags)); | ||
| assert((imm1 == 0) && (imm2 >= 1) && (imm2 <= 32)); // required for encoding | ||
| imm = (lsb << 5) | (width - 1); // lsb=shift=0, width=N -> sat_imm = N-1 | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| fmt = IF_T2_D0; | ||
| sf = INS_FLAGS_NOT_SET; | ||
| break; | ||
| case INS_usat: | ||
| // imm1 = shift amount (must be 0 for no shift), imm2 = saturation bits N (0-31) | ||
| // Encoding: sat_imm field = N stored directly in bits[4:0]; no shift (sh=0, imm5=0). | ||
| assert(reg1 != REG_PC); // VM debugging single stepper doesn't support PC register with this instruction. | ||
| assert(reg2 != REG_PC); | ||
| assert(insDoesNotSetFlags(flags)); | ||
| assert((imm1 == 0) && (imm2 >= 0) && (imm2 <= 31)); // required for encoding | ||
| imm = (lsb << 5) | width; // lsb=shift=0, width=N -> sat_imm = N | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| fmt = IF_T2_D0; | ||
| sf = INS_FLAGS_NOT_SET; | ||
| break; | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| default: | ||
| unreached(); | ||
| } | ||
| @@ -7569,6 +7600,18 @@ void emitter::emitDispInsHelp( | ||
| emitDispImm(imm1, true); | ||
| emitDispImm(imm2, false); | ||
| } | ||
| else if (ins == INS_ssat) | ||
| { | ||
| // SSAT: stored as sat_imm = N-1; display as #N (saturation bits) | ||
| int satBits = (imm & 0x1f) + 1; | ||
| emitDispImm(satBits, false); | ||
| } | ||
| else if (ins == INS_usat) | ||
| { | ||
| // USAT: stored as sat_imm = N; display as #N (saturation bits) | ||
| int satBits = imm & 0x1f; | ||
| emitDispImm(satBits, false); | ||
| } | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| else | ||
| { | ||
| int lsb = (imm >> 5) & 0x1f; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6796,6 +6796,26 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) | ||
| #endif | ||
| } | ||
| case NI_PRIMITIVE_SaturateToInt8: | ||
| case NI_PRIMITIVE_SaturateToInt16: | ||
| case NI_PRIMITIVE_SaturateToUInt8: | ||
| case NI_PRIMITIVE_SaturateToUInt16: | ||
| { | ||
| #if defined(TARGET_ARM) | ||
| // Single SSAT/USAT instruction. | ||
| costEx = 1; | ||
| costSz = 4; | ||
| #else | ||
| // Targets without saturating ALU ops (e.g. RISC-V64, LoongArch64) | ||
| // expand this into a normalize, two bound materializations, and two | ||
tannergooding marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // compare/branch/move pairs (~7 instructions), so it is materially | ||
| // more expensive. | ||
| costEx = 7; | ||
| costSz = 28; | ||
| #endif | ||
| break; | ||
| } | ||
| case NI_System_Math_Acos: | ||
| case NI_System_Math_Acosh: | ||
| case NI_System_Math_Asin: | ||
| @@ -7249,7 +7269,16 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) | ||
| level++; | ||
| break; | ||
| } | ||
| #endif // TARGET_RISCV64 | ||
| #elif defined(TARGET_WASM) | ||
| // WASM lowers MaxNative/MinNative to native min/max instructions. Used | ||
| // both by user calls and by morph's float -> small int saturating clamp. | ||
| case NI_System_Math_MaxNative: | ||
| case NI_System_Math_MinNative: | ||
| { | ||
| level++; | ||
| break; | ||
| } | ||
| #endif // TARGET_RISCV64 || TARGET_WASM | ||
| default: | ||
| assert(!"Unknown binary GT_INTRINSIC operator"); | ||
| @@ -14245,6 +14274,18 @@ void Compiler::gtDispTree(GenTree* tree, | ||
| printf(" popCount"); | ||
| break; | ||
| #endif // TARGET_RISCV64 | ||
| case NI_PRIMITIVE_SaturateToInt8: | ||
| printf(" saturateToInt8"); | ||
| break; | ||
| case NI_PRIMITIVE_SaturateToInt16: | ||
| printf(" saturateToInt16"); | ||
| break; | ||
| case NI_PRIMITIVE_SaturateToUInt8: | ||
| printf(" saturateToUInt8"); | ||
| break; | ||
| case NI_PRIMITIVE_SaturateToUInt16: | ||
| printf(" saturateToUInt16"); | ||
| break; | ||
| case NI_System_Math_Pow: | ||
| printf(" pow"); | ||
| break; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.