diff options
author | Simon Nattress <nattress@gmail.com> | 2017-01-21 11:54:07 +0300 |
---|---|---|
committer | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2017-01-21 11:54:07 +0300 |
commit | b580dd08744ee43d22b1adb59b674dafbb2f0e30 (patch) | |
tree | c07b760c280d747908ab2385ae09d20c05a311a5 | |
parent | 972e86c243974d49047328b0dccd72eb44ca493a (diff) |
X86 and Arm assembly emitters (#2555)
Port the emitter code for X86 and Arm, allowing unbox stub generation
for those architectures.
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" /> |