diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs index 04885c056cac..c2cbc0b194c2 100644 --- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs +++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs @@ -39,7 +39,7 @@ public CompilationResult CompileMethod (MethodInfo methodInfo, out NativeCodeHan try { BitCodeEmitter processor = new BitCodeEmitter (RuntimeInfo, methodInfo) { - // PrintDebugInfo = true, + //PrintDebugInfo = true, VerifyGeneratedCode = true }; CILSymbolicExecutor exec = new CILSymbolicExecutor (processor, RuntimeInfo, methodInfo); diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs index b0d2844d1ae1..abe7217f585b 100644 --- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs +++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/CILSymbolicExecutor.cs @@ -409,6 +409,12 @@ private void Pass2 () opParam = iter.DecodeParamI (); operands.Add (args[opParam]); break; + case Opcode.LdelemI4: + // Assumption: the first operand is an array. CLR should guarantee this. + Type t = tempOds[0].Type.AsSystemType; + t = t.GetElementType(); + output = new TempOperand (this, RuntimeInformation.ClrTypeFromType(t)); + break; case Opcode.Ldsfld: int token = iter.DecodeParamI (); FieldInfo fieldInfo = runtime.GetFieldInfoForToken (methodInfo, token); diff --git a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs index b78b895b675d..720edcc54430 100644 --- a/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs +++ b/mcs/class/Mono.Compiler/Mono.Compiler.BigStep/LLVM/BitCodeEmitter.cs @@ -355,6 +355,38 @@ public void Process (OperationInfo opInfo) return new NamedTempValue (tmp, tempName); }); break; + case Opcode.LdelemI1: + // load element from array + // tmp (array), tmp (index) => tmp + InvokeOperation (op, exop, operands, + vm => { + return GetIntArrayElement(operands[0].Type, 1, tempName, vm.Temp0, vm.Temp1); + }); + break; + case Opcode.LdelemI2: + // load element from array + // tmp (array), tmp (index) => tmp + InvokeOperation (op, exop, operands, + vm => { + return GetIntArrayElement(operands[0].Type, 2, tempName, vm.Temp0, vm.Temp1); + }); + break; + case Opcode.LdelemI4: + // load element from array + // tmp (array), tmp (index) => tmp + InvokeOperation (op, exop, operands, + vm => { + return GetIntArrayElement(operands[0].Type, 4, tempName, vm.Temp0, vm.Temp1); + }); + break; + case Opcode.LdelemI8: + // load element from array + // tmp (array), tmp (index) => tmp + InvokeOperation (op, exop, operands, + vm => { + return GetIntArrayElement(operands[0].Type, 8, tempName, vm.Temp0, vm.Temp1); + }); + break; case Opcode.Ldsfld: // const => tmp int token = (operands[0] as Int32ConstOperand).Value; @@ -630,6 +662,27 @@ private void AllocateArgsAndLocals (LLVMTypeRef[] args, IList } } + private NamedTempValue GetIntArrayElement( + ClrType arrayClrType, uint elementSize, string resultValueName, LLVMValueRef arrayBaseAddr, LLVMValueRef index) + { + // Get array's base address + // The trick is to treat the metadata also as array elements and use GEP to perform pointer arithmetics + LLVMValueRef offset = LLVM.ConstInt( + LLVM.Int32Type(), RuntimeInfo.GetArrayBaseOffset(arrayClrType) / elementSize, false); + LLVMValueRef basePtr = LLVM.BuildGEP ( + builder, arrayBaseAddr, new LLVMValueRef[] { offset }, this.NextTempName); + + // Array access is translated to two LLVM operations: + // (1) get element address + // %tmpPtr = getelementptr i32, i32* %tmp0, i64 %tmp1 + // (2) get element data + // %result = load i32, i32* %tmpPtr + LLVMValueRef tmpPtr = LLVM.BuildGEP (builder, basePtr, new LLVMValueRef[] { index }, this.NextTempName); + //LLVM.ConstPtrToInt() + LLVMValueRef tmp = LLVM.BuildLoad (builder, tmpPtr, resultValueName); + return new NamedTempValue (tmp, resultValueName); + } + private Tuple CompareAndJumpTo ( LLVMRealPredicate rprd, LLVMIntPredicate prd, IOperand[] operands, ValueMappings vm, int pcIndex) { @@ -789,7 +842,7 @@ private LLVMValueRef GetConstValue (IOperand operand) return LLVM.ConstReal (LLVM.FloatType (), ((Float64ConstOperand)cod).Value); } - throw new Exception ("Unexpected. The const operand is tno recognized."); + throw new Exception ("Unexpected. The const operand is not recognized."); } private LLVMValueRef GetConstValue (IntPtr constant) @@ -797,6 +850,10 @@ private LLVMValueRef GetConstValue (IntPtr constant) return LLVM.ConstInt (TranslateType (RuntimeInformation.NativeIntType), (ulong)constant, true); } + /// Translate a CLR type to an LLVM type. Basically, + /// - Primitive types will be mapped to their counterparts in LLVM + /// - Non-array class types are all mapped to pointer types + /// - Array types are mapped to pointer types of the mapped element types private static LLVMTypeRef TranslateType (ClrType ctyp) { if (ctyp == RuntimeInformation.BoolType) { @@ -805,7 +862,7 @@ private static LLVMTypeRef TranslateType (ClrType ctyp) if (ctyp == RuntimeInformation.Int8Type) { return LLVM.Int8Type (); } - if (ctyp == RuntimeInformation.Int16Type || ctyp == RuntimeInformation.Int8Type) { + if (ctyp == RuntimeInformation.Int16Type || ctyp == RuntimeInformation.UInt8Type) { return LLVM.Int16Type (); } if (ctyp == RuntimeInformation.Int32Type || ctyp == RuntimeInformation.UInt16Type) { @@ -832,6 +889,13 @@ private static LLVMTypeRef TranslateType (ClrType ctyp) } Type typ = ctyp.AsSystemType; + if (typ.IsArray) { + // If this is array, recursively call this method to drill down the subtypes. Our goal + // is to make an LLVM pointer type which maps exactly all the dimensions of the array. + typ = typ.GetElementType(); + ctyp = RuntimeInformation.ClrTypeFromType(typ); + return LLVM.PointerType(TranslateType (ctyp), 0); // 0 = default address sapce + } if (typ.IsClass) { return LLVM.PointerType(LLVM.Int64Type (), 0); // 0 = default address sapce } diff --git a/mcs/class/Mono.Compiler/Mono.Compiler/IRuntimeInformation.cs b/mcs/class/Mono.Compiler/Mono.Compiler/IRuntimeInformation.cs index 6073aa00ae83..27ea84b0812c 100644 --- a/mcs/class/Mono.Compiler/Mono.Compiler/IRuntimeInformation.cs +++ b/mcs/class/Mono.Compiler/Mono.Compiler/IRuntimeInformation.cs @@ -17,5 +17,8 @@ public interface IRuntimeInformation FieldInfo GetFieldInfoForToken (MethodInfo mi, int token); IntPtr ComputeFieldAddress (FieldInfo fi); + + /// For a given array type, get the offset of the vector relative to the base address. + uint GetArrayBaseOffset(ClrType type); } } diff --git a/mcs/class/Mono.Compiler/Mono.Compiler/RuntimeInformation.cs b/mcs/class/Mono.Compiler/Mono.Compiler/RuntimeInformation.cs index 10dde5d15178..e3287e5f770d 100644 --- a/mcs/class/Mono.Compiler/Mono.Compiler/RuntimeInformation.cs +++ b/mcs/class/Mono.Compiler/Mono.Compiler/RuntimeInformation.cs @@ -40,6 +40,17 @@ public FieldInfo GetFieldInfoForToken (MethodInfo mi, int token) { return new FieldInfo (srfi); } + /// (mono/metadata/object-internals.h) + /// struct _MonoArray { // Base + /// MonoObject obj; // 16 bytes + /// MonoArrayBounds *bounds; // 8 bytes + /// mono_array_size_t max_length; // 8 bytes + /// mono_64bitaligned_t vector [MONO_ZERO_LEN_ARRAY]; // Start of vector + /// } + public uint GetArrayBaseOffset(ClrType type){ + return 32; + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern IntPtr ComputeStaticFieldAddress (RuntimeFieldHandle handle); diff --git a/mcs/class/Mono.Compiler/Test/ICompilerInterfaceTest.cs b/mcs/class/Mono.Compiler/Test/ICompilerInterfaceTest.cs index d66e359ae80e..c39049b4ce27 100644 --- a/mcs/class/Mono.Compiler/Test/ICompilerInterfaceTest.cs +++ b/mcs/class/Mono.Compiler/Test/ICompilerInterfaceTest.cs @@ -72,6 +72,19 @@ public static int WhileLoop1 (int times, int unit) { return result; } + public static int ArrayAccess1 (int[] array, int index) { + int result = array[index]; + return result; + } + + [Test] + public void TestArrayAccess1 () { + int[] array = new int[]{4937, 5443, 6673, 7561}; + InstalledRuntimeCode irc = CompileCode("ArrayAccess1"); + int result = (int) runtimeInfo.ExecuteInstalledMethod (irc, array, 2); + Assert.AreEqual (6673, result); + } + [Test] public void TestWhileLoop1 () { InstalledRuntimeCode irc = CompileCode("WhileLoop1");