diff options
author | Petr Bred <bredpetr@gmail.com> | 2017-09-20 23:23:13 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-09-20 23:23:13 +0300 |
commit | bcf05f3933d1584a6618c5eb1d14f846a5f5d798 (patch) | |
tree | 7c615ecd2895ad3f434edf93d98a43bdf86db0c9 /src/ILCompiler.Compiler | |
parent | 3c882b0ed8bc355d07156632f6dd6e96de7a1c35 (diff) |
Adding inspections to ARM emitter (#4578)
Signed-off-by: Petr Bred <bredpetr@gmail.com>
Diffstat (limited to 'src/ILCompiler.Compiler')
3 files changed, 71 insertions, 31 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs index 96cd53b78..535f13fce 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMEmitter.cs @@ -18,31 +18,55 @@ namespace ILCompiler.DependencyAnalysis.ARM public ObjectDataBuilder Builder; public TargetRegisterMap TargetRegister; + // check the value length + private static bool IsBitNumOverflow(int value, byte numBits) + { + return (value >> numBits) != 0; + } + + private static bool IsLowReg(Register reg) + { + return !IsBitNumOverflow((int)reg, 3); + } + + private static bool IsValidReg(Register reg) + { + return !IsBitNumOverflow((int)reg, 4); + } + // mov reg, immediate - // reg range: 0-7 - public void EmitMOV(Register reg, byte immediate) + // reg range: [0..7] + // immediage range: [0..255] + public void EmitMOV(Register reg, int immediate) { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); Builder.EmitShort((short)(0x2000 + ((byte)reg << 8) + immediate)); } // cmp reg, immediate - // reg range: 0-7 - public void EmitCMP(Register reg, byte immediate) + // reg range: [0..7] + // immediage range: [0..255] + public void EmitCMP(Register reg, int immediate) { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); Builder.EmitShort((short)(0x2800 + ((byte)reg << 8) + immediate)); } // add reg, immediate - // reg range: 0-7 - public void EmitADD(Register reg, byte immediate) + // reg range: [0..7] + // immediage range: [0..255] + public void EmitADD(Register reg, int immediate) { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); Builder.EmitShort((short)(0x3000 + ((byte)reg << 8) + immediate)); } // sub reg, immediate - // reg range: 0-7 - public void EmitSUB(Register reg, byte immediate) + // reg range: [0..7] + // immediage range: [0..255] + public void EmitSUB(Register reg, int immediate) { + Debug.Assert(IsLowReg(reg) && !IsBitNumOverflow(immediate, 8)); Builder.EmitShort((short)(0x3800 + ((byte)reg << 8) + immediate)); } @@ -61,38 +85,48 @@ namespace ILCompiler.DependencyAnalysis.ARM } // push reg + // reg range: [0..12, LR] public void EmitPUSH(Register reg) { + Debug.Assert(reg >= Register.R0 && (reg <= Register.R12 || reg == TargetRegister.LR)); Builder.EmitByte(0x4d); Builder.EmitByte(0xf8); Builder.EmitShort((short)(0x0d04 + ((byte)reg << 12))); } // pop reg + // reg range: [0..12, LR, PC] public void EmitPOP(Register reg) { + Debug.Assert(IsValidReg(reg) && reg != TargetRegister.SP); Builder.EmitByte(0x5d); Builder.EmitByte(0xf8); Builder.EmitShort((short)(0x0b04 + ((byte)reg << 12))); } // mov reg, reg + // reg range: [0..PC] public void EmitMOV(Register destination, Register source) { + Debug.Assert(IsValidReg(destination) && IsValidReg(source)); Builder.EmitShort((short)(0x4600 + (((byte)destination & 0x8) << 4) + (((byte)source & 0x8) << 3) + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); } // ldr reg, [reg] - // reg range: 0-7 + // reg range: [0..7] public void EmitLDR(Register destination, Register source) { + Debug.Assert(IsLowReg(destination) && IsLowReg(source)); Builder.EmitShort((short)(0x6800 + (((byte)source & 0x7) << 3) + ((byte)destination & 0x7))); } // ldr.w reg, [reg, #offset] + // reg range: [0..PC] // offset range: [-255..4095] - public void EmitLDR(Register destination, Register source, short offset) + public void EmitLDR(Register destination, Register source, int offset) { + Debug.Assert(IsValidReg(destination) && IsValidReg(source)); + Debug.Assert(offset >= -255 && offset <= 4095); if (offset >= 0) { Builder.EmitShort((short)(0xf8d0 + ((byte)(source)))); @@ -105,10 +139,12 @@ namespace ILCompiler.DependencyAnalysis.ARM } } - // mov reg, [reloc] & 0x0000FFFF + // movw reg, [reloc] & 0x0000FFFF // movt reg, [reloc] & 0xFFFF0000 + // reg range: [0..12, LR] public void EmitMOV(Register destination, ISymbolNode symbol) { + Debug.Assert(destination >= Register.R0 && (destination <= Register.R12 || destination == TargetRegister.LR)); Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_THUMB_MOV32); Builder.EmitShort(unchecked((short)0xf240)); Builder.EmitShort((short)((byte)destination << 8)); @@ -116,7 +152,7 @@ namespace ILCompiler.DependencyAnalysis.ARM Builder.EmitShort((short)((byte)destination << 8)); } - // b symbol + // b.w symbol public void EmitJMP(ISymbolNode symbol) { Debug.Assert(!symbol.RepresentsIndirectionCell); @@ -128,8 +164,10 @@ namespace ILCompiler.DependencyAnalysis.ARM } // bx reg + // reg range: [0..PC] public void EmitJMP(Register destination) { + Debug.Assert(IsValidReg(destination)); Builder.EmitShort((short)(0x4700 + ((byte)destination << 3))); } @@ -141,8 +179,9 @@ namespace ILCompiler.DependencyAnalysis.ARM // bne #offset // offset range: [-256..254] - public void EmitBNE(short immediate) + public void EmitBNE(int immediate) { + Debug.Assert(immediate >= -256 && immediate <= 254); // considering the pipeline with PC immediate -= 4; @@ -152,8 +191,9 @@ namespace ILCompiler.DependencyAnalysis.ARM // beq #offset // offset range: [-256..254] - public void EmitBEQ(short immediate) + public void EmitBEQ(int immediate) { + Debug.Assert(immediate >= -256 && immediate <= 254); // considering the pipeline with PC immediate -= 4; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs index 93e4fd8ae..287eff2be 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunGenericHelperNode.cs @@ -35,7 +35,7 @@ namespace ILCompiler.DependencyAnalysis } // Load the generic dictionary cell - encoder.EmitLDR(result, context, ((short)(dictionarySlot * factory.Target.PointerSize))); + encoder.EmitLDR(result, context, dictionarySlot * factory.Target.PointerSize); switch (lookup.LookupResultReferenceType(factory)) { @@ -125,10 +125,10 @@ namespace ILCompiler.DependencyAnalysis EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); - encoder.EmitSUB(encoder.TargetRegister.Arg0, ((byte)(cctorContextSize))); + encoder.EmitSUB(encoder.TargetRegister.Arg0, cctorContextSize); // cmp [r0 + ptrSize], 1 - encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg0, ((short)factory.Target.PointerSize)); - encoder.EmitCMP(encoder.TargetRegister.Arg2, ((byte)1)); + encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg0, factory.Target.PointerSize); + encoder.EmitCMP(encoder.TargetRegister.Arg2, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); @@ -155,7 +155,7 @@ namespace ILCompiler.DependencyAnalysis GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); - encoder.EmitSUB(encoder.TargetRegister.Arg2, ((byte)(cctorContextSize))); + encoder.EmitSUB(encoder.TargetRegister.Arg2, cctorContextSize); encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2); helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); @@ -171,7 +171,7 @@ namespace ILCompiler.DependencyAnalysis encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1); // Second arg: index of the type in the ThreadStatic section of the modules - encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg1, ((short)(factory.Target.PointerSize))); + encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg1, factory.Target.PointerSize); encoder.EmitJMP(helperEntrypoint); } @@ -253,7 +253,7 @@ namespace ILCompiler.DependencyAnalysis int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); // Load the dictionary pointer from the VTable - encoder.EmitLDR(contextRegister, contextRegister, ((short)(slotOffset))); + encoder.EmitLDR(contextRegister, contextRegister, slotOffset); } } } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs index b45306615..aadc3a376 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM/ARMReadyToRunHelperNode.cs @@ -45,7 +45,7 @@ namespace ILCompiler.DependencyAnalysis encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.Arg0, 0); encoder.EmitLDR(encoder.TargetRegister.InterproceduralScratch, encoder.TargetRegister.InterproceduralScratch, - (short)(EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize))); + EETypeNode.GetVTableOffset(pointerSize) + (slot * pointerSize)); encoder.EmitJMP(encoder.TargetRegister.InterproceduralScratch); } break; @@ -89,11 +89,11 @@ namespace ILCompiler.DependencyAnalysis { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); - encoder.EmitSUB(encoder.TargetRegister.Arg2, ((byte)NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target))); + encoder.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)); // cmp [r2 + ptrSize], 1 - encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)factory.Target.PointerSize)); - encoder.EmitCMP(encoder.TargetRegister.Arg3, ((byte)1)); + encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, factory.Target.PointerSize); + encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); // return if cmp encoder.EmitRETIfEqual(); @@ -115,7 +115,7 @@ namespace ILCompiler.DependencyAnalysis encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2); // Second arg: index of the type in the ThreadStatic section of the modules - encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, ((short)factory.Target.PointerSize)); + encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, factory.Target.PointerSize); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { @@ -124,7 +124,7 @@ namespace ILCompiler.DependencyAnalysis else { encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); - encoder.EmitSUB(encoder.TargetRegister.Arg2, (byte)(NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target))); + encoder.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)); // TODO: performance optimization - inline the check verifying whether we need to trigger the cctor encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase)); } @@ -146,10 +146,10 @@ namespace ILCompiler.DependencyAnalysis // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. encoder.EmitMOV(encoder.TargetRegister.Arg2, factory.TypeNonGCStaticsSymbol(target)); // Get cctor pointer: offset is usually equal to the double size of the pointer, therefore we can use arm sub imm - encoder.EmitSUB(encoder.TargetRegister.Arg2, (byte)(NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target))); + encoder.EmitSUB(encoder.TargetRegister.Arg2, NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target)); // cmp [r2 + ptrSize], 1 - encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)factory.Target.PointerSize)); - encoder.EmitCMP(encoder.TargetRegister.Arg3, (byte)1); + encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, factory.Target.PointerSize); + encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); // return if cmp encoder.EmitRETIfEqual(); @@ -174,7 +174,7 @@ namespace ILCompiler.DependencyAnalysis Debug.Assert(slot != -1); encoder.EmitLDR(encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, - ((short)(EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)))); + EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (slot * factory.Target.PointerSize)); } else { |