Skip to content

Commit

Permalink
Get element from int array.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhoux738 committed Aug 3, 2018
1 parent 9a8c8b0 commit 49a9059
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 3 deletions.
2 changes: 1 addition & 1 deletion mcs/class/Mono.Compiler/Mono.Compiler.BigStep/BigStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -630,6 +662,27 @@ private void AllocateArgsAndLocals (LLVMTypeRef[] args, IList<LocalVariableInfo>
}
}

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<LLVMValueRef, LLVMBasicBlockRef, LLVMBasicBlockRef> CompareAndJumpTo (
LLVMRealPredicate rprd, LLVMIntPredicate prd, IOperand[] operands, ValueMappings vm, int pcIndex)
{
Expand Down Expand Up @@ -789,14 +842,18 @@ 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)
{
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) {
Expand All @@ -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) {
Expand All @@ -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
}
Expand Down
3 changes: 3 additions & 0 deletions mcs/class/Mono.Compiler/Mono.Compiler/IRuntimeInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
11 changes: 11 additions & 0 deletions mcs/class/Mono.Compiler/Mono.Compiler/RuntimeInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
13 changes: 13 additions & 0 deletions mcs/class/Mono.Compiler/Test/ICompilerInterfaceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down

0 comments on commit 49a9059

Please sign in to comment.