Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ var_types ABIPassingSegment::GetRegisterType() const
{
switch (Size)
{
case 2:
return TYP_HALF;
case 4:
return TYP_FLOAT;
case 8:
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7359,7 +7359,7 @@ bool CodeGen::isStructReturn(GenTree* treeNode)
}

#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
assert(!varTypeIsStruct(treeNode));
assert(!varTypeIsStruct(treeNode) || treeNode->TypeGet() == TYP_HALF);
Comment thread
tannergooding marked this conversation as resolved.
return false;
#else
return varTypeIsStruct(treeNode) && (m_compiler->info.compRetNativeType == TYP_STRUCT);
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6063,7 +6063,7 @@ void CodeGen::genCall(GenTreeCall* call)
}
else
#endif // TARGET_X86
if (varTypeIsFloating(returnType))
if (varTypeIsFloating(returnType) || returnType == TYP_HALF)
Comment thread
tannergooding marked this conversation as resolved.
{
returnReg = REG_FLOATRET;
}
Expand Down Expand Up @@ -6158,7 +6158,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
}
else
{
assert(!varTypeIsStruct(call));
assert(!varTypeIsStruct(call) || call->TypeIs(TYP_HALF));

if (call->TypeIs(TYP_REF))
{
Expand Down Expand Up @@ -8346,7 +8346,7 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
}
#endif // defined(TARGET_X86) && defined(FEATURE_SIMD)

if (varTypeIsSIMD(targetType))
if (varTypeIsSIMD(targetType) || targetType == TYP_HALF)
{
regNumber srcReg = genConsumeReg(source);
assert((srcReg != REG_NA) && (genIsValidFloatReg(srcReg)));
Expand Down
28 changes: 27 additions & 1 deletion src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,32 @@ bool Compiler::isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd)
return strcmp(typeName, "CLong") == 0 || strcmp(typeName, "CULong") == 0 || strcmp(typeName, "NFloat") == 0;
}

bool Compiler::isNativeHalfStructType(CORINFO_CLASS_HANDLE clsHnd)
{
#if defined(TARGET_XARCH)
if (!isIntrinsicType(clsHnd))
{
return false;
}
const char* namespaceName = nullptr;
const char* typeName = getClassNameFromMetadata(clsHnd, &namespaceName);

if (strcmp(namespaceName, "System") != 0)
{
return false;
}

if (strcmp(typeName, "Half") != 0)
{
return false;
}
Comment thread
anthonycanino marked this conversation as resolved.
Outdated

return compOpportunisticallyDependsOn(InstructionSet_AVX10v1);
#else
return false;
#endif
}
Comment thread
tannergooding marked this conversation as resolved.

//-----------------------------------------------------------------------------
// getPrimitiveTypeForStruct:
// Get the "primitive" type that is used for a struct
Expand Down Expand Up @@ -651,7 +677,7 @@ var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS
break;

case 2:
useType = TYP_USHORT;
useType = isNativeHalfStructType(clsHnd) ? TYP_HALF : TYP_USHORT;
Comment thread
tannergooding marked this conversation as resolved.
break;

#if !defined(TARGET_XARCH) || defined(UNIX_AMD64_ABI)
Expand Down
11 changes: 10 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4725,6 +4725,11 @@ class Compiler

NamedIntrinsic lookupPrimitiveFloatNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName);
NamedIntrinsic lookupPrimitiveIntNamedIntrinsic(CORINFO_METHOD_HANDLE method, const char* methodName);

NamedIntrinsic lookupHalfIntrinsic(NamedIntrinsic ni);
NamedIntrinsic lookupHalfConversionIntrinsic(var_types fromType, var_types toType);
int lookupHalfRoundingMode(NamedIntrinsic ni);

GenTree* impUnsupportedNamedIntrinsic(unsigned helper,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
Expand Down Expand Up @@ -5925,6 +5930,7 @@ class Compiler
// Returns true if the provided type should be treated as a primitive type
// for the unmanaged calling conventions.
bool isNativePrimitiveStructType(CORINFO_CLASS_HANDLE clsHnd);
bool isNativeHalfStructType(CORINFO_CLASS_HANDLE clsHnd);

enum structPassingKind
{
Expand Down Expand Up @@ -9973,8 +9979,11 @@ class Compiler

// Use to determine if a struct *might* be a SIMD type. As this function only takes a size, many
// structs will fit the criteria.
bool structSizeMightRepresentSIMDType(size_t structSize)
bool structSizeMightRepresentAcceleratedType(size_t structSize)
{
if (structSize == 2)
return true;
Comment thread
kg marked this conversation as resolved.

#ifdef FEATURE_SIMD
return (structSize >= getMinVectorByteLength()) && (structSize <= getMaxVectorByteLength());
Comment thread
tannergooding marked this conversation as resolved.
#else
Expand Down
14 changes: 8 additions & 6 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -2031,18 +2031,20 @@ class emitter

#define PERFSCORE_THROUGHPUT_ZERO 0.0f // Only used for pseudo-instructions that don't generate code

#define PERFSCORE_THROUGHPUT_9X (1.0f / 9.0f)
#define PERFSCORE_THROUGHPUT_6X (1.0f / 6.0f) // Hextuple issue
#define PERFSCORE_THROUGHPUT_5X 0.20f // Pentuple issue
#define PERFSCORE_THROUGHPUT_4X 0.25f // Quad issue
#define PERFSCORE_THROUGHPUT_3X (1.0f / 3.0f) // Three issue
#define PERFSCORE_THROUGHPUT_2X 0.5f // Dual issue
#define PERFSCORE_THROUGHPUT_9X (1.0f / 9.0f)
#define PERFSCORE_THROUGHPUT_6X (1.0f / 6.0f) // Hextuple issue
#define PERFSCORE_THROUGHPUT_5X 0.20f // Pentuple issue
#define PERFSCORE_THROUGHPUT_4X 0.25f // Quad issue
#define PERFSCORE_THROUGHPUT_3X (1.0f / 3.0f) // Three issue
#define PERFSCORE_THROUGHPUT_2X 0.5f // Dual issue
#define PERFSCORE_THROUGHPUT_1P5X 0.67f // Dual issue

#define PERFSCORE_THROUGHPUT_1C 1.0f // Single Issue

#define PERFSCORE_THROUGHPUT_2C 2.0f // slower - 2 cycles
#define PERFSCORE_THROUGHPUT_3C 3.0f // slower - 3 cycles
#define PERFSCORE_THROUGHPUT_4C 4.0f // slower - 4 cycles
#define PERFSCORE_THROUGHPUT_4P5C 4.5f // slower - 4.5 cycles
#define PERFSCORE_THROUGHPUT_5C 5.0f // slower - 5 cycles
#define PERFSCORE_THROUGHPUT_6C 6.0f // slower - 6 cycles
#define PERFSCORE_THROUGHPUT_7C 7.0f // slower - 7 cycles
Expand Down
120 changes: 109 additions & 11 deletions src/coreclr/jit/emitxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ bool emitter::Is3OpRmwInstruction(instruction ins)
return ((ins >= FIRST_FMA_INSTRUCTION) && (ins <= LAST_FMA_INSTRUCTION)) ||
(IsAVXVNNIFamilyInstruction(ins)) ||
((ins >= FIRST_AVX512BMM_INSTRUCTION) && (ins <= LAST_AVX512BMM_INSTRUCTION)) ||
((ins >= FIRST_AVXIFMA_INSTRUCTION) && (ins <= LAST_AVXIFMA_INSTRUCTION));
((ins >= FIRST_AVXIFMA_INSTRUCTION) && (ins <= LAST_AVXIFMA_INSTRUCTION)) ||
((ins >= FIRST_AVX10V1_FMA_INSTR) && (ins <= LAST_AVX10V1_FMA_INSTR));
}
}
}
Expand Down Expand Up @@ -3076,9 +3077,9 @@ emitter::code_t emitter::emitExtractEvexPrefix(instruction ins, code_t& code) co
}
// Now the byte in the 22 position should be either of the below:
// 1. An escape byte 0F (For isa before AVX10.2)
// 2. A map number from 0 to 7 (For AVX10.2 and above)
// 2. A map number from 0 to 7 (For AVX10.1 and above)
leadingBytes = check;
assert((leadingBytes == 0x0F) || ((m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v2) ||
assert((leadingBytes == 0x0F) || ((m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v1) ||
Comment thread
anthonycanino marked this conversation as resolved.
(m_compiler->compIsaSupportedDebugOnly(InstructionSet_APX))) &&
(leadingBytes >= 0x00) && (leadingBytes <= 0x07)));

Expand Down Expand Up @@ -3161,14 +3162,15 @@ emitter::code_t emitter::emitExtractEvexPrefix(instruction ins, code_t& code) co

case 0x05:
{
assert(m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v2));
assert(m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v1));
evexPrefix |= (0x05 << 16);
break;
}

case 0x06:
{
assert(m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX512BMM));
assert(m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX512BMM) ||
m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v1));
evexPrefix |= (0x6 << 16);
break;
}
Expand Down Expand Up @@ -5396,10 +5398,8 @@ UNATIVE_OFFSET emitter::emitInsSizeAM(instrDesc* id, code_t code)

assert((attrSize == EA_4BYTE) || (attrSize == EA_PTRSIZE) // Only for x64
|| (attrSize == EA_16BYTE) || (attrSize == EA_32BYTE) || (attrSize == EA_64BYTE) // only for x64
|| (ins == INS_movzx) || (ins == INS_movsx) ||
(ins == INS_cmpxchg)
// kmov instructions reach this path with EA_8BYTE size, even on x86
Comment thread
anthonycanino marked this conversation as resolved.
|| IsKMOVInstruction(ins)
Comment thread
anthonycanino marked this conversation as resolved.
|| (ins == INS_movzx) || (ins == INS_movsx) || (ins == INS_vmovsh) || (ins == INS_cmpxchg) ||
IsKMOVInstruction(ins)
// The prefetch instructions are always 3 bytes and have part of their modr/m byte hardcoded
|| isPrefetch(ins));

Expand Down Expand Up @@ -7432,6 +7432,7 @@ bool emitter::IsMovInstruction(instruction ins)
case INS_kmovw_gpr:
case INS_kmovd_gpr:
case INS_kmovq_gpr:
case INS_vmovsh:
{
return true;
}
Expand Down Expand Up @@ -7630,6 +7631,13 @@ bool emitter::HasSideEffect(instruction ins, emitAttr size)
break;
}

case INS_vmovsh:
{
// Clears the upper bits
hasSideEffect = true;
break;
}

default:
{
unreached();
Expand Down Expand Up @@ -7903,6 +7911,12 @@ bool emitter::emitIns_Mov(
break;
}

case INS_vmovsh:
{
assert(isFloatReg(dstReg) && isFloatReg(srcReg));
break;
}

default:
{
unreached();
Expand Down Expand Up @@ -11805,6 +11819,10 @@ const char* emitter::emitRegName(regNumber reg, emitAttr attr, bool varName) con

case EA_2BYTE:
{
if (IsXMMReg(reg))
{
return emitXMMregName(reg);
}
Comment thread
anthonycanino marked this conversation as resolved.
#if defined(TARGET_AMD64)
if (reg > REG_RDI)
{
Expand Down Expand Up @@ -14530,7 +14548,7 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
// Is this a 'big' opcode?
else if (code & 0xFF000000)
{
if (size == EA_2BYTE)
if (size == EA_2BYTE && ins != INS_vmovsh)
{
assert(ins == INS_movbe);

Expand Down Expand Up @@ -15398,7 +15416,7 @@ BYTE* emitter::emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
// Is this a 'big' opcode?
else if (code & 0xFF000000)
{
if (size == EA_2BYTE)
if (size == EA_2BYTE && !IsSimdInstruction(ins))
Comment thread
anthonycanino marked this conversation as resolved.
{
assert(ins == INS_movbe);

Expand Down Expand Up @@ -20954,6 +20972,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
case INS_movss:
case INS_movsd_simd:
case INS_movddup:
case INS_vmovsh:
{
if (memAccessKind == PERFSCORE_MEMORY_NONE)
{
Expand Down Expand Up @@ -21394,6 +21413,85 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
break;
}

case INS_vaddsh:
case INS_vsubsh:
case INS_vmulsh:
case INS_vfmadd213sh:
case INS_vmaxsh:
case INS_vminsh:
case INS_vcvtsh2ss:
{
result.insLatency = PERFSCORE_LATENCY_4C;
result.insThroughput = PERFSCORE_THROUGHPUT_2X;
break;
}

case INS_vdivsh:
{
result.insLatency = PERFSCORE_LATENCY_14C;
result.insThroughput = PERFSCORE_THROUGHPUT_4C;
break;
}

case INS_vsqrtsh:
{
result.insLatency = PERFSCORE_LATENCY_14C;
result.insThroughput = PERFSCORE_THROUGHPUT_4P5C;
break;
}

case INS_vrsqrtsh:
case INS_vcomish:
case INS_vucomish:
case INS_vrcpsh:
{
result.insLatency = PERFSCORE_LATENCY_4C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;
}

case INS_vrndscalesh:
{
result.insLatency = PERFSCORE_LATENCY_8C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;
}

case INS_vcvtss2sh:
{
result.insLatency = PERFSCORE_LATENCY_6C;
result.insThroughput = PERFSCORE_THROUGHPUT_1P5X;
break;
}

case INS_vcvtsd2sh:
{
result.insLatency = PERFSCORE_THROUGHPUT_ILLEGAL;
result.insThroughput = PERFSCORE_THROUGHPUT_ILLEGAL;
break;
}
Comment thread
tannergooding marked this conversation as resolved.

case INS_vcvtsh2sd:
{
result.insLatency = PERFSCORE_LATENCY_10C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;
}

case INS_vcvtsi2sh32:
case INS_vcvtsi2sh64:
case INS_vcvtsh2si32:
case INS_vcvtsh2si64:
case INS_vcvtusi2sh32:
case INS_vcvtusi2sh64:
case INS_vcvtsh2usi32:
case INS_vcvtsh2usi64:
{
result.insLatency = PERFSCORE_LATENCY_7C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;
}

default:
{
assert((unsigned)ins < ArrLen(insThroughputInfos));
Expand Down
19 changes: 19 additions & 0 deletions src/coreclr/jit/float16.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

/*****************************************************************************
Both simd.cpp, gentree.cpp, and utils.cpp need a definition of float16_t
but do not share a common header.

Defining here so as to not create accidental implicit include dependencies.
This definition can be removed once .NET moves to C++23 support.
******************************************************************************/

#ifndef _FLOAT16_H_
#define _FLOAT16_H_

#include <cstdint>

typedef uint16_t float16_t;

#endif // _FLOAT16_H_
Loading
Loading