private LLVM.FunctionType ConstructType() { LLVM.Type retTy = Cil2Llvm.GetType(_method.ReturnType); if (_method.ReturnType.MetadataType == MetadataType.Class) { retTy = retTy.GetPointerTo(); } List <LLVM.Type> paramsTy = new List <LLVM.Type>(); if (_method.HasThis) { paramsTy.Add(Cil2Llvm.GetType(_method.DeclaringType).GetPointerTo()); } if (_method.HasParameters) { foreach (ParameterDefinition p in _method.Parameters) { LLVM.Type ty = Cil2Llvm.GetType(p.ParameterType); if (p.ParameterType.MetadataType == MetadataType.Class) { ty = ty.GetPointerTo(); } paramsTy.Add(ty); } } // TODO false -> varArg return(LLVM.FunctionType.Get(retTy, paramsTy.ToArray(), false)); }
private void EmitOpCodeNewobj(MethodReference method) { Trace.Assert(method != null); TypeReference type = method.DeclaringType; Trace.Assert(type != null); // cannot be null, we are creating an obj LLVM.Type ty = Cil2Llvm.GetType(type); LLVM.Value size = ConvertInteger(ty.Size, CLR.Native); LLVM.Value newobj = _builder.CreateCall(CLR.Newobj, size, "newobj"); newobj.Dump(); LLVM.Value obj = ConvertPointer(newobj, ty.GetPointerTo()); //obj.dump(); _stack.Push(obj); //TODO: Trace.Assert(method.ReturnType == Void); EmitOpCodeCall(method); _stack.Push(obj); /* * // Cast to object type, call ctor and push on the stack * // * convertValue(newobj, PointerType::get(ClassTy, 0), bb); * callMethod(newobj, token, bb); * _Stack.push_back(newobj); */ }
private void EmitOpCodeStfld(FieldReference field) { Trace.Assert(field != null); Trace.Assert(_stack.Count >= 2); Trace.Assert(field.IsDefinition); CodeGenType ty = Cil2Llvm.GetCodeGenType(field.DeclaringType); FieldDefinition f = field as FieldDefinition; uint offset = ty.GetFieldOffset(f); LLVM.Value val = _stack.Pop(); LLVM.Value obj = ConvertToType(_stack.Pop(), ty.Type.GetPointerTo()); LLVM.Value ptr = _builder.CreateStructGEP(obj, offset, field.Name + " pointer"); _builder.CreateStore(val, ptr); }
private void EmitOpCodeCall(MethodReference method) { Trace.Assert(method != null); List <LLVM.Type> argsTy = new List <LLVM.Type>(); if (method.HasThis) { argsTy.Add(Cil2Llvm.GetType(method.DeclaringType).GetPointerTo()); } if (method.HasParameters) { foreach (ParameterDefinition p in method.Parameters) { argsTy.Add(Cil2Llvm.GetType(p.ParameterType)); } } Trace.Assert(_stack.Count >= argsTy.Count); LLVM.Value[] args = new LLVM.Value[argsTy.Count]; for (int i = argsTy.Count - 1; i >= 0; i--) { args[i] = ConvertToType(_stack.Pop(), argsTy[i]); } LLVM.Value ret = _builder.CreateCall(Cil2Llvm.GetMethod(method), args); LLVM.Type retTy = Cil2Llvm.GetType(method.ReturnType); if (!retTy.Equals(CLR.Void)) { _stack.Push(ret); } /* * // Cast to object type, call ctor and push on the stack * // * convertValue(newobj, PointerType::get(ClassTy, 0), bb); * callMethod(newobj, token, bb); * _Stack.push_back(newobj); */ }
public void EmitBody() { uint hasThis = 0; MethodDefinition meth = _method.Method as MethodDefinition; LLVM.Function func = _method.Function; // Process parameters // if (meth.HasThis) { LLVM.Value val = func.GetParam(0); val.Name = "this"; _params.Add(val); hasThis = 1; } for (uint i = 0; i < meth.Parameters.Count; i++) { LLVM.Value val = func.GetParam(i + hasThis); val.Name = meth.Parameters[(int)i].Name; _params.Add(val); } MethodBody body = meth.Body; if (body == null) { // Method may not have a body. For instance in the case of // external methods return; // end here } LLVM.BasicBlock bb = new LLVM.BasicBlock(func, "IL_0000"); _builder.PositionAtEnd(bb); // Process local variables // if (body.HasVariables) { _variables = new List <LLVM.Value>(); foreach (VariableDefinition variable in body.Variables) { LLVM.Type ty = Cil2Llvm.GetType(variable.VariableType); // FIXME: check when we want to use pointers and when we // want to use primitive type. Do we want to use struct // for ValueTypes ? // if (!variable.VariableType.IsPrimitive && !variable.VariableType.IsValueType) { ty = ty.GetPointerTo(); } string name = "V_"; if (variable.Name.Length != 0) { name = variable.Name; } LLVM.Value val = _builder.CreateAlloca(ty, name); _variables.Add(val); } } // parse all flowcontrol instructions a first time to create // basic blocks with the labels these instructions point to. // List <int> labels = new List <int>(); foreach (Instruction inst in body.Instructions) { if (inst.OpCode.OperandType == OperandType.InlineBrTarget || inst.OpCode.OperandType == OperandType.ShortInlineBrTarget) { if (inst.OpCode.FlowControl == FlowControl.Cond_Branch) { labels.Add(inst.Next.Offset); } Instruction br = inst.Operand as Instruction; labels.Add(br.Offset); } } labels.Sort(); foreach (int offset in labels) { LLVM.BasicBlock lbl = func.AppendBasicBlock("IL_" + offset.ToString("x4")); _labels[offset] = lbl; } var lEnum = labels.GetEnumerator(); bool hasLabels = lEnum.MoveNext(); foreach (Instruction inst in body.Instructions) { Console.WriteLine("{0}", inst); if (hasLabels && lEnum.Current == inst.Offset) { LLVM.BasicBlock lbl = _labels[inst.Offset]; Console.WriteLine("offset " + inst.Offset); if (!bb.HasTerminator) { _builder.CreateBr(lbl); } _builder.PositionAtEnd(lbl); bb = lbl; while (lEnum.Current == inst.Offset && (hasLabels = lEnum.MoveNext())) { } } //TODO: pre-select instruction by type (flowcontrol, ...) if (inst.OpCode == OpCodes.Nop) { } /* Nothing */ else if (inst.OpCode == OpCodes.Break) { EmitUnimplemented(); } else if (inst.OpCode == OpCodes.Ldarg_0) { EmitOpCodeLdarg(0); } else if (inst.OpCode == OpCodes.Ldarg_1) { EmitOpCodeLdarg(1); } else if (inst.OpCode == OpCodes.Ldarg_2) { EmitOpCodeLdarg(2); } else if (inst.OpCode == OpCodes.Ldarg_3) { EmitOpCodeLdarg(3); } else if (inst.OpCode == OpCodes.Ldloc_0) { EmitOpCodeLdloc(0); } else if (inst.OpCode == OpCodes.Ldloc_1) { EmitOpCodeLdloc(1); } else if (inst.OpCode == OpCodes.Ldloc_2) { EmitOpCodeLdloc(2); } else if (inst.OpCode == OpCodes.Ldloc_3) { EmitOpCodeLdloc(3); } else if (inst.OpCode == OpCodes.Stloc_0) { EmitOpCodeStloc(0); } else if (inst.OpCode == OpCodes.Stloc_1) { EmitOpCodeStloc(1); } else if (inst.OpCode == OpCodes.Stloc_2) { EmitOpCodeStloc(2); } else if (inst.OpCode == OpCodes.Stloc_3) { EmitOpCodeStloc(3); } else if (inst.OpCode == OpCodes.Ldnull) { EmitUnimplemented(); } else if (inst.OpCode == OpCodes.Ldc_I4_M1) { EmitOpCodeLdc(4, Convert.ToInt64(-1)); } else if (inst.OpCode == OpCodes.Ldc_I4_0) { EmitOpCodeLdc(4, 0); } else if (inst.OpCode == OpCodes.Ldc_I4_1) { EmitOpCodeLdc(4, 1); } else if (inst.OpCode == OpCodes.Ldc_I4_2) { EmitOpCodeLdc(4, 2); } else if (inst.OpCode == OpCodes.Ldc_I4_3) { EmitOpCodeLdc(4, 3); } else if (inst.OpCode == OpCodes.Ldc_I4_4) { EmitOpCodeLdc(4, 4); } else if (inst.OpCode == OpCodes.Ldc_I4_5) { EmitOpCodeLdc(4, 5); } else if (inst.OpCode == OpCodes.Ldc_I4_6) { EmitOpCodeLdc(4, 6); } else if (inst.OpCode == OpCodes.Ldc_I4_7) { EmitOpCodeLdc(4, 7); } else if (inst.OpCode == OpCodes.Ldc_I4_8) { EmitOpCodeLdc(4, 8); } else if (inst.OpCode == OpCodes.Dup) { EmitOpCodeDup(); } else if (inst.OpCode == OpCodes.Pop) { EmitOpCodePop(); } else if (inst.OpCode == OpCodes.Ret) { EmitOpCodeRet(); } /* * case 0x46: // ldind.i1 * case 0x47: // ldind.u1 * case 0x48: // ldind.i2 * case 0x49: // ldind.u2 * case 0x4A: // ldind.i4 * case 0x4B: // ldind.u4 * case 0x4C: // ldind.i8,u8 * case 0x4D: // ldind.i * case 0x4E: // ldind.r4 * case 0x4F: // ldind.r8 * case 0x50: // ldind.ref * case 0x51: // stind.ref * case 0x52: // stind.i1 * case 0x53: // stind.i2 * case 0x54: // stind.i4 * case 0x55: // stind.i8 * case 0x56: // stind.r4 * case 0x57: // stind.r8 */ else if (inst.OpCode == OpCodes.Call) { EmitOpCodeCall(inst.Operand as MethodReference); } else if (inst.OpCode == OpCodes.Add) { EmitOpCodeAdd(); } else if (inst.OpCode == OpCodes.Sub) { EmitOpCodeSub(); } else if (inst.OpCode == OpCodes.Mul) { EmitOpCodeMul(); } else if (inst.OpCode == OpCodes.Div) { EmitOpCodeDiv(); } else if (inst.OpCode == OpCodes.Div_Un) { EmitOpCodeDivUn(); } else if (inst.OpCode == OpCodes.And) { EmitOpCodeAnd(); } else if (inst.OpCode == OpCodes.Or) { EmitOpCodeOr(); } else if (inst.OpCode == OpCodes.Xor) { EmitOpCodeXor(); } else if (inst.OpCode == OpCodes.Not) { EmitOpCodeNot(); } else if (inst.OpCode == OpCodes.Ldfld) { EmitOpCodeLdfld(inst.Operand as FieldReference); } else if (inst.OpCode == OpCodes.Stfld) { EmitOpCodeStfld(inst.Operand as FieldReference); } else if (inst.OpCode == OpCodes.Bge) { EmitOpCodeBge(inst); } else if (inst.OpCode == OpCodes.Ble) { EmitOpCodeBle(inst); } #if UNIMPLEMENTED /* * case 0x5D: // rem * case 0x5E: // rem.un * case 0x62: // shl * case 0x63: // shr * case 0x64: // shr.un * case 0x65: // neg * case 0x67: // conv.i1 * case 0x68: // conv.i2 * case 0x69: // conv.i4 * case 0x6A: // conv.i8 * case 0x6B: // conv.r4 * case 0x6C: // conv.r8 * case 0x6D: // conv.u4 * case 0x6E: // conv.u8 * case 0x76: // conv.r.un * case 0x82: // conv.ovf.i1.un * case 0x83: // conv.ovfi.i2.un * case 0x84: // conv.ovf.i4.un * case 0x85: // conv.ovf.i8.un * case 0x86: // conv.ovf.u1.un * case 0x87: // conv.ovf.u2.un * case 0x88: // conv.ovf.u4.un * case 0x89: // conv.ovf.u8.un * case 0x8A: // conv.ovf.i.un * case 0x8B: // conv.ovf.u.un * case 0xB3: // conv.ovf.i1 * case 0xB4: // conv.ovf.u1 * case 0xB5: // conv.ovfi.i2 * case 0xB6: // conv.ovf.u2 * case 0xB7: // conv.ovf.i4 * case 0xB8: // conv.ovf.u4 * case 0xB9: // conv.ovf.i8 * case 0xBA: // conv.ovf.u8 * case 0xC3: // ckfinite * case 0xD1: // conv.u2 * case 0xD2: // conv.u1 * case 0xD3: // conv.i (native int) * case 0xD4: // conv.ovf.i * case 0xD5: // conv.ovf.u * case 0xD6: // add.ovf * case 0xD7: // add.ovf.un * case 0xD8: // mul.ovf * case 0xD9: // mul.ovf.un * case 0xDA: // sub.ovf * case 0xDB: // sub.ovf.un * case 0xDC: // endfault, endfinally * case 0xDD: // leave * case 0xDE: // leave.s * case 0xDF: // stind.i * case 0xE0: // conv.u (native int) * */ #endif else if (inst.OpCode == OpCodes.Newobj) { EmitOpCodeNewobj(inst.Operand as MethodReference); } else if (inst.OpCode == OpCodes.Ldc_I4_S) { EmitOpCodeLdc(4, Convert.ToInt64(inst.Operand)); } else if (inst.OpCode == OpCodes.Ldc_I4) { EmitOpCodeLdc(4, Convert.ToInt64(inst.Operand)); } else { EmitUnimplemented(); } } }