Skip to content

Commit ab3c7da

Browse files
* fix #105969 * formatting * reset the base type of some intrinsics when the actual base type mismatches with the data type implied by the intrinsics. * Move the normalization to import. * clean up * bug fix * formatting. * bug fix * resolve comments. * Ensure that we're computing the correct memory operand size for disassembly * Ensure that we correctly handled rewriting PTESTM to account for a nested AND having an embedded broadcast --------- Co-authored-by: Tanner Gooding <[email protected]>
1 parent 0c67acb commit ab3c7da

File tree

11 files changed

+205
-73
lines changed

11 files changed

+205
-73
lines changed

src/coreclr/jit/emit.h

+7-48
Original file line numberDiff line numberDiff line change
@@ -2249,8 +2249,7 @@ class emitter
22492249
ssize_t emitGetInsCIdisp(instrDesc* id);
22502250
unsigned emitGetInsCIargs(instrDesc* id);
22512251

2252-
inline emitAttr emitGetMemOpSize(instrDesc* id) const;
2253-
inline emitAttr emitGetBaseMemOpSize(instrDesc*) const;
2252+
inline emitAttr emitGetMemOpSize(instrDesc* id, bool ignoreEmbeddedBroadcast = false) const;
22542253

22552254
// Return the argument count for a direct call "id".
22562255
int emitGetInsCDinfo(instrDesc* id);
@@ -3962,51 +3961,11 @@ inline unsigned emitter::emitGetInsCIargs(instrDesc* id)
39623961
//-----------------------------------------------------------------------------
39633962
// emitGetMemOpSize: Get the memory operand size of instrDesc.
39643963
//
3965-
// Note: there are cases when embedded broadcast is enabled, so the memory operand
3966-
// size is different from the intrinsic simd size, we will check here if emitter is
3967-
// emiting a embedded broadcast enabled instruction.
3968-
3969-
// Arguments:
3970-
// id - Instruction descriptor
3971-
//
3972-
emitAttr emitter::emitGetMemOpSize(instrDesc* id) const
3973-
{
3974-
if (id->idIsEvexbContextSet())
3975-
{
3976-
// should have the assumption that Evex.b now stands for the embedded broadcast context.
3977-
// reference: Section 2.7.5 in Intel 64 and ia-32 architectures software developer's manual volume 2.
3978-
ssize_t inputSize = GetInputSizeInBytes(id);
3979-
switch (inputSize)
3980-
{
3981-
case 4:
3982-
return EA_4BYTE;
3983-
case 8:
3984-
return EA_8BYTE;
3985-
3986-
default:
3987-
unreached();
3988-
}
3989-
}
3990-
else
3991-
{
3992-
return emitGetBaseMemOpSize(id);
3993-
}
3994-
}
3995-
3996-
//-----------------------------------------------------------------------------
3997-
// emitGetMemOpSize: Get the memory operand size of instrDesc.
3998-
//
3999-
// Note: vextractf128 has a 128-bit output (register or memory) but a 256-bit input (register).
4000-
// vinsertf128 is the inverse with a 256-bit output (register), a 256-bit input(register),
4001-
// and a 128-bit input (register or memory).
4002-
// Similarly, vextractf64x4 has a 256-bit output and 128-bit input and vinsertf64x4 the inverse
4003-
// This method is mainly used for such instructions to return the appropriate memory operand
4004-
// size, otherwise returns the regular operand size of the instruction.
4005-
40063964
// Arguments:
4007-
// id - Instruction descriptor
3965+
// id - Instruction descriptor
3966+
// ignoreEmbeddedBroadcast - true to get the non-embedded operand size; otherwise false
40083967
//
4009-
emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const
3968+
emitAttr emitter::emitGetMemOpSize(instrDesc* id, bool ignoreEmbeddedBroadcast) const
40103969
{
40113970
ssize_t memSize = 0;
40123971

@@ -4022,7 +3981,7 @@ emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const
40223981
else if (tupleType == INS_TT_FULL)
40233982
{
40243983
// Embedded broadcast supported, so either loading scalar or full vector
4025-
if (id->idIsEvexbContextSet())
3984+
if (id->idIsEvexbContextSet() && !ignoreEmbeddedBroadcast)
40263985
{
40273986
memSize = GetInputSizeInBytes(id);
40283987
}
@@ -4044,7 +4003,7 @@ emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const
40444003
{
40454004
memSize = 16;
40464005
}
4047-
else if (id->idIsEvexbContextSet())
4006+
else if (id->idIsEvexbContextSet() && !ignoreEmbeddedBroadcast)
40484007
{
40494008
memSize = GetInputSizeInBytes(id);
40504009
}
@@ -4056,7 +4015,7 @@ emitAttr emitter::emitGetBaseMemOpSize(instrDesc* id) const
40564015
else if (tupleType == INS_TT_HALF)
40574016
{
40584017
// Embedded broadcast supported, so either loading scalar or half vector
4059-
if (id->idIsEvexbContextSet())
4018+
if (id->idIsEvexbContextSet() && !ignoreEmbeddedBroadcast)
40604019
{
40614020
memSize = GetInputSizeInBytes(id);
40624021
}

src/coreclr/jit/emitxarch.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -10987,7 +10987,7 @@ void emitter::emitDispEmbBroadcastCount(instrDesc* id) const
1098710987
return;
1098810988
}
1098910989
ssize_t baseSize = GetInputSizeInBytes(id);
10990-
ssize_t vectorSize = (ssize_t)emitGetBaseMemOpSize(id);
10990+
ssize_t vectorSize = (ssize_t)emitGetMemOpSize(id, /* ignoreEmbeddedBroadcast */ true);
1099110991
printf(" {1to%d}", vectorSize / baseSize);
1099210992
}
1099310993

src/coreclr/jit/gentree.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -20933,6 +20933,13 @@ GenTree* Compiler::gtNewSimdBinOpNode(
2093320933
std::swap(op1, op2);
2093420934
#endif // TARGET_XARCH
2093520935
}
20936+
#ifdef TARGET_XARCH
20937+
if (HWIntrinsicInfo::NeedsNormalizeSmallTypeToInt(intrinsic) && varTypeIsSmall(simdBaseType))
20938+
{
20939+
simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UINT : CORINFO_TYPE_INT;
20940+
simdBaseType = JitType2PreciseVarType(simdBaseJitType);
20941+
}
20942+
#endif // TARGET_XARCH
2093620943
return gtNewSimdHWIntrinsicNode(type, op1, op2, intrinsic, simdBaseJitType, simdSize);
2093720944
}
2093820945

@@ -25691,6 +25698,15 @@ GenTree* Compiler::gtNewSimdTernaryLogicNode(var_types type,
2569125698
intrinsic = NI_AVX512F_VL_TernaryLogic;
2569225699
}
2569325700

25701+
#ifdef TARGET_XARCH
25702+
assert(HWIntrinsicInfo::NeedsNormalizeSmallTypeToInt(intrinsic));
25703+
if (varTypeIsSmall(simdBaseType))
25704+
{
25705+
simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UINT : CORINFO_TYPE_INT;
25706+
simdBaseType = JitType2PreciseVarType(simdBaseJitType);
25707+
}
25708+
#endif // TARGET_XARCH
25709+
2569425710
return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, op4, intrinsic, simdBaseJitType, simdSize);
2569525711
}
2569625712
#endif // TARGET_XARCH

src/coreclr/jit/gentree.h

+14
Original file line numberDiff line numberDiff line change
@@ -6667,6 +6667,20 @@ struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic
66676667

66686668
bool ShouldConstantProp(GenTree* operand, GenTreeVecCon* vecCon);
66696669

6670+
void NormalizeJitBaseTypeToInt(NamedIntrinsic id, var_types simdBaseType)
6671+
{
6672+
assert(varTypeIsSmall(simdBaseType));
6673+
6674+
if (varTypeIsUnsigned(simdBaseType))
6675+
{
6676+
SetSimdBaseJitType(CORINFO_TYPE_UINT);
6677+
}
6678+
else
6679+
{
6680+
SetSimdBaseJitType(CORINFO_TYPE_UINT);
6681+
}
6682+
}
6683+
66706684
private:
66716685
void SetHWIntrinsicId(NamedIntrinsic intrinsicId);
66726686

src/coreclr/jit/hwintrinsic.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,13 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic,
18181818
if (simdBaseJitType != CORINFO_TYPE_UNDEF)
18191819
{
18201820
simdBaseType = JitType2PreciseVarType(simdBaseJitType);
1821+
#ifdef TARGET_XARCH
1822+
if (HWIntrinsicInfo::NeedsNormalizeSmallTypeToInt(intrinsic) && varTypeIsSmall(simdBaseType))
1823+
{
1824+
simdBaseJitType = varTypeIsUnsigned(simdBaseType) ? CORINFO_TYPE_UINT : CORINFO_TYPE_INT;
1825+
simdBaseType = JitType2PreciseVarType(simdBaseJitType);
1826+
}
1827+
#endif // TARGET_XARCH
18211828
}
18221829

18231830
const unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig);

src/coreclr/jit/hwintrinsic.h

+9
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ enum HWIntrinsicFlag : unsigned int
227227

228228
// The intrinsic is an embedded masking compatible intrinsic
229229
HW_Flag_EmbMaskingCompatible = 0x10000000,
230+
231+
// The base type of this intrinsic needs to be normalized to int/uint unless it is long/ulong.
232+
HW_Flag_NormalizeSmallTypeToInt = 0x20000000,
230233
#elif defined(TARGET_ARM64)
231234

232235
// The intrinsic has an enum operand. Using this implies HW_Flag_HasImmediateOperand.
@@ -755,6 +758,12 @@ struct HWIntrinsicInfo
755758
HWIntrinsicFlag flags = lookupFlags(id);
756759
return (flags & HW_Flag_MaybeMemoryStore) != 0;
757760
}
761+
762+
static bool NeedsNormalizeSmallTypeToInt(NamedIntrinsic id)
763+
{
764+
HWIntrinsicFlag flags = lookupFlags(id);
765+
return (flags & HW_Flag_NormalizeSmallTypeToInt) != 0;
766+
}
758767
#endif
759768

760769
static bool NoJmpTableImm(NamedIntrinsic id)

src/coreclr/jit/hwintrinsiccodegenxarch.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
186186
// We need to validate that other phases of the compiler haven't introduced unsupported intrinsics
187187
assert(compiler->compIsaSupportedDebugOnly(isa));
188188
assert(HWIntrinsicInfo::RequiresCodegen(intrinsicId));
189+
assert(!HWIntrinsicInfo::NeedsNormalizeSmallTypeToInt(intrinsicId) || !varTypeIsSmall(node->GetSimdBaseType()));
189190

190191
bool isTableDriven = genIsTableDrivenHWIntrinsic(intrinsicId, category);
191192
insOpts instOptions = INS_OPTS_NONE;

0 commit comments

Comments
 (0)