Skip to content
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

Crossgen2: Support HVA for ARM64 #35576

Merged
merged 2 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 7 additions & 6 deletions src/coreclr/src/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
// If the argType is a struct, then check if it is an HFA
if (varTypeIsStruct(argType))
{
// hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF.
// hfaType is set to float, double, or SIMD type if it is an HFA, otherwise TYP_UNDEF
hfaType = GetHfaType(typeHnd);
isHfaArg = varTypeIsValidHfaType(hfaType);
}
Expand All @@ -643,9 +643,9 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)

if (isHfaArg)
{
// We have an HFA argument, so from here on out treat the type as a float, double or vector.
// The orginal struct type is available by using origArgType
// We also update the cSlots to be the number of float/double fields in the HFA
// We have an HFA argument, so from here on out treat the type as a float, double, or vector.
// The orginal struct type is available by using origArgType.
// We also update the cSlots to be the number of float/double/vector fields in the HFA.
argType = hfaType;
varDsc->SetHfaType(hfaType);
cSlots = varDsc->lvHfaSlots();
Expand Down Expand Up @@ -2614,10 +2614,11 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool
}
#endif // FEATURE_SIMD
#ifdef FEATURE_HFA
// for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
// For structs that are small enough, we check and set HFA element type
if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
{
var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
// hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF
var_types hfaType = GetHfaType(typeHnd);
if (varTypeIsValidHfaType(hfaType))
{
varDsc->SetHfaType(hfaType);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/jit/regalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc
}
else
{
assert(!regState->rsIsFloat);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could miss this check due to the break below, then fail later in an unexpected way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @dotnet/jit-contrib

unsigned cSlots = argDsc->lvSize() / TARGET_POINTER_SIZE;
for (unsigned i = 1; i < cSlots; i++)
{
Expand All @@ -183,7 +184,6 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc
{
break;
}
assert(regState->rsIsFloat == false);
regState->rsCalleeRegArgMaskLiveIn |= genRegMask(nextArgReg);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,17 @@ public override bool ComputeContainsGCPointers(DefType type)

public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
{
return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type);
}

public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
{
return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type);
if (type.Context.Target.Architecture == TargetArchitecture.ARM64)
{
return type.InstanceFieldSize.AsInt switch
{
8 => ValueTypeShapeCharacteristics.Vector64Aggregate,
16 => ValueTypeShapeCharacteristics.Vector128Aggregate,
32 => ValueTypeShapeCharacteristics.Vector256Aggregate,
_ => ValueTypeShapeCharacteristics.None
};
}
return ValueTypeShapeCharacteristics.None;
}

public static bool IsVectorType(DefType type)
Expand All @@ -104,7 +109,8 @@ public static bool IsVectorType(DefType type)
type.Namespace == "System.Runtime.Intrinsics" &&
(type.Name == "Vector64`1" ||
type.Name == "Vector128`1" ||
type.Name == "Vector256`1");
type.Name == "Vector256`1") &&
type.Instantiation[0].IsPrimitive;
}
}
}
28 changes: 20 additions & 8 deletions src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ private enum ImageFileMachine

private ExceptionDispatchInfo _lastException;

[DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] // stdcall in CoreCLR!
[DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)] // stdcall in CoreCLR!
private extern static IntPtr jitStartup(IntPtr host);

[DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)]
[DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)]
private extern static IntPtr getJit();

[DllImport(JitSupportLibrary)]
Expand All @@ -79,7 +79,7 @@ private static CorInfoImpl GetThis(IntPtr thisHandle)
}

[DllImport(JitSupportLibrary)]
private extern static CorJitResult JitCompileMethod(out IntPtr exception,
private extern static CorJitResult JitCompileMethod(out IntPtr exception,
IntPtr jit, IntPtr thisHandle, IntPtr callbacks,
ref CORINFO_METHOD_INFO info, uint flags, out IntPtr nativeEntry, out uint codeSize);

Expand Down Expand Up @@ -492,7 +492,7 @@ private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool

if (method.IsArrayAddressMethod())
hasHiddenParameter = true;

// We only populate sigInst for intrinsic methods because most of the time,
// JIT doesn't care what the instantiation is and this is expensive.
Instantiation owningTypeInst = method.OwningType.Instantiation;
Expand Down Expand Up @@ -1237,7 +1237,7 @@ private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls)
*namespaceName = null;
return null;
}

private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index)
{
TypeDesc type = HandleToObject(cls);
Expand Down Expand Up @@ -1690,7 +1690,7 @@ private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_M
// This optimization may cause static fields in reference types to be accessed without cctor being triggered
// for NULL "this" object. It does not conform with what the spec says. However, we have been historically
// doing it for perf reasons.
if (!typeToInit.IsValueType && ! typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit)
if (!typeToInit.IsValueType && !typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit)
{
if (typeToInit == typeFromContext(context) || typeToInit == MethodBeingCompiled.OwningType)
{
Expand Down Expand Up @@ -2014,7 +2014,7 @@ private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls)
{
var td = HandleToObject(cls) as ArrayType;
Debug.Assert(td != null);
return (uint) td.Rank;
return (uint)td.Rank;
}

private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size)
Expand Down Expand Up @@ -2204,7 +2204,19 @@ private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_ST
private CorInfoType getHFAType(CORINFO_CLASS_STRUCT_* hClass)
{
var type = (DefType)HandleToObject(hClass);
return type.IsHfa ? asCorInfoType(type.HfaElementType) : CorInfoType.CORINFO_TYPE_UNDEF;

// For 8-byte vectors return CORINFO_TYPE_DOUBLE, which is mapped by JIT to SIMD8.
// Otherwise, return CORINFO_TYPE_VALUECLASS, which is mapped by JIT to SIMD16.
// See MethodTable::GetHFAType and Compiler::GetHfaType.
return (type.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
{
ValueTypeShapeCharacteristics.Float32Aggregate => CorInfoType.CORINFO_TYPE_FLOAT,
ValueTypeShapeCharacteristics.Float64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE,
ValueTypeShapeCharacteristics.Vector64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE,
ValueTypeShapeCharacteristics.Vector128Aggregate => CorInfoType.CORINFO_TYPE_VALUECLASS,
ValueTypeShapeCharacteristics.Vector256Aggregate => CorInfoType.CORINFO_TYPE_VALUECLASS,
_ => CorInfoType.CORINFO_TYPE_UNDEF
};
}

private HRESULT GetErrorHRESULT(_EXCEPTION_POINTERS* pExceptionPointers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,52 +281,51 @@ public LayoutInt ThreadGcStaticFieldAlignment
}
}

/// <summary>
/// Gets a value indicating whether the fields of the type satisfy the Homogeneous Float Aggregate classification.
/// </summary>
public bool IsHfa
public ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics))
{
ComputeValueTypeShapeCharacteristics();
}
return (_valueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.HomogenousFloatAggregate) != 0;
return _valueTypeShapeCharacteristics;
}
}

internal ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics
private void ComputeValueTypeShapeCharacteristics()
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics))
{
ComputeValueTypeShapeCharacteristics();
}
return _valueTypeShapeCharacteristics;
}
_valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this);
_fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics);
}

/// <summary>
/// Get the Homogeneous Float Aggregate element type if this is a HFA type (<see cref="IsHfa"/> is true).
/// Gets a value indicating whether the type is a homogeneous floating-point or short-vector aggregate.
/// </summary>
public DefType HfaElementType
public bool IsHomogeneousAggregate
{
get
{
// We are not caching this because this is rare and not worth wasting space in DefType.
return this.Context.GetLayoutAlgorithmForType(this).ComputeHomogeneousFloatAggregateElementType(this);
return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) != 0;
}
}

private void ComputeValueTypeShapeCharacteristics()
/// <summary>
/// If the type is a homogeneous floating-point or short-vector aggregate, returns its element size.
/// </summary>
public int GetHomogeneousAggregateElementSize()
{
_valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this);
_fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics);
return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
{
ValueTypeShapeCharacteristics.Float32Aggregate => 4,
ValueTypeShapeCharacteristics.Float64Aggregate => 8,
ValueTypeShapeCharacteristics.Vector64Aggregate => 8,
ValueTypeShapeCharacteristics.Vector128Aggregate => 16,
ValueTypeShapeCharacteristics.Vector256Aggregate => 16,
_ => throw new InvalidOperationException()
};
}


public void ComputeInstanceLayout(InstanceLayoutKind layoutKind)
{
if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,10 @@ public abstract class FieldLayoutAlgorithm
public abstract bool ComputeContainsGCPointers(DefType type);

/// <summary>
/// Compute the shape of a valuetype. The shape information is used to control code generation and allocation
/// (such as vectorization, passing the valuetype by value across method calls, or boxing alignment).
/// Compute the shape of a value type. The shape information is used to control code generation and allocation
/// (such as vectorization, passing the value type by value across method calls, or boxing alignment).
/// </summary>
public abstract ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type);

/// <summary>
/// If the type has <see cref="ValueTypeShapeCharacteristics.HomogenousFloatAggregate"/> characteristic, returns
/// the element type of the homogenous float aggregate. This will either be System.Double or System.Float.
/// </summary>
public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type);
}

/// <summary>
Expand Down Expand Up @@ -119,8 +113,43 @@ public enum ValueTypeShapeCharacteristics
None = 0x00,

/// <summary>
/// The structure is an aggregate of floating point values of the same type.
/// The type is an aggregate of 32-bit floating-point values.
/// </summary>
Float32Aggregate = 0x01,

/// <summary>
/// The type is an aggregate of 64-bit floating-point values.
/// </summary>
Float64Aggregate = 0x02,

/// <summary>
/// The type is an aggregate of 64-bit short-vector values.
/// </summary>
Vector64Aggregate = 0x04,

/// <summary>
/// The type is an aggregate of 128-bit short-vector values.
/// </summary>
Vector128Aggregate = 0x08,

/// <summary>
/// The type is an aggregate of 256-bit short-vector values.
/// </summary>
Vector256Aggregate = 0x10,

/// <summary>
/// The mask for homogeneous aggregates of floating-point values.
/// </summary>
FloatingPointAggregateMask = Float32Aggregate | Float64Aggregate,

/// <summary>
/// The mask for homogeneous aggregates of short-vector values.
/// </summary>
ShortVectorAggregateMask = Vector64Aggregate | Vector128Aggregate | Vector256Aggregate,

/// <summary>
/// The mask for homogeneous aggregates.
/// </summary>
HomogenousFloatAggregate = 0x01,
AggregateMask = FloatingPointAggregateMask | ShortVectorAggregateMask,
}
}
Loading