Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.
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
102 changes: 92 additions & 10 deletions src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,7 @@ private void ImportStoreVar(int index, bool argument)
TypeDesc varType;
StackEntry toStore = _stack.Pop();
LLVMValueRef varAddress = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out varType);
CastingStore(varAddress, toStore, varType, $"Variable{index}_");
CastingStore(varAddress, toStore, varType, false, $"Variable{index}_");
}

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

private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType, string targetName = null)
private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType, bool withGCBarrier, string targetName = null)
{
var typedStoreLocation = CastToPointerToTypeDesc(address, targetType, targetName);
_builder.BuildStore(value.ValueAsType(targetType, _builder), typedStoreLocation);
if (withGCBarrier && targetType.IsGCPointer)
{
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef", new StackEntry[]
{
new ExpressionEntry(StackValueKind.Int32, "address", address), value
});
}
else
{
var typedStoreLocation = CastToPointerToTypeDesc(address, targetType, targetName);
var llvmValue = value.ValueAsType(targetType, _builder);
if (withGCBarrier && IsStruct(targetType))
{
StoreStruct(address, llvmValue, targetType, typedStoreLocation);
}
else
{
_builder.BuildStore(llvmValue, typedStoreLocation);
}
}
}

private static bool IsStruct(TypeDesc typeDesc)
{
return typeDesc.IsValueType && !typeDesc.IsPrimitive && !typeDesc.IsEnum;
}

private void StoreStruct(LLVMValueRef address, LLVMValueRef llvmValue, TypeDesc targetType, LLVMValueRef typedStoreLocation, bool childStruct = false)
{
// TODO: if this is used for anything multithreaded, this foreach and the subsequent BuildStore are susceptible to a race condition
foreach (FieldDesc f in targetType.GetFields())
{
if (f.IsStatic) continue;
if (IsStruct(f.FieldType) && llvmValue.TypeOf.IsPackedStruct)
{
LLVMValueRef targetAddress = _builder.BuildGEP(address, new[] { BuildConstInt32(f.Offset.AsInt) });
uint index = LLVMSharpInterop.ElementAtOffset(_compilation.TargetData, llvmValue.TypeOf, (ulong)f.Offset.AsInt);
LLVMValueRef fieldValue = _builder.BuildExtractValue(llvmValue, index);
//recurse into struct
StoreStruct(targetAddress, fieldValue, f.FieldType, CastToPointerToTypeDesc(targetAddress, f.FieldType), true);
}
else if (f.FieldType.IsGCPointer)
{
LLVMValueRef targetAddress = _builder.BuildGEP(address, new[] {BuildConstInt32(f.Offset.AsInt)});
LLVMValueRef fieldValue;
if (llvmValue.TypeOf.IsPackedStruct)
{
uint index = LLVMSharpInterop.ElementAtOffset(_compilation.TargetData, llvmValue.TypeOf, (ulong) f.Offset.AsInt);
fieldValue = _builder.BuildExtractValue(llvmValue, index);
Debug.Assert(fieldValue.TypeOf.Kind == LLVMTypeKind.LLVMPointerTypeKind, "expected an LLVM pointer type");
}
else
{
// single field IL structs are not LLVM structs
fieldValue = llvmValue;
}
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef",
new StackEntry[]
{
new ExpressionEntry(StackValueKind.Int32, "targetAddress", targetAddress),
new ExpressionEntry(StackValueKind.ObjRef, "sourceAddress", fieldValue)
});
}
}
if (!childStruct)
{
_builder.BuildStore(llvmValue, typedStoreLocation); // just copy all the fields again for simplicity, if all the fields were set using RhpAssignRef then a possible optimisation would be to skip this line
}
}

private LLVMValueRef CastIfNecessary(LLVMValueRef source, LLVMTypeRef valueType, string name = null, bool unsigned = false)
Expand Down Expand Up @@ -3578,7 +3644,6 @@ private void ImportLoadIndirect(TypeDesc type)
{
var pointer = _stack.Pop();
Debug.Assert(pointer is ExpressionEntry || pointer is ConstantEntry);
var expressionPointer = pointer as ExpressionEntry;
if (type == null)
{
type = GetWellKnownType(WellKnownType.Object);
Expand All @@ -3600,19 +3665,36 @@ private void ImportStoreIndirect(TypeDesc type)
StackEntry destinationPointer = _stack.Pop();
LLVMValueRef typedValue;
LLVMValueRef typedPointer;
bool requireWriteBarrier;

if (type != null)
{
typedValue = value.ValueAsType(type, _builder);
typedPointer = destinationPointer.ValueAsType(type.MakePointerType(), _builder);
typedValue = value.ValueAsType(type, _builder);
if (IsStruct(type))
{
StoreStruct(typedPointer, typedValue, type, typedPointer);
return;
}
requireWriteBarrier = type.IsGCPointer;
}
else
{
typedPointer = destinationPointer.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int32, 0), _builder);
typedValue = value.ValueAsInt32(_builder, false);
requireWriteBarrier = (value is ExpressionEntry) && !((ExpressionEntry)value).RawLLVMValue.IsNull && value.Type.IsGCPointer;
}
if (requireWriteBarrier)
{
CallRuntime(_method.Context, "InternalCalls", "RhpAssignRef", new StackEntry[]
{
new ExpressionEntry(StackValueKind.Int32, "typedPointer", typedPointer), value
});
}
else
{
_builder.BuildStore(typedValue, typedPointer);
}

_builder.BuildStore(typedValue, typedPointer);
}

private void ImportBinaryOperation(ILOpcode opcode)
Expand Down Expand Up @@ -4720,7 +4802,7 @@ private void ImportStoreField(int token, bool isStatic)
StackEntry valueEntry = _stack.Pop();

LLVMValueRef fieldAddress = GetFieldAddress(runtimeDeterminedField, field, isStatic);
CastingStore(fieldAddress, valueEntry, field.FieldType);
CastingStore(fieldAddress, valueEntry, field.FieldType, true);
}

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

private void ImportLoadLength()
Expand Down
15 changes: 15 additions & 0 deletions src/ILCompiler.WebAssembly/src/CodeGen/LLVMSharpInterop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using LLVMSharp.Interop;

namespace Internal.IL
{
/// <summary>
/// Workaround while waiting for https://github.com/microsoft/LLVMSharp/pull/141
/// </summary>
internal class LLVMSharpInterop
{
internal static unsafe uint ElementAtOffset(LLVMTargetDataRef targetDataRef, LLVMTypeRef structTypeRef, ulong offset)
{
return LLVM.ElementAtOffset(targetDataRef, structTypeRef, offset);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class WebAssemblyCodegenCompilation : Compilation
{
internal WebAssemblyCodegenConfigProvider Options { get; }
internal LLVMModuleRef Module { get; }
internal LLVMTargetDataRef TargetData { get; }
public new WebAssemblyCodegenNodeFactory NodeFactory { get; }
internal LLVMDIBuilderRef DIBuilder { get; }
internal Dictionary<string, DebugMetadata> DebugMetadataMap { get; }
Expand All @@ -32,7 +33,7 @@ internal WebAssemblyCodegenCompilation(
{
NodeFactory = nodeFactory;
LLVMModuleRef m = LLVMModuleRef.CreateWithName("netscripten");
m.Target = "wasm32-unknown-unknown-wasm";
m.Target = "wasm32-unknown-emscripten";
// https://llvm.org/docs/LangRef.html#langref-datalayout
// e litte endian, mangled names
// m:e ELF mangling
Expand All @@ -41,8 +42,8 @@ internal WebAssemblyCodegenCompilation(
// n:32:64 native widths
// S128 natural alignment of stack
m.DataLayout = "e-m:e-p:32:32-i64:64-n32:64-S128";
Module = m;

Module = m;
TargetData = m.CreateExecutionEngine().TargetData;
Options = options;
DIBuilder = Module.CreateDIBuilder();
DebugMetadataMap = new Dictionary<string, DebugMetadata>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
</Compile>
<Compile Include="CodeGen\DebugMetadata.cs" />
<Compile Include="CodeGen\ILToWebAssemblyImporter_Statics.cs" />
<Compile Include="CodeGen\LLVMSharpInterop.cs" />
<Compile Include="CodeGen\WebAssemblyObjectWriter.cs" />
<Compile Include="Compiler\DependencyAnalysis\EHInfoNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\RawMainMethodRootProvider.cs" />
Expand Down
Loading