fix dup instruction result to no longer reference the original memory in WASM (#5784)
fix dup instruction result to no longer reference the original memory added additional dup test cases
This commit is contained in:
Родитель
932f1d0788
Коммит
832b86f068
|
@ -239,7 +239,7 @@ namespace Internal.IL
|
|||
/// Create a new copy of current entry.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the same type as the current entry.</returns>
|
||||
public abstract StackEntry Duplicate();
|
||||
public abstract StackEntry Duplicate(LLVMBuilderRef builder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -298,7 +298,7 @@ namespace Internal.IL
|
|||
}
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new Int32ConstantEntry(Value, Type);
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ namespace Internal.IL
|
|||
{
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new Int64ConstantEntry(Value, Type);
|
||||
}
|
||||
|
@ -397,7 +397,7 @@ namespace Internal.IL
|
|||
return LLVM.ConstReal(type, Value);
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new FloatConstantEntry(Value, Type);
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ namespace Internal.IL
|
|||
RawLLVMValue = llvmValue;
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new ExpressionEntry(Kind, Name, RawLLVMValue, Type);
|
||||
}
|
||||
|
@ -449,9 +449,9 @@ namespace Internal.IL
|
|||
{
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type);
|
||||
return new ExpressionEntry(Kind, "duplicate_" + Name, ILImporter.LoadValue(builder, RawLLVMValue, Type, ILImporter.GetLLVMTypeForTypeDesc(Type), false, "load_duplicate_" + Name), Type);
|
||||
}
|
||||
|
||||
protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
|
||||
|
@ -472,9 +472,9 @@ namespace Internal.IL
|
|||
{
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type);
|
||||
return new AddressExpressionEntry(Kind, Name, RawLLVMValue, Type);
|
||||
}
|
||||
|
||||
protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
|
||||
|
@ -501,7 +501,7 @@ namespace Internal.IL
|
|||
IsVirtual = isVirtual;
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new FunctionPointerEntry(Name, Method, RawLLVMValue, Type, IsVirtual);
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ namespace Internal.IL
|
|||
LdToken = token;
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new LdTokenEntry<T>(Kind, Name, LdToken, RawLLVMValue, Type);
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ namespace Internal.IL
|
|||
{
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -576,7 +576,7 @@ namespace Internal.IL
|
|||
return ILImporter.CastIfNecessary(builder, value, type);
|
||||
}
|
||||
|
||||
public override StackEntry Duplicate()
|
||||
public override StackEntry Duplicate(LLVMBuilderRef builder)
|
||||
{
|
||||
return new SpilledExpressionEntry(Kind, Name, Type, LocalIndex, _importer);
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ namespace Internal.IL
|
|||
int n = entryStack.Length;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
_stack.Push(entryStack[i].Duplicate());
|
||||
_stack.Push(entryStack[i].Duplicate(_builder));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,19 +365,19 @@ namespace Internal.IL
|
|||
LLVM.BuildStore(_builder, CastToTypeDesc(value, type), CastToPointerToTypeDesc(address, type));
|
||||
}
|
||||
|
||||
internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend)
|
||||
internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend, string loadName = null)
|
||||
{
|
||||
var underlyingSourceType = sourceType.UnderlyingType;
|
||||
if (targetType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind && underlyingSourceType.IsPrimitive && !underlyingSourceType.IsPointer)
|
||||
{
|
||||
var sourceLLVMType = ILImporter.GetLLVMTypeForTypeDesc(underlyingSourceType);
|
||||
var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(sourceLLVMType, 0));
|
||||
return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, "ldvalue"), targetType, signExtend);
|
||||
return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, loadName ?? "ldvalue"), targetType, signExtend);
|
||||
}
|
||||
else
|
||||
{
|
||||
var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(targetType, 0));
|
||||
return LLVM.BuildLoad(builder, typedAddress, "ldvalue");
|
||||
return LLVM.BuildLoad(builder, typedAddress, loadName ?? "ldvalue");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,7 +836,9 @@ namespace Internal.IL
|
|||
|
||||
private void ImportDup()
|
||||
{
|
||||
_stack.Push(_stack.Peek().Duplicate());
|
||||
var entry = _stack.Pop();
|
||||
_stack.Push(entry.Duplicate(_builder));
|
||||
_stack.Push(entry.Duplicate(_builder));
|
||||
}
|
||||
|
||||
private void ImportPop()
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
<ProjectReference Include="CpObj.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<IlcArg Include="-r:$(IntermediateOutputPath)\CpObj.dll" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
|
||||
<ProjectReference Include="ILHelpers.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<IlcArg Include="-r:$(IntermediateOutputPath)\ILHelpers.dll" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
.assembly extern mscorlib
|
||||
{
|
||||
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
|
||||
.ver 4:0:0:0
|
||||
}
|
||||
|
||||
.assembly extern System.Private.CoreLib
|
||||
{
|
||||
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
|
||||
.ver 4:0:0:0
|
||||
}
|
||||
|
||||
.assembly ILHelpers { }
|
||||
|
||||
.class public ILHelpers.ILHelpersTest
|
||||
{
|
||||
.method public static void EatArgs(string, object)
|
||||
{
|
||||
ret
|
||||
}
|
||||
|
||||
.method public static void EatArg(object)
|
||||
{
|
||||
ret
|
||||
}
|
||||
//this is copied from the test case for https://github.com/dotnet/coreclr/issues/14784
|
||||
//its been adapted to remove the requirement for Console.WriteLine because thats not supported in WASM
|
||||
//it can be removed once we have support for Console.WriteLine and can run the CoreCLR tests
|
||||
.method public static int32 InlineAssignByte()
|
||||
{
|
||||
.locals init (
|
||||
int8 local,
|
||||
object b
|
||||
)
|
||||
ldstr "InlineAssignByte"
|
||||
ldc.i4 300
|
||||
dup
|
||||
stloc.0
|
||||
box int32
|
||||
stloc.1
|
||||
ldloc.1
|
||||
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
|
||||
ldstr "InlineAssignByte"
|
||||
ldloc.0
|
||||
box int32
|
||||
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
|
||||
ldloc.1
|
||||
//after the unboxing and truncation on the way in ensure that we can subtract 200 and end up with the expected 100 return value
|
||||
unbox.any int32
|
||||
ldc.i4 200
|
||||
sub
|
||||
ret
|
||||
}
|
||||
.method public static int32 DupTest(int32&)
|
||||
{
|
||||
.locals init (
|
||||
int32 local,
|
||||
int32 local2
|
||||
)
|
||||
ldarg.0
|
||||
//push a bunch of entries onto the stack using dup, we will consume them through the rest of this method
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
//first off lets ensure the passed parameter was pointing to an int of less than 10 (it should be 9)
|
||||
ldind.i4
|
||||
ldc.i4 10
|
||||
clt
|
||||
brtrue target
|
||||
//this is just trying to mess with the stack accross basic block boundries
|
||||
//it should actually leave the evaluation stack unchanged in the end
|
||||
pop
|
||||
dup
|
||||
//make sure we can deref one of our duplicate int refs and box it without any trouble
|
||||
target: ldind.i4
|
||||
box int32
|
||||
call void ILHelpers.ILHelpersTest::EatArg(object)
|
||||
//deref one of our duplicates and add 1 to it, this should not write back to the parameter it should only be stored in the local
|
||||
ldind.i4
|
||||
ldc.i4 1
|
||||
add
|
||||
stloc.0
|
||||
//load one of our duplicates and add 200 to it, we're eventually going to return this value and test for it in the caller
|
||||
ldind.i4
|
||||
ldc.i4 200
|
||||
add
|
||||
//this should write back into the parameter
|
||||
stind.i4
|
||||
ldloc.0
|
||||
dup
|
||||
add
|
||||
dup
|
||||
stloc.1
|
||||
ldloc.0
|
||||
ceq
|
||||
//if the added value equals the source value we've got something writing to its original StackEntry instead of a dup
|
||||
brtrue failure
|
||||
ldind.i4
|
||||
ret
|
||||
failure:
|
||||
pop
|
||||
ldc.i4 0
|
||||
ret
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<DebugType>portable</DebugType>
|
||||
<OutputPath>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutputPath>
|
||||
<IntermediateOutputPath>$(MSBuildProjectDirectory)\obj\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="ILHelpers.il" />
|
||||
<PackageReference Include="Microsoft.NETCore.App">
|
||||
<Version>$(MicrosoftNETCoreAppPackageVersion)</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
|
@ -17,12 +17,31 @@ internal static class Program
|
|||
{
|
||||
Add(1, 2);
|
||||
int tempInt = 0;
|
||||
int tempInt2 = 0;
|
||||
(*(&tempInt)) = 9;
|
||||
if(tempInt == 9)
|
||||
{
|
||||
PrintLine("Hello from C#!");
|
||||
}
|
||||
|
||||
int* targetAddr = (tempInt > 0) ? (&tempInt2) : (&tempInt);
|
||||
|
||||
(*targetAddr) = 1;
|
||||
if(tempInt2 == 1 && tempInt == 9)
|
||||
{
|
||||
PrintLine("basic block stack entry Test: Ok.");
|
||||
}
|
||||
|
||||
if(ILHelpers.ILHelpersTest.InlineAssignByte() == 100)
|
||||
{
|
||||
PrintLine("Inline assign byte Test: Ok.");
|
||||
}
|
||||
|
||||
if(ILHelpers.ILHelpersTest.DupTest(ref tempInt) == 209 && tempInt == 209)
|
||||
{
|
||||
PrintLine("dup test: Ok.");
|
||||
}
|
||||
|
||||
TestClass tempObj = new TestDerivedClass(1337);
|
||||
tempObj.TestMethod("Hello");
|
||||
tempObj.TestVirtualMethod("Hello");
|
||||
|
@ -159,6 +178,10 @@ internal static class Program
|
|||
arrayTest[1].Value = "Array load/store test: Ok.";
|
||||
PrintLine(arrayTest[1].Value);
|
||||
|
||||
int ii = 0;
|
||||
arrayTest[ii++].Value = "dup ref test: Ok.";
|
||||
PrintLine(arrayTest[0].Value);
|
||||
|
||||
var largeArrayTest = new long[] { Int64.MaxValue, 0, Int64.MinValue, 0 };
|
||||
if(largeArrayTest[0] == Int64.MaxValue &&
|
||||
largeArrayTest[1] == 0 &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче