Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Nattress <nattress@gmail.com>2017-01-21 11:54:07 +0300
committerMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2017-01-21 11:54:07 +0300
commitb580dd08744ee43d22b1adb59b674dafbb2f0e30 (patch)
treec07b760c280d747908ab2385ae09d20c05a311a5
parent972e86c243974d49047328b0dccd72eb44ca493a (diff)
X86 and Arm assembly emitters (#2555)
Port the emitter code for X86 and Arm, allowing unbox stub generation for those architectures.
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs17
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs13
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs8
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Relocation.cs10
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs62
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMInitialInterfaceDispatchStubNode.cs49
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMNodeFactory.cs27
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs22
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs22
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMUnboxingStubNode.cs17
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/Register.cs37
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs35
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs33
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/Register.cs29
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs35
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs155
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunGenericHelperNode.cs22
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunHelperNode.cs24
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86UnboxingStubNode.cs19
-rw-r--r--src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj15
20 files changed, 648 insertions, 3 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs
index df7322c46..930dfaff1 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs
@@ -34,11 +34,28 @@ namespace ILCompiler.DependencyAnalysis
x64Emitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
x64Emitter.Builder.DefinedSymbols.Add(this);
return x64Emitter.Builder.ToObjectData();
+
+ case TargetArchitecture.X86:
+ X86.X86Emitter x86Emitter = new X86.X86Emitter(factory);
+ EmitCode(factory, ref x86Emitter, relocsOnly);
+ x86Emitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
+ x86Emitter.Builder.DefinedSymbols.Add(this);
+ return x86Emitter.Builder.ToObjectData();
+
+ case TargetArchitecture.ARM:
+ ARM.ARMEmitter armEmitter = new ARM.ARMEmitter(factory);
+ EmitCode(factory, ref armEmitter, relocsOnly);
+ armEmitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
+ armEmitter.Builder.DefinedSymbols.Add(this);
+ return armEmitter.Builder.ToObjectData();
+
default:
throw new NotImplementedException();
}
}
protected abstract void EmitCode(NodeFactory factory, ref X64.X64Emitter instructionEncoder, bool relocsOnly);
+ protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly);
+ protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly);
}
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs
index 9ca9e4415..aad579a3b 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchCellNode.cs
@@ -42,9 +42,16 @@ namespace ILCompiler.DependencyAnalysis
// synchronization mechanism of the two values in the runtime.
objData.Alignment = _targetMethod.Context.Target.PointerSize * 2;
objData.DefinedSymbols.Add(this);
-
- objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch"));
-
+
+ if (factory.Target.Architecture == TargetArchitecture.ARM)
+ {
+ objData.EmitPointerReloc(factory.InitialInterfaceDispatchStub);
+ }
+ else
+ {
+ objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch"));
+ }
+
// The second cell field uses the two lower-order bits to communicate the contents.
// We add 1 to signal IDC_CachePointerIsInterfacePointer. See src\Native\Runtime\inc\rhbinder.h.
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(_targetMethod.OwningType), 1);
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs
index dcf5396b6..93abe65f5 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs
@@ -227,12 +227,20 @@ namespace ILCompiler.DependencyAnalysis
switch (relocType)
{
case RelocType.IMAGE_REL_BASED_REL32:
+ case RelocType.IMAGE_REL_BASED_RELPTR32:
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
+ case RelocType.IMAGE_REL_BASED_HIGHLOW:
+ case RelocType.IMAGE_REL_SECREL:
EmitInt(delta);
break;
case RelocType.IMAGE_REL_BASED_DIR64:
EmitLong(delta);
break;
+ case RelocType.IMAGE_REL_THUMB_BRANCH24:
+ case RelocType.IMAGE_REL_THUMB_MOV32:
+ // Do not vacate space for this kind of relocation, because
+ // the space is embedded in the instruction.
+ break;
default:
throw new NotImplementedException();
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Relocation.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Relocation.cs
index dfe96310a..645b7f505 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Relocation.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Relocation.cs
@@ -12,6 +12,14 @@ namespace ILCompiler.DependencyAnalysis
IMAGE_REL_BASED_HIGHLOW = 0x03,
IMAGE_REL_BASED_DIR64 = 0x0A,
IMAGE_REL_BASED_REL32 = 0x10,
+ IMAGE_REL_THUMB_MOV32 = 0x11, // Thumb2: MOVW/MOVT
+ IMAGE_REL_THUMB_BRANCH24 = 0x14, // Thumb2: B, BL
+
+ IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc
+ // This is a special NGEN-specific relocation type
+ // for relative pointer (used to make NGen relocation
+ // section smaller)
+ IMAGE_REL_SECREL = 0x80, // 32 bit offset from base of section containing target
}
public struct Relocation
{
@@ -51,6 +59,8 @@ namespace ILCompiler.DependencyAnalysis
case RelocType.IMAGE_REL_BASED_ABSOLUTE:
case RelocType.IMAGE_REL_BASED_HIGHLOW:
case RelocType.IMAGE_REL_BASED_REL32:
+ case RelocType.IMAGE_REL_BASED_RELPTR32:
+ case RelocType.IMAGE_REL_SECREL:
return *(int*)location;
case RelocType.IMAGE_REL_BASED_DIR64:
return *(long*)location;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs
new file mode 100644
index 000000000..0f59d1603
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs
@@ -0,0 +1,62 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+
+namespace ILCompiler.DependencyAnalysis.ARM
+{
+ public struct ARMEmitter
+ {
+ public ARMEmitter(NodeFactory factory)
+ {
+ Builder = new ObjectDataBuilder(factory);
+ TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem);
+ }
+
+ public ObjectDataBuilder Builder;
+ public TargetRegisterMap TargetRegister;
+
+ // add reg, immediate
+ public void EmitADD(Register reg, byte immediate)
+ {
+ Builder.EmitShort((short)(0x3000 + ((byte)reg << 8) + immediate));
+ }
+
+ // push reg
+ public void EmitPUSH(Register reg)
+ {
+ Builder.EmitByte(0x4d);
+ Builder.EmitByte(0xf8);
+ Builder.EmitShort((short)(0x0d04 + ((byte)reg << 12)));
+ }
+
+ // mov reg, reg
+ public void EmitMOV(Register destination, Register source)
+ {
+ Builder.EmitShort((short)(0x4600 + (((byte)destination & 0x8) << 4) + (((byte)source & 0x8) << 3) + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7)));
+ }
+
+ // mov reg, [reloc] & 0x0000FFFF
+ // movt reg, [reloc] & 0xFFFF0000
+ public void EmitMOV(Register destination, ISymbolNode symbol)
+ {
+ Builder.EmitReloc(symbol, RelocType.IMAGE_REL_THUMB_MOV32);
+ Builder.EmitShort(unchecked((short)0xf240));
+ Builder.EmitShort((short)((byte)destination << 8));
+ Builder.EmitShort(unchecked((short)0xf2c0));
+ Builder.EmitShort((short)((byte)destination << 8));
+ }
+
+ // b symbol
+ public void EmitJMP(ISymbolNode symbol)
+ {
+ Builder.EmitReloc(symbol, RelocType.IMAGE_REL_THUMB_BRANCH24);
+ Builder.EmitByte(0);
+ Builder.EmitByte(0xF0);
+ Builder.EmitByte(0);
+ Builder.EmitByte(0xB8);
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMInitialInterfaceDispatchStubNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMInitialInterfaceDispatchStubNode.cs
new file mode 100644
index 000000000..c34dfe9ec
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMInitialInterfaceDispatchStubNode.cs
@@ -0,0 +1,49 @@
+// 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.
+
+using Internal.Text;
+using System;
+
+using ILCompiler.DependencyAnalysis.ARM;
+using ILCompiler.DependencyAnalysis.X64;
+using ILCompiler.DependencyAnalysis.X86;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// On ARM, we use R12 to store the interface dispatch cell. However, the jump through the import address
+ /// table to call the runtime interface dispatch helper trashes R12. This stub pushes R12 before making
+ /// the runtime call. The ARM runtime interface dispatch code expects this and pops R12 to get the dispatch
+ /// cell.
+ /// </summary>
+ public partial class InitialInterfaceDispatchStubNode : AssemblyStubNode
+ {
+ protected override string GetName() => this.GetMangledName();
+
+ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(nameMangler.CompilationUnitPrefix).Append("_InitialInterfaceDispatchStub");
+ }
+
+ public override bool IsShareable => false;
+
+ protected override void EmitCode(NodeFactory factory, ref ARMEmitter instructionEncoder, bool relocsOnly)
+ {
+ instructionEncoder.EmitPUSH(ARM.Register.R12);
+ instructionEncoder.EmitMOV(ARM.Register.R12, factory.ExternSymbol("RhpInitialInterfaceDispatch"));
+ instructionEncoder.EmitMOV(ARM.Register.R15, ARM.Register.R12);
+ }
+
+ // Only ARM requires a stub
+ protected override void EmitCode(NodeFactory factory, ref X86Emitter instructionEncoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override void EmitCode(NodeFactory factory, ref X64Emitter instructionEncoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMNodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMNodeFactory.cs
new file mode 100644
index 000000000..4bf25f08b
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMNodeFactory.cs
@@ -0,0 +1,27 @@
+// 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.
+
+using System;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ public partial class NodeFactory
+ {
+ private InitialInterfaceDispatchStubNode _initialInterfaceDispatchStubNode;
+
+ public InitialInterfaceDispatchStubNode InitialInterfaceDispatchStub
+ {
+ get
+ {
+ if (_initialInterfaceDispatchStubNode == null)
+ {
+ _initialInterfaceDispatchStubNode = new InitialInterfaceDispatchStubNode();
+ }
+
+ return _initialInterfaceDispatchStubNode;
+ }
+ }
+
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs
new file mode 100644
index 000000000..df0916b44
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs
@@ -0,0 +1,22 @@
+// 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.
+
+using System;
+
+using ILCompiler.DependencyAnalysis.ARM;
+
+using Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ partial class ReadyToRunGenericHelperNode
+ {
+ protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs
new file mode 100644
index 000000000..afdf9bdeb
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs
@@ -0,0 +1,22 @@
+// 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.
+
+using System;
+
+using Internal.TypeSystem;
+
+using ILCompiler;
+using ILCompiler.DependencyAnalysis.ARM;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ // ARM specific portions of ReadyToRunHelperNode
+ partial class ReadyToRunHelperNode
+ {
+ protected override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMUnboxingStubNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMUnboxingStubNode.cs
new file mode 100644
index 000000000..99fd0dec3
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMUnboxingStubNode.cs
@@ -0,0 +1,17 @@
+// 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.
+
+using ILCompiler.DependencyAnalysis.ARM;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ public partial class UnboxingStubNode
+ {
+ protected override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly)
+ {
+ encoder.EmitADD(encoder.TargetRegister.Arg0, (byte)factory.Target.PointerSize); // add r0, sizeof(void*);
+ encoder.EmitJMP(factory.MethodEntrypoint(_target)); // b methodEntryPoint
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/Register.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/Register.cs
new file mode 100644
index 000000000..15213c752
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/Register.cs
@@ -0,0 +1,37 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ILCompiler.DependencyAnalysis.ARM
+{
+ public enum Register
+ {
+ R0 = 0,
+ R1 = 1,
+ R2 = 2,
+ R3 = 3,
+ R4 = 4,
+ R5 = 5,
+ R6 = 6,
+ R7 = 7,
+ R8 = 8,
+ R9 = 9,
+ R10 = 10,
+ R11 = 11,
+ R12 = 12,
+ R13 = 13,
+ R14 = 14,
+ R15 = 15,
+
+ None = 16,
+ RegDirect = 24,
+
+ NoIndex = 128,
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs
new file mode 100644
index 000000000..93bbdd57e
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/TargetRegisterMap.cs
@@ -0,0 +1,35 @@
+// 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.
+
+using System;
+
+using Internal.TypeSystem;
+
+namespace ILCompiler.DependencyAnalysis.ARM
+{
+ /// <summary>
+ /// Maps logical registers to physical registers on a specified OS.
+ /// </summary>
+ public struct TargetRegisterMap
+ {
+ public readonly Register Arg0;
+ public readonly Register Arg1;
+ public readonly Register Result;
+
+ public TargetRegisterMap(TargetOS os)
+ {
+ switch (os)
+ {
+ case TargetOS.Windows:
+ Arg0 = Register.R0;
+ Arg1 = Register.R1;
+ Result = Register.R0;
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs
new file mode 100644
index 000000000..75a5a7eda
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/AddrMode.cs
@@ -0,0 +1,33 @@
+// 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.
+
+using System;
+
+namespace ILCompiler.DependencyAnalysis.X86
+{
+ public enum AddrModeSize
+ {
+ Int8 = 1,
+ Int16 = 2,
+ Int32 = 4
+ }
+
+ public struct AddrMode
+ {
+ public readonly Register BaseReg;
+ public readonly Register? IndexReg;
+ public readonly int Offset;
+ public readonly byte Scale;
+ public readonly AddrModeSize Size;
+
+ public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size)
+ {
+ BaseReg = baseRegister;
+ IndexReg = indexRegister;
+ Offset = offset;
+ Scale = scale;
+ Size = size;
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/Register.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/Register.cs
new file mode 100644
index 000000000..ab938c828
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/Register.cs
@@ -0,0 +1,29 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ILCompiler.DependencyAnalysis.X86
+{
+ public enum Register
+ {
+ EAX = 0,
+ ECX = 1,
+ EDX = 2,
+ EBX = 3,
+ ESP = 4,
+ EBP = 5,
+ ESI = 6,
+ EDI = 7,
+
+ None = 8,
+ RegDirect = 24,
+
+ NoIndex = 128,
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs
new file mode 100644
index 000000000..3b81e43ba
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/TargetRegisterMap.cs
@@ -0,0 +1,35 @@
+// 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.
+
+using System;
+
+using Internal.TypeSystem;
+
+namespace ILCompiler.DependencyAnalysis.X86
+{
+ /// <summary>
+ /// Maps logical registers to physical registers on a specified OS.
+ /// </summary>
+ public struct TargetRegisterMap
+ {
+ public readonly Register Arg0;
+ public readonly Register Arg1;
+ public readonly Register Result;
+
+ public TargetRegisterMap(TargetOS os)
+ {
+ switch (os)
+ {
+ case TargetOS.Windows:
+ Arg0 = Register.ECX;
+ Arg1 = Register.EDX;
+ Result = Register.EAX;
+ break;
+
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs
new file mode 100644
index 000000000..3ecc4078c
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86Emitter.cs
@@ -0,0 +1,155 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+
+namespace ILCompiler.DependencyAnalysis.X86
+{
+ public struct X86Emitter
+ {
+ public X86Emitter(NodeFactory factory)
+ {
+ Builder = new ObjectDataBuilder(factory);
+ TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem);
+ }
+
+ public ObjectDataBuilder Builder;
+ public TargetRegisterMap TargetRegister;
+
+ public void EmitADD(ref AddrMode addrMode, sbyte immediate)
+ {
+ if (addrMode.Size == AddrModeSize.Int16)
+ Builder.EmitByte(0x66);
+ EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode);
+ Builder.EmitByte((byte)immediate);
+ }
+
+ public void EmitJMP(ISymbolNode symbol)
+ {
+ Builder.EmitByte(0xE9);
+ Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
+ }
+
+ private bool InSignedByteRange(int i)
+ {
+ return i == (int)(sbyte)i;
+ }
+
+ private void EmitImmediate(int immediate, int size)
+ {
+ switch (size)
+ {
+ case 0:
+ break;
+ case 1:
+ Builder.EmitByte((byte)immediate);
+ break;
+ case 2:
+ Builder.EmitShort((short)immediate);
+ break;
+ case 4:
+ Builder.EmitInt(immediate);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ private void EmitModRM(byte subOpcode, ref AddrMode addrMode)
+ {
+ byte modRM = (byte)((subOpcode & 0x07) << 3);
+ if (addrMode.BaseReg > Register.None)
+ {
+ Debug.Assert(addrMode.BaseReg >= Register.RegDirect);
+
+ Register reg = (Register)(addrMode.BaseReg - Register.RegDirect);
+ Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07)));
+ }
+ else
+ {
+ byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07);
+ modRM |= lowOrderBitsOfBaseReg;
+ int offsetSize = 0;
+
+ if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.EBP))
+ {
+ offsetSize = 0;
+ }
+ else if (InSignedByteRange(addrMode.Offset))
+ {
+ offsetSize = 1;
+ modRM |= 0x40;
+ }
+ else
+ {
+ offsetSize = 4;
+ modRM |= 0x80;
+ }
+
+ bool emitSibByte = false;
+ Register sibByteBaseRegister = addrMode.BaseReg;
+
+ if (addrMode.BaseReg == Register.None)
+ {
+ emitSibByte = (addrMode.IndexReg != Register.NoIndex);
+ modRM &= 0x38; // set Mod bits to 00 and clear out base reg
+ offsetSize = 4; // this forces 32-bit displacement
+
+ if (emitSibByte)
+ {
+ // EBP in SIB byte means no base
+ // ModRM base register forced to ESP in SIB code below
+ sibByteBaseRegister = Register.EBP;
+ }
+ else
+ {
+ // EBP in ModRM means no base
+ modRM |= (byte)(Register.EBP);
+ }
+ }
+ else if (lowOrderBitsOfBaseReg == (byte)Register.ESP || addrMode.IndexReg.HasValue)
+ {
+ emitSibByte = true;
+ }
+
+ if (!emitSibByte)
+ {
+ Builder.EmitByte(modRM);
+ }
+ else
+ {
+ modRM = (byte)((modRM & 0xF8) | (int)Register.ESP);
+ Builder.EmitByte(modRM);
+ int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.ESP);
+ Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07)));
+ }
+ EmitImmediate(addrMode.Offset, offsetSize);
+ }
+ }
+
+ private void EmitExtendedOpcode(int opcode)
+ {
+ if ((opcode >> 16) != 0)
+ {
+ if ((opcode >> 24) != 0)
+ {
+ Builder.EmitByte((byte)(opcode >> 24));
+ }
+ Builder.EmitByte((byte)(opcode >> 16));
+ }
+ Builder.EmitByte((byte)(opcode >> 8));
+ }
+
+ private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode)
+ {
+ if ((opcode >> 8) != 0)
+ {
+ EmitExtendedOpcode(opcode);
+ }
+ Builder.EmitByte((byte)opcode);
+ EmitModRM(subOpcode, ref addrMode);
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunGenericHelperNode.cs
new file mode 100644
index 000000000..8f856ae5e
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunGenericHelperNode.cs
@@ -0,0 +1,22 @@
+// 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.
+
+using System;
+
+using ILCompiler.DependencyAnalysis.X86;
+
+using Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ partial class ReadyToRunGenericHelperNode
+ {
+ protected sealed override void EmitCode(NodeFactory factory, ref X86Emitter encoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunHelperNode.cs
new file mode 100644
index 000000000..0c8347625
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86ReadyToRunHelperNode.cs
@@ -0,0 +1,24 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using ILCompiler.DependencyAnalysis.X86;
+using Internal.TypeSystem;
+using ILCompiler;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ /// <summary>
+ /// X64 specific portions of ReadyToRunHelperNode
+ /// </summary>
+ public partial class ReadyToRunHelperNode
+ {
+ protected override void EmitCode(NodeFactory factory, ref X86Emitter encoder, bool relocsOnly)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86UnboxingStubNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86UnboxingStubNode.cs
new file mode 100644
index 000000000..ea6009ce7
--- /dev/null
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X86/X86UnboxingStubNode.cs
@@ -0,0 +1,19 @@
+// 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.
+
+using ILCompiler.DependencyAnalysis.X86;
+
+namespace ILCompiler.DependencyAnalysis
+{
+ public partial class UnboxingStubNode
+ {
+ protected override void EmitCode(NodeFactory factory, ref X86Emitter encoder, bool relocsOnly)
+ {
+ AddrMode thisPtr = new AddrMode(
+ Register.RegDirect | encoder.TargetRegister.Arg0, null, 0, 0, AddrModeSize.Int32);
+ encoder.EmitADD(ref thisPtr, (sbyte)factory.Target.PointerSize);
+ encoder.EmitJMP(factory.MethodEntrypoint(_target));
+ }
+ }
+}
diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
index 2330e0a02..ed9a96cb5 100644
--- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
+++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
@@ -139,6 +139,8 @@
<Compile Include="Compiler\DependencyAnalysis\RuntimeImportMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\StringAllocatorMethodNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\Target_X64\X64ReadyToRunGenericHelperNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMInitialInterfaceDispatchStubNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMNodeFactory.cs" />
<Compile Include="Compiler\DependencyAnalysis\VTableSliceNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\EETypeOptionalFieldsNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\EmbeddedObjectNode.cs" />
@@ -184,6 +186,19 @@
<Compile Include="Compiler\DependencyAnalysis\Target_X64\X64Emitter.cs" />
<Compile Include="Compiler\DependencyAnalysis\Target_X64\X64ReadyToRunHelperNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\InterfaceDispatchMapNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\AddrMode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\TargetRegisterMap.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\X86UnboxingStubNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\Register.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\X86Emitter.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\X86ReadyToRunHelperNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_X86\X86ReadyToRunGenericHelperNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\TargetRegisterMap.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMUnboxingStubNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\Register.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMEmitter.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMReadyToRunHelperNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\Target_ARM\ARMReadyToRunGenericHelperNode.cs" />
<Compile Include="Compiler\ExportedMethodsRootProvider.cs" />
<Compile Include="Compiler\IRootingServiceProvider.cs" />
<Compile Include="Compiler\JitHelper.cs" />