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

Commit 6fdbe26

Browse files
committed
Add calls to RhpAssignRef
1 parent bb212a9 commit 6fdbe26

File tree

5 files changed

+339
-20
lines changed

5 files changed

+339
-20
lines changed

src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ private void ImportStoreVar(int index, bool argument)
10721072
TypeDesc varType;
10731073
StackEntry toStore = _stack.Pop();
10741074
LLVMValueRef varAddress = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out varType);
1075-
CastingStore(varAddress, toStore, varType, $"Variable{index}_");
1075+
CastingStore(varAddress, toStore, varType, false, $"Variable{index}_");
10761076
}
10771077

10781078
private void ImportStoreHelper(LLVMValueRef toStore, LLVMTypeRef valueType, LLVMValueRef basePtr, uint offset, string name = null, LLVMBuilderRef builder = default(LLVMBuilderRef))
@@ -1104,10 +1104,75 @@ private LLVMValueRef CastToPointerToTypeDesc(LLVMValueRef source, TypeDesc type,
11041104
return CastIfNecessary(source, LLVMTypeRef.CreatePointer(GetLLVMTypeForTypeDesc(type), 0), (name ?? "") + type.ToString());
11051105
}
11061106

1107-
private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType, string targetName = null)
1107+
private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType, bool withBarrier, string targetName = null)
11081108
{
1109-
var typedStoreLocation = CastToPointerToTypeDesc(address, targetType, targetName);
1110-
_builder.BuildStore(value.ValueAsType(targetType, _builder), typedStoreLocation);
1109+
if (withBarrier && targetType.IsGCPointer)
1110+
{
1111+
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef", new StackEntry[]
1112+
{
1113+
new ExpressionEntry(StackValueKind.Int32, "address", address), value
1114+
});
1115+
}
1116+
else
1117+
{
1118+
var typedStoreLocation = CastToPointerToTypeDesc(address, targetType, targetName);
1119+
var llvmValue = value.ValueAsType(targetType, _builder);
1120+
if (withBarrier && IsStruct(targetType))
1121+
{
1122+
StoreStruct(address, llvmValue, targetType, typedStoreLocation);
1123+
}
1124+
else
1125+
{
1126+
_builder.BuildStore(llvmValue, typedStoreLocation);
1127+
}
1128+
}
1129+
}
1130+
1131+
private static bool IsStruct(TypeDesc typeDesc)
1132+
{
1133+
return typeDesc.IsValueType && !typeDesc.IsPrimitive && !typeDesc.IsEnum;
1134+
}
1135+
1136+
private void StoreStruct(LLVMValueRef address, LLVMValueRef llvmValue, TypeDesc targetType, LLVMValueRef typedStoreLocation, bool childStruct = false)
1137+
{
1138+
foreach (FieldDesc f in targetType.GetFields())
1139+
{
1140+
if (f.IsStatic) continue;
1141+
if (IsStruct(f.FieldType) && llvmValue.TypeOf.IsPackedStruct)
1142+
{
1143+
LLVMValueRef targetAddress = _builder.BuildGEP(address, new[] { BuildConstInt32(f.Offset.AsInt) });
1144+
uint index = LLVMSharpInterop.ElementAtOffset(_compilation.TargetData, llvmValue.TypeOf, (ulong)f.Offset.AsInt);
1145+
LLVMValueRef fieldValue = _builder.BuildExtractValue(llvmValue, index);
1146+
//recurse into struct
1147+
StoreStruct(targetAddress, fieldValue, f.FieldType, CastToPointerToTypeDesc(targetAddress, f.FieldType), true);
1148+
}
1149+
else if (f.FieldType.IsGCPointer)
1150+
{
1151+
LLVMValueRef targetAddress = _builder.BuildGEP(address, new[] {BuildConstInt32(f.Offset.AsInt)});
1152+
LLVMValueRef fieldValue;
1153+
if (llvmValue.TypeOf.IsPackedStruct)
1154+
{
1155+
uint index = LLVMSharpInterop.ElementAtOffset(_compilation.TargetData, llvmValue.TypeOf, (ulong) f.Offset.AsInt);
1156+
fieldValue = _builder.BuildExtractValue(llvmValue, index);
1157+
Debug.Assert(fieldValue.TypeOf.Kind == LLVMTypeKind.LLVMPointerTypeKind, "expected an LLVM pointer type");
1158+
}
1159+
else
1160+
{
1161+
// single field IL structs are not LLVM structs
1162+
fieldValue = llvmValue;
1163+
}
1164+
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef",
1165+
new StackEntry[]
1166+
{
1167+
new ExpressionEntry(StackValueKind.Int32, "targetAddress", targetAddress),
1168+
new ExpressionEntry(StackValueKind.ObjRef, "sourceAddress", fieldValue)
1169+
});
1170+
}
1171+
}
1172+
if (!childStruct)
1173+
{
1174+
_builder.BuildStore(llvmValue, typedStoreLocation); // just copy all the fields again for simplicity, if all the fields where set using RhpAssignRef then a possible optimisation would be to skip this line
1175+
}
11111176
}
11121177

11131178
private LLVMValueRef CastIfNecessary(LLVMValueRef source, LLVMTypeRef valueType, string name = null, bool unsigned = false)
@@ -3578,7 +3643,6 @@ private void ImportLoadIndirect(TypeDesc type)
35783643
{
35793644
var pointer = _stack.Pop();
35803645
Debug.Assert(pointer is ExpressionEntry || pointer is ConstantEntry);
3581-
var expressionPointer = pointer as ExpressionEntry;
35823646
if (type == null)
35833647
{
35843648
type = GetWellKnownType(WellKnownType.Object);
@@ -3600,19 +3664,36 @@ private void ImportStoreIndirect(TypeDesc type)
36003664
StackEntry destinationPointer = _stack.Pop();
36013665
LLVMValueRef typedValue;
36023666
LLVMValueRef typedPointer;
3667+
bool requireWriteBarrier;
36033668

36043669
if (type != null)
36053670
{
3606-
typedValue = value.ValueAsType(type, _builder);
36073671
typedPointer = destinationPointer.ValueAsType(type.MakePointerType(), _builder);
3672+
typedValue = value.ValueAsType(type, _builder);
3673+
if (IsStruct(type))
3674+
{
3675+
StoreStruct(typedPointer, typedValue, type, typedPointer);
3676+
return;
3677+
}
3678+
requireWriteBarrier = type.IsGCPointer;
36083679
}
36093680
else
36103681
{
36113682
typedPointer = destinationPointer.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int32, 0), _builder);
36123683
typedValue = value.ValueAsInt32(_builder, false);
3684+
requireWriteBarrier = (value is ExpressionEntry) && !((ExpressionEntry)value).RawLLVMValue.IsNull && value.Type.IsGCPointer;
3685+
}
3686+
if (requireWriteBarrier)
3687+
{
3688+
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef", new StackEntry[]
3689+
{
3690+
new ExpressionEntry(StackValueKind.Int32, "typedPointer", typedPointer), value
3691+
});
3692+
}
3693+
else
3694+
{
3695+
_builder.BuildStore(typedValue, typedPointer);
36133696
}
3614-
3615-
_builder.BuildStore(typedValue, typedPointer);
36163697
}
36173698

36183699
private void ImportBinaryOperation(ILOpcode opcode)
@@ -4720,7 +4801,7 @@ private void ImportStoreField(int token, bool isStatic)
47204801
StackEntry valueEntry = _stack.Pop();
47214802

47224803
LLVMValueRef fieldAddress = GetFieldAddress(runtimeDeterminedField, field, isStatic);
4723-
CastingStore(fieldAddress, valueEntry, field.FieldType);
4804+
CastingStore(fieldAddress, valueEntry, field.FieldType, true);
47244805
}
47254806

47264807
// Loads symbol address. Address is represented as a i32*
@@ -4936,7 +5017,7 @@ private void ImportStoreElement(TypeDesc elementType)
49365017
StackEntry arrayReference = _stack.Pop();
49375018
var nullSafeElementType = elementType ?? GetWellKnownType(WellKnownType.Object);
49385019
LLVMValueRef elementAddress = GetElementAddress(index.ValueAsInt32(_builder, true), arrayReference.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), _builder), nullSafeElementType);
4939-
CastingStore(elementAddress, value, nullSafeElementType);
5020+
CastingStore(elementAddress, value, nullSafeElementType, true);
49405021
}
49415022

49425023
private void ImportLoadLength()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using LLVMSharp.Interop;
2+
3+
namespace Internal.IL
4+
{
5+
/// <summary>
6+
/// Workaround while waiting for https://github.com/microsoft/LLVMSharp/pull/141
7+
/// </summary>
8+
internal class LLVMSharpInterop
9+
{
10+
internal static unsafe uint ElementAtOffset(LLVMTargetDataRef targetDataRef, LLVMTypeRef structTypeRef, ulong offset)
11+
{
12+
return LLVM.ElementAtOffset(targetDataRef, structTypeRef, offset);
13+
}
14+
}
15+
}

src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilation.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public sealed class WebAssemblyCodegenCompilation : Compilation
1717
{
1818
internal WebAssemblyCodegenConfigProvider Options { get; }
1919
internal LLVMModuleRef Module { get; }
20+
internal LLVMTargetDataRef TargetData { get; }
2021
public new WebAssemblyCodegenNodeFactory NodeFactory { get; }
2122
internal LLVMDIBuilderRef DIBuilder { get; }
2223
internal Dictionary<string, DebugMetadata> DebugMetadataMap { get; }
@@ -32,7 +33,7 @@ internal WebAssemblyCodegenCompilation(
3233
{
3334
NodeFactory = nodeFactory;
3435
LLVMModuleRef m = LLVMModuleRef.CreateWithName("netscripten");
35-
m.Target = "wasm32-unknown-unknown-wasm";
36+
m.Target = "wasm32-unknown-emscripten";
3637
// https://llvm.org/docs/LangRef.html#langref-datalayout
3738
// e litte endian, mangled names
3839
// m:e ELF mangling
@@ -41,8 +42,8 @@ internal WebAssemblyCodegenCompilation(
4142
// n:32:64 native widths
4243
// S128 natural alignment of stack
4344
m.DataLayout = "e-m:e-p:32:32-i64:64-n32:64-S128";
44-
Module = m;
45-
45+
Module = m;
46+
TargetData = m.CreateExecutionEngine().TargetData;
4647
Options = options;
4748
DIBuilder = Module.CreateDIBuilder();
4849
DebugMetadataMap = new Dictionary<string, DebugMetadata>();

src/ILCompiler.WebAssembly/src/ILCompiler.WebAssembly.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
</Compile>
4141
<Compile Include="CodeGen\DebugMetadata.cs" />
4242
<Compile Include="CodeGen\ILToWebAssemblyImporter_Statics.cs" />
43+
<Compile Include="CodeGen\LLVMSharpInterop.cs" />
4344
<Compile Include="CodeGen\WebAssemblyObjectWriter.cs" />
4445
<Compile Include="Compiler\DependencyAnalysis\EHInfoNode.cs" />
4546
<Compile Include="Compiler\DependencyAnalysis\RawMainMethodRootProvider.cs" />

0 commit comments

Comments
 (0)