Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Wasm: add support for ovf op with char type (#8257)
Browse files Browse the repository at this point in the history
* add support for ovf op with char type

* use stack kind for 32/64 switching and for asserts
  • Loading branch information
yowl authored Aug 11, 2020
1 parent f542d97 commit 127405d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 14 deletions.
37 changes: 23 additions & 14 deletions src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -820,12 +820,6 @@ private void ImportLoadVar(int index, bool argument)
PushLoadExpression(GetStackValueKind(type), (argument ? "arg" : "loc") + index + "_", typedLoadLocation, type);
}

private LLVMValueRef LoadTemp(int index)
{
LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type);
return _builder.BuildLoad(CastToPointerToTypeDesc(address, type, $"Temp{index}_"), $"LdTemp{index}_");
}

internal LLVMValueRef LoadTemp(int index, LLVMTypeRef asType)
{
LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type);
Expand Down Expand Up @@ -3814,8 +3808,8 @@ private void ImportBinaryOperation(ILOpcode opcode)
break;

case ILOpcode.add_ovf:
Debug.Assert(type.Category == TypeFlags.Int32 || type.Category == TypeFlags.Int64);
if (type.Category == TypeFlags.Int32)
Debug.Assert(CanPerformSignedOverflowOperations(op1.Kind));
if (Is32BitStackValue(op1.Kind))
{
BuildAddOverflowChecksForSize(ref AddOvf32Function, left, right, LLVMTypeRef.Int32, BuildConstInt32(int.MaxValue), BuildConstInt32(int.MinValue), true);
}
Expand All @@ -3827,8 +3821,8 @@ private void ImportBinaryOperation(ILOpcode opcode)
result = _builder.BuildAdd(left, right, "add");
break;
case ILOpcode.add_ovf_un:
Debug.Assert(type.Category == TypeFlags.UInt32 || type.Category == TypeFlags.Int32 || type.Category == TypeFlags.UInt64 || type.Category == TypeFlags.Int64 || type.Category == TypeFlags.Pointer);
if (type.Category == TypeFlags.UInt32 || type.Category == TypeFlags.Int32 || type.Category == TypeFlags.Pointer)
Debug.Assert(CanPerformUnsignedOverflowOperations(op1.Kind));
if (Is32BitStackValue(op1.Kind))
{
BuildAddOverflowChecksForSize(ref AddOvfUn32Function, left, right, LLVMTypeRef.Int32, BuildConstUInt32(uint.MaxValue), BuildConstInt32(0), false);
}
Expand All @@ -3840,8 +3834,8 @@ private void ImportBinaryOperation(ILOpcode opcode)
result = _builder.BuildAdd(left, right, "add");
break;
case ILOpcode.sub_ovf:
Debug.Assert(type.Category == TypeFlags.Int32 || type.Category == TypeFlags.Int64);
if (type.Category == TypeFlags.Int32)
Debug.Assert(CanPerformSignedOverflowOperations(op1.Kind));
if (Is32BitStackValue(op1.Kind))
{
BuildSubOverflowChecksForSize(ref SubOvf32Function, left, right, LLVMTypeRef.Int32, BuildConstInt32(int.MaxValue), BuildConstInt32(int.MinValue), true);
}
Expand All @@ -3853,8 +3847,8 @@ private void ImportBinaryOperation(ILOpcode opcode)
result = _builder.BuildSub(left, right, "sub");
break;
case ILOpcode.sub_ovf_un:
Debug.Assert(type.Category == TypeFlags.UInt32 || type.Category == TypeFlags.Int32 || type.Category == TypeFlags.UInt64 || type.Category == TypeFlags.Int64 || type.Category == TypeFlags.Pointer);
if (type.Category == TypeFlags.UInt32 || type.Category == TypeFlags.Int32 || type.Category == TypeFlags.Pointer)
Debug.Assert(CanPerformUnsignedOverflowOperations(op1.Kind));
if (Is32BitStackValue(op1.Kind))
{
BuildSubOverflowChecksForSize(ref SubOvfUn32Function, left, right, LLVMTypeRef.Int32, BuildConstUInt32(uint.MaxValue), BuildConstInt32(0), false);
}
Expand Down Expand Up @@ -3885,6 +3879,21 @@ private void ImportBinaryOperation(ILOpcode opcode)
PushExpression(kind, "binop", result, type);
}

bool CanPerformSignedOverflowOperations(StackValueKind kind)
{
return kind == StackValueKind.Int32 || kind == StackValueKind.Int64;
}

bool CanPerformUnsignedOverflowOperations(StackValueKind kind)
{
return CanPerformSignedOverflowOperations(kind) || kind == StackValueKind.ByRef ||
kind == StackValueKind.ObjRef || kind == StackValueKind.NativeInt;
}

bool Is32BitStackValue(StackValueKind kind)
{
return kind == StackValueKind.Int32 || kind == StackValueKind.ByRef || kind == StackValueKind.ObjRef || kind == StackValueKind.NativeInt;
}

LLVMValueRef StartOverflowCheckFunction(LLVMTypeRef sizeTypeRef, bool signed,
string throwFuncName, out LLVMValueRef leftOp, out LLVMValueRef rightOp, out LLVMBuilderRef builder, out LLVMBasicBlockRef elseBlock,
Expand Down
17 changes: 17 additions & 0 deletions tests/src/Simple/HelloWasm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,8 @@ private static unsafe bool CkFinite64(ulong value)

static void TestIntOverflows()
{
TestCharInOvf();

TestSignedIntAddOvf();

TestSignedLongAddOvf();
Expand Down Expand Up @@ -2329,6 +2331,21 @@ private static void TestSignedLongAddOvf()
EndTest(true);
}

private static void TestCharInOvf()
{
// Just checks the compiler can handle the char type
// This was failing for https://github.com/dotnet/corert/blob/f542d97f26e87f633310e67497fb01dad29987a5/src/System.Private.CoreLib/shared/System/Environment.Unix.cs#L111
StartTest("Test char add overflows");
char opChar = '1';
int op32r = 2;
if (checked(opChar + op32r) != 51)
{
FailTest("No overflow for char failed"); // check not always throwing an exception
return;
}
PassTest();
}

private static void TestSignedIntAddOvf()
{
StartTest("Test int add overflows");
Expand Down

0 comments on commit 127405d

Please sign in to comment.