Skip to content

Commit

Permalink
NativeAOT-LLVM: cast unsigned ints to floats using uitofp (#1994)
Browse files Browse the repository at this point in the history
* if the source is an unsigned int, then make the cast unsigned

* u4 should be unsigned

* widen small ints before conv

* add boolean to widening check (and a couple of more tests).
  • Loading branch information
yowl authored Oct 1, 2022
1 parent d852365 commit 6629e07
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ private void ImportBasicBlock(BasicBlock basicBlock)
ImportConvert(WellKnownType.Double, false, false);
break;
case ILOpcode.conv_u4:
ImportConvert(WellKnownType.UInt32, false, false);
ImportConvert(WellKnownType.UInt32, false, true);
break;
case ILOpcode.conv_u8:
ImportConvert(WellKnownType.UInt64, false, true);
Expand Down Expand Up @@ -825,7 +825,7 @@ private void ImportBasicBlock(BasicBlock basicBlock)
ImportStoreIndirect(WellKnownType.IntPtr);
break;
case ILOpcode.conv_u:
ImportConvert(WellKnownType.UIntPtr, false, false);
ImportConvert(WellKnownType.UIntPtr, false, true);
break;
case ILOpcode.prefix1:
opCode = (ILOpcode)(0x100 + ReadILByte());
Expand Down
19 changes: 14 additions & 5 deletions src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/ILToLLVMImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,8 +1227,9 @@ internal static LLVMValueRef CastIfNecessary(LLVMBuilderRef builder, LLVMValueRe
}
else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && (valueTypeKind == LLVMTypeKind.LLVMDoubleTypeKind || valueTypeKind == LLVMTypeKind.LLVMFloatTypeKind))
{
//TODO: keep track of the TypeDesc so we can call BuildUIToFP when the integer is unsigned
typedToStore = builder.BuildSIToFP(source, valueType, "CastSIToFloat" + (name ?? ""));
typedToStore = unsigned
? builder.BuildUIToFP(source, valueType, "CastUIToFloat" + (name ?? ""))
: builder.BuildSIToFP(source, valueType, "CastSIToFloat" + (name ?? ""));
}
else if ((toStoreKind == LLVMTypeKind.LLVMDoubleTypeKind || toStoreKind == LLVMTypeKind.LLVMFloatTypeKind) &&
valueTypeKind == LLVMTypeKind.LLVMIntegerTypeKind)
Expand Down Expand Up @@ -4026,27 +4027,35 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool
{
//TODO checkOverflow - r_un & r_4, i & i_un
StackEntry value = _stack.Pop();
TypeDesc stackType = value.Type;

TypeDesc destType = GetWellKnownType(wellKnownType);

// Load the value and then convert it instead of using ValueAsType to avoid loading the incorrect size
LLVMValueRef loadedValue = value.ValueAsType(value.Type, _builder);
LLVMValueRef widenedStackValue = CastIfNecessary(loadedValue, GetLLVMTypeForTypeDesc(WidenBytesAndShorts(value.Type)), value.Name(),
stackType.IsWellKnownType(WellKnownType.Boolean) ||
stackType.IsWellKnownType(WellKnownType.Byte) ||
stackType.IsWellKnownType(WellKnownType.UInt16) ||
stackType.IsWellKnownType(WellKnownType.UInt32)
);

ExpressionEntry expressionEntry;
if (checkOverflow)
{
Debug.Assert(destType is EcmaType);
if (IsLlvmReal(loadedValue.TypeOf))
{
expressionEntry = BuildConvOverflowFromReal(value, loadedValue, (EcmaType)destType, wellKnownType, unsigned, value.Type);
expressionEntry = BuildConvOverflowFromReal(value, widenedStackValue, (EcmaType)destType, wellKnownType, unsigned, value.Type);
}
else
{
expressionEntry = BuildConvOverflow(value.Name(), loadedValue, (EcmaType)destType, wellKnownType, unsigned, value.Type);
expressionEntry = BuildConvOverflow(value.Name(), widenedStackValue, (EcmaType)destType, wellKnownType, unsigned, value.Type);
}
}
else
{
LLVMValueRef converted = CastIfNecessary(loadedValue, GetLLVMTypeForTypeDesc(destType), value.Name(), wellKnownType == WellKnownType.UInt64 /* unsigned is always false, so check for the type explicitly */);
LLVMValueRef converted = CastIfNecessary(widenedStackValue, GetLLVMTypeForTypeDesc(destType), value.Name(), unsigned);
expressionEntry = new ExpressionEntry(GetStackValueKind(destType), "conv", converted, destType);
}
_stack.Push(expressionEntry);
Expand Down
25 changes: 25 additions & 0 deletions src/tests/nativeaot/SmokeTests/HelloWasm/HelloWasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ private static unsafe int Main(string[] args)
PrintLine(((BoxStubTest[])arrayCastingTest)[2].Value);
EndTest(!(arrayCastingTest is CastingTestClass[]));

ConvUTest();

CastByteForIndex();

ldindTest();
Expand Down Expand Up @@ -1081,6 +1083,29 @@ private static void IntToStringTest()
EndTest(intString == "42");
}

private static void ConvUTest()
{
StartTest("Implicit casting using ConvU");
byte alpha = 0xFF;
float f = alpha / 255f;
if (f != 1f)
{
FailTest("Expected 1f but didn't get it"); // TODO: float.ToString() is failing in DiyFP
}

byte msbByte = 0xff;
nuint nativeUnsignedFromByte = msbByte;
if (nativeUnsignedFromByte != 0xff)
{
FailTest($"Expected 0xff but got {nativeUnsignedFromByte}");
return;
}

ushort msbUshort = 0x8000;
nuint nativeUnsignedFromUshort = msbUshort;
EndTest(nativeUnsignedFromUshort == 0x8000, $"Expected 0x8000 but got {nativeUnsignedFromUshort}");
}

private static void CastByteForIndex()
{
StartTest("Implicit casting of byte for an index");
Expand Down

0 comments on commit 6629e07

Please sign in to comment.