|  | //===-- MSILWriter.cpp - Library for converting LLVM code to MSIL ---------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This library converts LLVM code to MSIL code. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "MSILWriter.h" | 
|  | #include "llvm/CallingConv.h" | 
|  | #include "llvm/DerivedTypes.h" | 
|  | #include "llvm/Intrinsics.h" | 
|  | #include "llvm/IntrinsicInst.h" | 
|  | #include "llvm/TypeSymbolTable.h" | 
|  | #include "llvm/Analysis/ConstantsScanner.h" | 
|  | #include "llvm/Support/CallSite.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/InstVisitor.h" | 
|  | #include "llvm/Support/MathExtras.h" | 
|  | #include "llvm/Transforms/Scalar.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/CodeGen/Passes.h" | 
|  |  | 
|  | namespace { | 
|  | // TargetMachine for the MSIL | 
|  | struct VISIBILITY_HIDDEN MSILTarget : public TargetMachine { | 
|  | const TargetData DataLayout;       // Calculates type size & alignment | 
|  |  | 
|  | MSILTarget(const Target &T, const Module &M, const std::string &FS) | 
|  | : TargetMachine(T), DataLayout(&M) {} | 
|  |  | 
|  | virtual bool WantsWholeFile() const { return true; } | 
|  | virtual bool addPassesToEmitWholeFile(PassManager &PM, | 
|  | formatted_raw_ostream &Out, | 
|  | CodeGenFileType FileType, | 
|  | CodeGenOpt::Level OptLevel); | 
|  |  | 
|  | // This class always works, but shouldn't be the default in most cases. | 
|  | static unsigned getModuleMatchQuality(const Module &M) { return 1; } | 
|  |  | 
|  | virtual const TargetData *getTargetData() const { return &DataLayout; } | 
|  | }; | 
|  | } | 
|  |  | 
|  | static RegisterTarget<MSILTarget> X(TheMSILTarget, "msil", "MSIL backend"); | 
|  |  | 
|  | // Force static initialization. | 
|  | extern "C" void LLVMInitializeMSILTarget() { } | 
|  |  | 
|  | bool MSILModule::runOnModule(Module &M) { | 
|  | ModulePtr = &M; | 
|  | TD = &getAnalysis<TargetData>(); | 
|  | bool Changed = false; | 
|  | // Find named types. | 
|  | TypeSymbolTable& Table = M.getTypeSymbolTable(); | 
|  | std::set<const Type *> Types = getAnalysis<FindUsedTypes>().getTypes(); | 
|  | for (TypeSymbolTable::iterator I = Table.begin(), E = Table.end(); I!=E; ) { | 
|  | if (!isa<StructType>(I->second) && !isa<OpaqueType>(I->second)) | 
|  | Table.remove(I++); | 
|  | else { | 
|  | std::set<const Type *>::iterator T = Types.find(I->second); | 
|  | if (T==Types.end()) | 
|  | Table.remove(I++); | 
|  | else { | 
|  | Types.erase(T); | 
|  | ++I; | 
|  | } | 
|  | } | 
|  | } | 
|  | // Find unnamed types. | 
|  | unsigned RenameCounter = 0; | 
|  | for (std::set<const Type *>::const_iterator I = Types.begin(), | 
|  | E = Types.end(); I!=E; ++I) | 
|  | if (const StructType *STy = dyn_cast<StructType>(*I)) { | 
|  | while (ModulePtr->addTypeName("unnamed$"+utostr(RenameCounter), STy)) | 
|  | ++RenameCounter; | 
|  | Changed = true; | 
|  | } | 
|  | // Pointer for FunctionPass. | 
|  | UsedTypes = &getAnalysis<FindUsedTypes>().getTypes(); | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | char MSILModule::ID = 0; | 
|  | char MSILWriter::ID = 0; | 
|  |  | 
|  | bool MSILWriter::runOnFunction(Function &F) { | 
|  | if (F.isDeclaration()) return false; | 
|  |  | 
|  | // Do not codegen any 'available_externally' functions at all, they have | 
|  | // definitions outside the translation unit. | 
|  | if (F.hasAvailableExternallyLinkage()) | 
|  | return false; | 
|  |  | 
|  | LInfo = &getAnalysis<LoopInfo>(); | 
|  | printFunction(F); | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | bool MSILWriter::doInitialization(Module &M) { | 
|  | ModulePtr = &M; | 
|  | Mang = new Mangler(M); | 
|  | Out << ".assembly extern mscorlib {}\n"; | 
|  | Out << ".assembly MSIL {}\n\n"; | 
|  | Out << "// External\n"; | 
|  | printExternals(); | 
|  | Out << "// Declarations\n"; | 
|  | printDeclarations(M.getTypeSymbolTable()); | 
|  | Out << "// Definitions\n"; | 
|  | printGlobalVariables(); | 
|  | Out << "// Startup code\n"; | 
|  | printModuleStartup(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | bool MSILWriter::doFinalization(Module &M) { | 
|  | delete Mang; | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printModuleStartup() { | 
|  | Out << | 
|  | ".method static public int32 $MSIL_Startup() {\n" | 
|  | "\t.entrypoint\n" | 
|  | "\t.locals (native int i)\n" | 
|  | "\t.locals (native int argc)\n" | 
|  | "\t.locals (native int ptr)\n" | 
|  | "\t.locals (void* argv)\n" | 
|  | "\t.locals (string[] args)\n" | 
|  | "\tcall\tstring[] [mscorlib]System.Environment::GetCommandLineArgs()\n" | 
|  | "\tdup\n" | 
|  | "\tstloc\targs\n" | 
|  | "\tldlen\n" | 
|  | "\tconv.i4\n" | 
|  | "\tdup\n" | 
|  | "\tstloc\targc\n"; | 
|  | printPtrLoad(TD->getPointerSize()); | 
|  | Out << | 
|  | "\tmul\n" | 
|  | "\tlocalloc\n" | 
|  | "\tstloc\targv\n" | 
|  | "\tldc.i4.0\n" | 
|  | "\tstloc\ti\n" | 
|  | "L_01:\n" | 
|  | "\tldloc\ti\n" | 
|  | "\tldloc\targc\n" | 
|  | "\tceq\n" | 
|  | "\tbrtrue\tL_02\n" | 
|  | "\tldloc\targs\n" | 
|  | "\tldloc\ti\n" | 
|  | "\tldelem.ref\n" | 
|  | "\tcall\tnative int [mscorlib]System.Runtime.InteropServices.Marshal::" | 
|  | "StringToHGlobalAnsi(string)\n" | 
|  | "\tstloc\tptr\n" | 
|  | "\tldloc\targv\n" | 
|  | "\tldloc\ti\n"; | 
|  | printPtrLoad(TD->getPointerSize()); | 
|  | Out << | 
|  | "\tmul\n" | 
|  | "\tadd\n" | 
|  | "\tldloc\tptr\n" | 
|  | "\tstind.i\n" | 
|  | "\tldloc\ti\n" | 
|  | "\tldc.i4.1\n" | 
|  | "\tadd\n" | 
|  | "\tstloc\ti\n" | 
|  | "\tbr\tL_01\n" | 
|  | "L_02:\n" | 
|  | "\tcall void $MSIL_Init()\n"; | 
|  |  | 
|  | // Call user 'main' function. | 
|  | const Function* F = ModulePtr->getFunction("main"); | 
|  | if (!F || F->isDeclaration()) { | 
|  | Out << "\tldc.i4.0\n\tret\n}\n"; | 
|  | return; | 
|  | } | 
|  | bool BadSig = true; | 
|  | std::string Args(""); | 
|  | Function::const_arg_iterator Arg1,Arg2; | 
|  |  | 
|  | switch (F->arg_size()) { | 
|  | case 0: | 
|  | BadSig = false; | 
|  | break; | 
|  | case 1: | 
|  | Arg1 = F->arg_begin(); | 
|  | if (Arg1->getType()->isInteger()) { | 
|  | Out << "\tldloc\targc\n"; | 
|  | Args = getTypeName(Arg1->getType()); | 
|  | BadSig = false; | 
|  | } | 
|  | break; | 
|  | case 2: | 
|  | Arg1 = Arg2 = F->arg_begin(); ++Arg2; | 
|  | if (Arg1->getType()->isInteger() && | 
|  | Arg2->getType()->getTypeID() == Type::PointerTyID) { | 
|  | Out << "\tldloc\targc\n\tldloc\targv\n"; | 
|  | Args = getTypeName(Arg1->getType())+","+getTypeName(Arg2->getType()); | 
|  | BadSig = false; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | BadSig = true; | 
|  | } | 
|  |  | 
|  | bool RetVoid = (F->getReturnType()->getTypeID() == Type::VoidTyID); | 
|  | if (BadSig || (!F->getReturnType()->isInteger() && !RetVoid)) { | 
|  | Out << "\tldc.i4.0\n"; | 
|  | } else { | 
|  | Out << "\tcall\t" << getTypeName(F->getReturnType()) << | 
|  | getConvModopt(F->getCallingConv()) << "main(" << Args << ")\n"; | 
|  | if (RetVoid) | 
|  | Out << "\tldc.i4.0\n"; | 
|  | else | 
|  | Out << "\tconv.i4\n"; | 
|  | } | 
|  | Out << "\tret\n}\n"; | 
|  | } | 
|  |  | 
|  | bool MSILWriter::isZeroValue(const Value* V) { | 
|  | if (const Constant *C = dyn_cast<Constant>(V)) | 
|  | return C->isNullValue(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getValueName(const Value* V) { | 
|  | std::string Name; | 
|  | if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) | 
|  | Name = Mang->getMangledName(GV); | 
|  | else { | 
|  | unsigned &No = AnonValueNumbers[V]; | 
|  | if (No == 0) No = ++NextAnonValueNumber; | 
|  | Name = "tmp" + utostr(No); | 
|  | } | 
|  |  | 
|  | // Name into the quotes allow control and space characters. | 
|  | return "'"+Name+"'"; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getLabelName(const std::string& Name) { | 
|  | if (Name.find('.')!=std::string::npos) { | 
|  | std::string Tmp(Name); | 
|  | // Replace unaccepable characters in the label name. | 
|  | for (std::string::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) | 
|  | if (*I=='.') *I = '@'; | 
|  | return Tmp; | 
|  | } | 
|  | return Name; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getLabelName(const Value* V) { | 
|  | std::string Name; | 
|  | if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) | 
|  | Name = Mang->getMangledName(GV); | 
|  | else { | 
|  | unsigned &No = AnonValueNumbers[V]; | 
|  | if (No == 0) No = ++NextAnonValueNumber; | 
|  | Name = "tmp" + utostr(No); | 
|  | } | 
|  |  | 
|  | return getLabelName(Name); | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getConvModopt(unsigned CallingConvID) { | 
|  | switch (CallingConvID) { | 
|  | case CallingConv::C: | 
|  | case CallingConv::Cold: | 
|  | case CallingConv::Fast: | 
|  | return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) "; | 
|  | case CallingConv::X86_FastCall: | 
|  | return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvFastcall) "; | 
|  | case CallingConv::X86_StdCall: | 
|  | return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) "; | 
|  | default: | 
|  | cerr << "CallingConvID = " << CallingConvID << '\n'; | 
|  | llvm_unreachable("Unsupported calling convention"); | 
|  | } | 
|  | return ""; // Not reached | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getArrayTypeName(Type::TypeID TyID, const Type* Ty) { | 
|  | std::string Tmp = ""; | 
|  | const Type* ElemTy = Ty; | 
|  | assert(Ty->getTypeID()==TyID && "Invalid type passed"); | 
|  | // Walk trought array element types. | 
|  | for (;;) { | 
|  | // Multidimensional array. | 
|  | if (ElemTy->getTypeID()==TyID) { | 
|  | if (const ArrayType* ATy = dyn_cast<ArrayType>(ElemTy)) | 
|  | Tmp += utostr(ATy->getNumElements()); | 
|  | else if (const VectorType* VTy = dyn_cast<VectorType>(ElemTy)) | 
|  | Tmp += utostr(VTy->getNumElements()); | 
|  | ElemTy = cast<SequentialType>(ElemTy)->getElementType(); | 
|  | } | 
|  | // Base element type found. | 
|  | if (ElemTy->getTypeID()!=TyID) break; | 
|  | Tmp += ","; | 
|  | } | 
|  | return getTypeName(ElemTy, false, true)+"["+Tmp+"]"; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getPrimitiveTypeName(const Type* Ty, bool isSigned) { | 
|  | unsigned NumBits = 0; | 
|  | switch (Ty->getTypeID()) { | 
|  | case Type::VoidTyID: | 
|  | return "void "; | 
|  | case Type::IntegerTyID: | 
|  | NumBits = getBitWidth(Ty); | 
|  | if(NumBits==1) | 
|  | return "bool "; | 
|  | if (!isSigned) | 
|  | return "unsigned int"+utostr(NumBits)+" "; | 
|  | return "int"+utostr(NumBits)+" "; | 
|  | case Type::FloatTyID: | 
|  | return "float32 "; | 
|  | case Type::DoubleTyID: | 
|  | return "float64 "; | 
|  | default: | 
|  | cerr << "Type = " << *Ty << '\n'; | 
|  | llvm_unreachable("Invalid primitive type"); | 
|  | } | 
|  | return ""; // Not reached | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned, | 
|  | bool isNested) { | 
|  | if (Ty->isPrimitiveType() || Ty->isInteger()) | 
|  | return getPrimitiveTypeName(Ty,isSigned); | 
|  | // FIXME: "OpaqueType" support | 
|  | switch (Ty->getTypeID()) { | 
|  | case Type::PointerTyID: | 
|  | return "void* "; | 
|  | case Type::StructTyID: | 
|  | if (isNested) | 
|  | return ModulePtr->getTypeName(Ty); | 
|  | return "valuetype '"+ModulePtr->getTypeName(Ty)+"' "; | 
|  | case Type::ArrayTyID: | 
|  | if (isNested) | 
|  | return getArrayTypeName(Ty->getTypeID(),Ty); | 
|  | return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' "; | 
|  | case Type::VectorTyID: | 
|  | if (isNested) | 
|  | return getArrayTypeName(Ty->getTypeID(),Ty); | 
|  | return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' "; | 
|  | default: | 
|  | cerr << "Type = " << *Ty << '\n'; | 
|  | llvm_unreachable("Invalid type in getTypeName()"); | 
|  | } | 
|  | return ""; // Not reached | 
|  | } | 
|  |  | 
|  |  | 
|  | MSILWriter::ValueType MSILWriter::getValueLocation(const Value* V) { | 
|  | // Function argument | 
|  | if (isa<Argument>(V)) | 
|  | return ArgumentVT; | 
|  | // Function | 
|  | else if (const Function* F = dyn_cast<Function>(V)) | 
|  | return F->hasLocalLinkage() ? InternalVT : GlobalVT; | 
|  | // Variable | 
|  | else if (const GlobalVariable* G = dyn_cast<GlobalVariable>(V)) | 
|  | return G->hasLocalLinkage() ? InternalVT : GlobalVT; | 
|  | // Constant | 
|  | else if (isa<Constant>(V)) | 
|  | return isa<ConstantExpr>(V) ? ConstExprVT : ConstVT; | 
|  | // Local variable | 
|  | return LocalVT; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getTypePostfix(const Type* Ty, bool Expand, | 
|  | bool isSigned) { | 
|  | unsigned NumBits = 0; | 
|  | switch (Ty->getTypeID()) { | 
|  | // Integer constant, expanding for stack operations. | 
|  | case Type::IntegerTyID: | 
|  | NumBits = getBitWidth(Ty); | 
|  | // Expand integer value to "int32" or "int64". | 
|  | if (Expand) return (NumBits<=32 ? "i4" : "i8"); | 
|  | if (NumBits==1) return "i1"; | 
|  | return (isSigned ? "i" : "u")+utostr(NumBits/8); | 
|  | // Float constant. | 
|  | case Type::FloatTyID: | 
|  | return "r4"; | 
|  | case Type::DoubleTyID: | 
|  | return "r8"; | 
|  | case Type::PointerTyID: | 
|  | return "i"+utostr(TD->getTypeAllocSize(Ty)); | 
|  | default: | 
|  | cerr << "TypeID = " << Ty->getTypeID() << '\n'; | 
|  | llvm_unreachable("Invalid type in TypeToPostfix()"); | 
|  | } | 
|  | return ""; // Not reached | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printConvToPtr() { | 
|  | switch (ModulePtr->getPointerSize()) { | 
|  | case Module::Pointer32: | 
|  | printSimpleInstruction("conv.u4"); | 
|  | break; | 
|  | case Module::Pointer64: | 
|  | printSimpleInstruction("conv.u8"); | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Module use not supporting pointer size"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printPtrLoad(uint64_t N) { | 
|  | switch (ModulePtr->getPointerSize()) { | 
|  | case Module::Pointer32: | 
|  | printSimpleInstruction("ldc.i4",utostr(N).c_str()); | 
|  | // FIXME: Need overflow test? | 
|  | if (!isUInt32(N)) { | 
|  | cerr << "Value = " << utostr(N) << '\n'; | 
|  | llvm_unreachable("32-bit pointer overflowed"); | 
|  | } | 
|  | break; | 
|  | case Module::Pointer64: | 
|  | printSimpleInstruction("ldc.i8",utostr(N).c_str()); | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Module use not supporting pointer size"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printValuePtrLoad(const Value* V) { | 
|  | printValueLoad(V); | 
|  | printConvToPtr(); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printConstLoad(const Constant* C) { | 
|  | if (const ConstantInt* CInt = dyn_cast<ConstantInt>(C)) { | 
|  | // Integer constant | 
|  | Out << "\tldc." << getTypePostfix(C->getType(),true) << '\t'; | 
|  | if (CInt->isMinValue(true)) | 
|  | Out << CInt->getSExtValue(); | 
|  | else | 
|  | Out << CInt->getZExtValue(); | 
|  | } else if (const ConstantFP* FP = dyn_cast<ConstantFP>(C)) { | 
|  | // Float constant | 
|  | uint64_t X; | 
|  | unsigned Size; | 
|  | if (FP->getType()->getTypeID()==Type::FloatTyID) { | 
|  | X = (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue(); | 
|  | Size = 4; | 
|  | } else { | 
|  | X = FP->getValueAPF().bitcastToAPInt().getZExtValue(); | 
|  | Size = 8; | 
|  | } | 
|  | Out << "\tldc.r" << Size << "\t( " << utohexstr(X) << ')'; | 
|  | } else if (isa<UndefValue>(C)) { | 
|  | // Undefined constant value = NULL. | 
|  | printPtrLoad(0); | 
|  | } else { | 
|  | cerr << "Constant = " << *C << '\n'; | 
|  | llvm_unreachable("Invalid constant value"); | 
|  | } | 
|  | Out << '\n'; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printValueLoad(const Value* V) { | 
|  | MSILWriter::ValueType Location = getValueLocation(V); | 
|  | switch (Location) { | 
|  | // Global variable or function address. | 
|  | case GlobalVT: | 
|  | case InternalVT: | 
|  | if (const Function* F = dyn_cast<Function>(V)) { | 
|  | std::string Name = getConvModopt(F->getCallingConv())+getValueName(F); | 
|  | printSimpleInstruction("ldftn", | 
|  | getCallSignature(F->getFunctionType(),NULL,Name).c_str()); | 
|  | } else { | 
|  | std::string Tmp; | 
|  | const Type* ElemTy = cast<PointerType>(V->getType())->getElementType(); | 
|  | if (Location==GlobalVT && cast<GlobalVariable>(V)->hasDLLImportLinkage()) { | 
|  | Tmp = "void* "+getValueName(V); | 
|  | printSimpleInstruction("ldsfld",Tmp.c_str()); | 
|  | } else { | 
|  | Tmp = getTypeName(ElemTy)+getValueName(V); | 
|  | printSimpleInstruction("ldsflda",Tmp.c_str()); | 
|  | } | 
|  | } | 
|  | break; | 
|  | // Function argument. | 
|  | case ArgumentVT: | 
|  | printSimpleInstruction("ldarg",getValueName(V).c_str()); | 
|  | break; | 
|  | // Local function variable. | 
|  | case LocalVT: | 
|  | printSimpleInstruction("ldloc",getValueName(V).c_str()); | 
|  | break; | 
|  | // Constant value. | 
|  | case ConstVT: | 
|  | if (isa<ConstantPointerNull>(V)) | 
|  | printPtrLoad(0); | 
|  | else | 
|  | printConstLoad(cast<Constant>(V)); | 
|  | break; | 
|  | // Constant expression. | 
|  | case ConstExprVT: | 
|  | printConstantExpr(cast<ConstantExpr>(V)); | 
|  | break; | 
|  | default: | 
|  | cerr << "Value = " << *V << '\n'; | 
|  | llvm_unreachable("Invalid value location"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printValueSave(const Value* V) { | 
|  | switch (getValueLocation(V)) { | 
|  | case ArgumentVT: | 
|  | printSimpleInstruction("starg",getValueName(V).c_str()); | 
|  | break; | 
|  | case LocalVT: | 
|  | printSimpleInstruction("stloc",getValueName(V).c_str()); | 
|  | break; | 
|  | default: | 
|  | cerr << "Value  = " << *V << '\n'; | 
|  | llvm_unreachable("Invalid value location"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printBinaryInstruction(const char* Name, const Value* Left, | 
|  | const Value* Right) { | 
|  | printValueLoad(Left); | 
|  | printValueLoad(Right); | 
|  | Out << '\t' << Name << '\n'; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printSimpleInstruction(const char* Inst, const char* Operand) { | 
|  | if(Operand) | 
|  | Out << '\t' << Inst << '\t' << Operand << '\n'; | 
|  | else | 
|  | Out << '\t' << Inst << '\n'; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printPHICopy(const BasicBlock* Src, const BasicBlock* Dst) { | 
|  | for (BasicBlock::const_iterator I = Dst->begin(), E = Dst->end(); | 
|  | isa<PHINode>(I); ++I) { | 
|  | const PHINode* Phi = cast<PHINode>(I); | 
|  | const Value* Val = Phi->getIncomingValueForBlock(Src); | 
|  | if (isa<UndefValue>(Val)) continue; | 
|  | printValueLoad(Val); | 
|  | printValueSave(Phi); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printBranchToBlock(const BasicBlock* CurrBB, | 
|  | const BasicBlock* TrueBB, | 
|  | const BasicBlock* FalseBB) { | 
|  | if (TrueBB==FalseBB) { | 
|  | // "TrueBB" and "FalseBB" destination equals | 
|  | printPHICopy(CurrBB,TrueBB); | 
|  | printSimpleInstruction("pop"); | 
|  | printSimpleInstruction("br",getLabelName(TrueBB).c_str()); | 
|  | } else if (FalseBB==NULL) { | 
|  | // If "FalseBB" not used the jump have condition | 
|  | printPHICopy(CurrBB,TrueBB); | 
|  | printSimpleInstruction("brtrue",getLabelName(TrueBB).c_str()); | 
|  | } else if (TrueBB==NULL) { | 
|  | // If "TrueBB" not used the jump is unconditional | 
|  | printPHICopy(CurrBB,FalseBB); | 
|  | printSimpleInstruction("br",getLabelName(FalseBB).c_str()); | 
|  | } else { | 
|  | // Copy PHI instructions for each block | 
|  | std::string TmpLabel; | 
|  | // Print PHI instructions for "TrueBB" | 
|  | if (isa<PHINode>(TrueBB->begin())) { | 
|  | TmpLabel = getLabelName(TrueBB)+"$phi_"+utostr(getUniqID()); | 
|  | printSimpleInstruction("brtrue",TmpLabel.c_str()); | 
|  | } else { | 
|  | printSimpleInstruction("brtrue",getLabelName(TrueBB).c_str()); | 
|  | } | 
|  | // Print PHI instructions for "FalseBB" | 
|  | if (isa<PHINode>(FalseBB->begin())) { | 
|  | printPHICopy(CurrBB,FalseBB); | 
|  | printSimpleInstruction("br",getLabelName(FalseBB).c_str()); | 
|  | } else { | 
|  | printSimpleInstruction("br",getLabelName(FalseBB).c_str()); | 
|  | } | 
|  | if (isa<PHINode>(TrueBB->begin())) { | 
|  | // Handle "TrueBB" PHI Copy | 
|  | Out << TmpLabel << ":\n"; | 
|  | printPHICopy(CurrBB,TrueBB); | 
|  | printSimpleInstruction("br",getLabelName(TrueBB).c_str()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printBranchInstruction(const BranchInst* Inst) { | 
|  | if (Inst->isUnconditional()) { | 
|  | printBranchToBlock(Inst->getParent(),NULL,Inst->getSuccessor(0)); | 
|  | } else { | 
|  | printValueLoad(Inst->getCondition()); | 
|  | printBranchToBlock(Inst->getParent(),Inst->getSuccessor(0), | 
|  | Inst->getSuccessor(1)); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printSelectInstruction(const Value* Cond, const Value* VTrue, | 
|  | const Value* VFalse) { | 
|  | std::string TmpLabel = std::string("select$true_")+utostr(getUniqID()); | 
|  | printValueLoad(VTrue); | 
|  | printValueLoad(Cond); | 
|  | printSimpleInstruction("brtrue",TmpLabel.c_str()); | 
|  | printSimpleInstruction("pop"); | 
|  | printValueLoad(VFalse); | 
|  | Out << TmpLabel << ":\n"; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printIndirectLoad(const Value* V) { | 
|  | const Type* Ty = V->getType(); | 
|  | printValueLoad(V); | 
|  | if (const PointerType* P = dyn_cast<PointerType>(Ty)) | 
|  | Ty = P->getElementType(); | 
|  | std::string Tmp = "ldind."+getTypePostfix(Ty, false); | 
|  | printSimpleInstruction(Tmp.c_str()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printIndirectSave(const Value* Ptr, const Value* Val) { | 
|  | printValueLoad(Ptr); | 
|  | printValueLoad(Val); | 
|  | printIndirectSave(Val->getType()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printIndirectSave(const Type* Ty) { | 
|  | // Instruction need signed postfix for any type. | 
|  | std::string postfix = getTypePostfix(Ty, false); | 
|  | if (*postfix.begin()=='u') *postfix.begin() = 'i'; | 
|  | postfix = "stind."+postfix; | 
|  | printSimpleInstruction(postfix.c_str()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printCastInstruction(unsigned int Op, const Value* V, | 
|  | const Type* Ty, const Type* SrcTy) { | 
|  | std::string Tmp(""); | 
|  | printValueLoad(V); | 
|  | switch (Op) { | 
|  | // Signed | 
|  | case Instruction::SExt: | 
|  | // If sign extending int, convert first from unsigned to signed | 
|  | // with the same bit size - because otherwise we will loose the sign. | 
|  | if (SrcTy) { | 
|  | Tmp = "conv."+getTypePostfix(SrcTy,false,true); | 
|  | printSimpleInstruction(Tmp.c_str()); | 
|  | } | 
|  | // FALLTHROUGH | 
|  | case Instruction::SIToFP: | 
|  | case Instruction::FPToSI: | 
|  | Tmp = "conv."+getTypePostfix(Ty,false,true); | 
|  | printSimpleInstruction(Tmp.c_str()); | 
|  | break; | 
|  | // Unsigned | 
|  | case Instruction::FPTrunc: | 
|  | case Instruction::FPExt: | 
|  | case Instruction::UIToFP: | 
|  | case Instruction::Trunc: | 
|  | case Instruction::ZExt: | 
|  | case Instruction::FPToUI: | 
|  | case Instruction::PtrToInt: | 
|  | case Instruction::IntToPtr: | 
|  | Tmp = "conv."+getTypePostfix(Ty,false); | 
|  | printSimpleInstruction(Tmp.c_str()); | 
|  | break; | 
|  | // Do nothing | 
|  | case Instruction::BitCast: | 
|  | // FIXME: meaning that ld*/st* instruction do not change data format. | 
|  | break; | 
|  | default: | 
|  | cerr << "Opcode = " << Op << '\n'; | 
|  | llvm_unreachable("Invalid conversion instruction"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printGepInstruction(const Value* V, gep_type_iterator I, | 
|  | gep_type_iterator E) { | 
|  | unsigned Size; | 
|  | // Load address | 
|  | printValuePtrLoad(V); | 
|  | // Calculate element offset. | 
|  | for (; I!=E; ++I){ | 
|  | Size = 0; | 
|  | const Value* IndexValue = I.getOperand(); | 
|  | if (const StructType* StrucTy = dyn_cast<StructType>(*I)) { | 
|  | uint64_t FieldIndex = cast<ConstantInt>(IndexValue)->getZExtValue(); | 
|  | // Offset is the sum of all previous structure fields. | 
|  | for (uint64_t F = 0; F<FieldIndex; ++F) | 
|  | Size += TD->getTypeAllocSize(StrucTy->getContainedType((unsigned)F)); | 
|  | printPtrLoad(Size); | 
|  | printSimpleInstruction("add"); | 
|  | continue; | 
|  | } else if (const SequentialType* SeqTy = dyn_cast<SequentialType>(*I)) { | 
|  | Size = TD->getTypeAllocSize(SeqTy->getElementType()); | 
|  | } else { | 
|  | Size = TD->getTypeAllocSize(*I); | 
|  | } | 
|  | // Add offset of current element to stack top. | 
|  | if (!isZeroValue(IndexValue)) { | 
|  | // Constant optimization. | 
|  | if (const ConstantInt* C = dyn_cast<ConstantInt>(IndexValue)) { | 
|  | if (C->getValue().isNegative()) { | 
|  | printPtrLoad(C->getValue().abs().getZExtValue()*Size); | 
|  | printSimpleInstruction("sub"); | 
|  | continue; | 
|  | } else | 
|  | printPtrLoad(C->getZExtValue()*Size); | 
|  | } else { | 
|  | printPtrLoad(Size); | 
|  | printValuePtrLoad(IndexValue); | 
|  | printSimpleInstruction("mul"); | 
|  | } | 
|  | printSimpleInstruction("add"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | std::string MSILWriter::getCallSignature(const FunctionType* Ty, | 
|  | const Instruction* Inst, | 
|  | std::string Name) { | 
|  | std::string Tmp(""); | 
|  | if (Ty->isVarArg()) Tmp += "vararg "; | 
|  | // Name and return type. | 
|  | Tmp += getTypeName(Ty->getReturnType())+Name+"("; | 
|  | // Function argument type list. | 
|  | unsigned NumParams = Ty->getNumParams(); | 
|  | for (unsigned I = 0; I!=NumParams; ++I) { | 
|  | if (I!=0) Tmp += ","; | 
|  | Tmp += getTypeName(Ty->getParamType(I)); | 
|  | } | 
|  | // CLR needs to know the exact amount of parameters received by vararg | 
|  | // function, because caller cleans the stack. | 
|  | if (Ty->isVarArg() && Inst) { | 
|  | // Origin to function arguments in "CallInst" or "InvokeInst". | 
|  | unsigned Org = isa<InvokeInst>(Inst) ? 3 : 1; | 
|  | // Print variable argument types. | 
|  | unsigned NumOperands = Inst->getNumOperands()-Org; | 
|  | if (NumParams<NumOperands) { | 
|  | if (NumParams!=0) Tmp += ", "; | 
|  | Tmp += "... , "; | 
|  | for (unsigned J = NumParams; J!=NumOperands; ++J) { | 
|  | if (J!=NumParams) Tmp += ", "; | 
|  | Tmp += getTypeName(Inst->getOperand(J+Org)->getType()); | 
|  | } | 
|  | } | 
|  | } | 
|  | return Tmp+")"; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printFunctionCall(const Value* FnVal, | 
|  | const Instruction* Inst) { | 
|  | // Get function calling convention. | 
|  | std::string Name = ""; | 
|  | if (const CallInst* Call = dyn_cast<CallInst>(Inst)) | 
|  | Name = getConvModopt(Call->getCallingConv()); | 
|  | else if (const InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) | 
|  | Name = getConvModopt(Invoke->getCallingConv()); | 
|  | else { | 
|  | cerr << "Instruction = " << Inst->getName() << '\n'; | 
|  | llvm_unreachable("Need \"Invoke\" or \"Call\" instruction only"); | 
|  | } | 
|  | if (const Function* F = dyn_cast<Function>(FnVal)) { | 
|  | // Direct call. | 
|  | Name += getValueName(F); | 
|  | printSimpleInstruction("call", | 
|  | getCallSignature(F->getFunctionType(),Inst,Name).c_str()); | 
|  | } else { | 
|  | // Indirect function call. | 
|  | const PointerType* PTy = cast<PointerType>(FnVal->getType()); | 
|  | const FunctionType* FTy = cast<FunctionType>(PTy->getElementType()); | 
|  | // Load function address. | 
|  | printValueLoad(FnVal); | 
|  | printSimpleInstruction("calli",getCallSignature(FTy,Inst,Name).c_str()); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printIntrinsicCall(const IntrinsicInst* Inst) { | 
|  | std::string Name; | 
|  | switch (Inst->getIntrinsicID()) { | 
|  | case Intrinsic::vastart: | 
|  | Name = getValueName(Inst->getOperand(1)); | 
|  | Name.insert(Name.length()-1,"$valist"); | 
|  | // Obtain the argument handle. | 
|  | printSimpleInstruction("ldloca",Name.c_str()); | 
|  | printSimpleInstruction("arglist"); | 
|  | printSimpleInstruction("call", | 
|  | "instance void [mscorlib]System.ArgIterator::.ctor" | 
|  | "(valuetype [mscorlib]System.RuntimeArgumentHandle)"); | 
|  | // Save as pointer type "void*" | 
|  | printValueLoad(Inst->getOperand(1)); | 
|  | printSimpleInstruction("ldloca",Name.c_str()); | 
|  | printIndirectSave(PointerType::getUnqual(IntegerType::get(8))); | 
|  | break; | 
|  | case Intrinsic::vaend: | 
|  | // Close argument list handle. | 
|  | printIndirectLoad(Inst->getOperand(1)); | 
|  | printSimpleInstruction("call","instance void [mscorlib]System.ArgIterator::End()"); | 
|  | break; | 
|  | case Intrinsic::vacopy: | 
|  | // Copy "ArgIterator" valuetype. | 
|  | printIndirectLoad(Inst->getOperand(1)); | 
|  | printIndirectLoad(Inst->getOperand(2)); | 
|  | printSimpleInstruction("cpobj","[mscorlib]System.ArgIterator"); | 
|  | break; | 
|  | default: | 
|  | cerr << "Intrinsic ID = " << Inst->getIntrinsicID() << '\n'; | 
|  | llvm_unreachable("Invalid intrinsic function"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printCallInstruction(const Instruction* Inst) { | 
|  | if (isa<IntrinsicInst>(Inst)) { | 
|  | // Handle intrinsic function. | 
|  | printIntrinsicCall(cast<IntrinsicInst>(Inst)); | 
|  | } else { | 
|  | // Load arguments to stack and call function. | 
|  | for (int I = 1, E = Inst->getNumOperands(); I!=E; ++I) | 
|  | printValueLoad(Inst->getOperand(I)); | 
|  | printFunctionCall(Inst->getOperand(0),Inst); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printICmpInstruction(unsigned Predicate, const Value* Left, | 
|  | const Value* Right) { | 
|  | switch (Predicate) { | 
|  | case ICmpInst::ICMP_EQ: | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | break; | 
|  | case ICmpInst::ICMP_NE: | 
|  | // Emulate = not neg (Op1 eq Op2) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printSimpleInstruction("neg"); | 
|  | printSimpleInstruction("not"); | 
|  | break; | 
|  | case ICmpInst::ICMP_ULE: | 
|  | case ICmpInst::ICMP_SLE: | 
|  | // Emulate = (Op1 eq Op2) or (Op1 lt Op2) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | if (Predicate==ICmpInst::ICMP_ULE) | 
|  | printBinaryInstruction("clt.un",Left,Right); | 
|  | else | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case ICmpInst::ICMP_UGE: | 
|  | case ICmpInst::ICMP_SGE: | 
|  | // Emulate = (Op1 eq Op2) or (Op1 gt Op2) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | if (Predicate==ICmpInst::ICMP_UGE) | 
|  | printBinaryInstruction("cgt.un",Left,Right); | 
|  | else | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case ICmpInst::ICMP_ULT: | 
|  | printBinaryInstruction("clt.un",Left,Right); | 
|  | break; | 
|  | case ICmpInst::ICMP_SLT: | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | break; | 
|  | case ICmpInst::ICMP_UGT: | 
|  | printBinaryInstruction("cgt.un",Left,Right); | 
|  | break; | 
|  | case ICmpInst::ICMP_SGT: | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | break; | 
|  | default: | 
|  | cerr << "Predicate = " << Predicate << '\n'; | 
|  | llvm_unreachable("Invalid icmp predicate"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printFCmpInstruction(unsigned Predicate, const Value* Left, | 
|  | const Value* Right) { | 
|  | // FIXME: Correct comparison | 
|  | std::string NanFunc = "bool [mscorlib]System.Double::IsNaN(float64)"; | 
|  | switch (Predicate) { | 
|  | case FCmpInst::FCMP_UGT: | 
|  | // X >  Y || llvm_fcmp_uno(X, Y) | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_OGT: | 
|  | // X >  Y | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | break; | 
|  | case FCmpInst::FCMP_UGE: | 
|  | // X >= Y || llvm_fcmp_uno(X, Y) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_OGE: | 
|  | // X >= Y | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printBinaryInstruction("cgt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_ULT: | 
|  | // X <  Y || llvm_fcmp_uno(X, Y) | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_OLT: | 
|  | // X <  Y | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | break; | 
|  | case FCmpInst::FCMP_ULE: | 
|  | // X <= Y || llvm_fcmp_uno(X, Y) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_OLE: | 
|  | // X <= Y | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printBinaryInstruction("clt",Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_UEQ: | 
|  | // X == Y || llvm_fcmp_uno(X, Y) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_OEQ: | 
|  | // X == Y | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | break; | 
|  | case FCmpInst::FCMP_UNE: | 
|  | // X != Y | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printSimpleInstruction("neg"); | 
|  | printSimpleInstruction("not"); | 
|  | break; | 
|  | case FCmpInst::FCMP_ONE: | 
|  | // X != Y && llvm_fcmp_ord(X, Y) | 
|  | printBinaryInstruction("ceq",Left,Right); | 
|  | printSimpleInstruction("not"); | 
|  | break; | 
|  | case FCmpInst::FCMP_ORD: | 
|  | // return X == X && Y == Y | 
|  | printBinaryInstruction("ceq",Left,Left); | 
|  | printBinaryInstruction("ceq",Right,Right); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | case FCmpInst::FCMP_UNO: | 
|  | // X != X || Y != Y | 
|  | printBinaryInstruction("ceq",Left,Left); | 
|  | printSimpleInstruction("not"); | 
|  | printBinaryInstruction("ceq",Right,Right); | 
|  | printSimpleInstruction("not"); | 
|  | printSimpleInstruction("or"); | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Illegal FCmp predicate"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printInvokeInstruction(const InvokeInst* Inst) { | 
|  | std::string Label = "leave$normal_"+utostr(getUniqID()); | 
|  | Out << ".try {\n"; | 
|  | // Load arguments | 
|  | for (int I = 3, E = Inst->getNumOperands(); I!=E; ++I) | 
|  | printValueLoad(Inst->getOperand(I)); | 
|  | // Print call instruction | 
|  | printFunctionCall(Inst->getOperand(0),Inst); | 
|  | // Save function result and leave "try" block | 
|  | printValueSave(Inst); | 
|  | printSimpleInstruction("leave",Label.c_str()); | 
|  | Out << "}\n"; | 
|  | Out << "catch [mscorlib]System.Exception {\n"; | 
|  | // Redirect to unwind block | 
|  | printSimpleInstruction("pop"); | 
|  | printBranchToBlock(Inst->getParent(),NULL,Inst->getUnwindDest()); | 
|  | Out << "}\n" << Label << ":\n"; | 
|  | // Redirect to continue block | 
|  | printBranchToBlock(Inst->getParent(),NULL,Inst->getNormalDest()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printSwitchInstruction(const SwitchInst* Inst) { | 
|  | // FIXME: Emulate with IL "switch" instruction | 
|  | // Emulate = if () else if () else if () else ... | 
|  | for (unsigned int I = 1, E = Inst->getNumCases(); I!=E; ++I) { | 
|  | printValueLoad(Inst->getCondition()); | 
|  | printValueLoad(Inst->getCaseValue(I)); | 
|  | printSimpleInstruction("ceq"); | 
|  | // Condition jump to successor block | 
|  | printBranchToBlock(Inst->getParent(),Inst->getSuccessor(I),NULL); | 
|  | } | 
|  | // Jump to default block | 
|  | printBranchToBlock(Inst->getParent(),NULL,Inst->getDefaultDest()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printVAArgInstruction(const VAArgInst* Inst) { | 
|  | printIndirectLoad(Inst->getOperand(0)); | 
|  | printSimpleInstruction("call", | 
|  | "instance typedref [mscorlib]System.ArgIterator::GetNextArg()"); | 
|  | printSimpleInstruction("refanyval","void*"); | 
|  | std::string Name = | 
|  | "ldind."+getTypePostfix(PointerType::getUnqual(IntegerType::get(8)),false); | 
|  | printSimpleInstruction(Name.c_str()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printAllocaInstruction(const AllocaInst* Inst) { | 
|  | uint64_t Size = TD->getTypeAllocSize(Inst->getAllocatedType()); | 
|  | // Constant optimization. | 
|  | if (const ConstantInt* CInt = dyn_cast<ConstantInt>(Inst->getOperand(0))) { | 
|  | printPtrLoad(CInt->getZExtValue()*Size); | 
|  | } else { | 
|  | printPtrLoad(Size); | 
|  | printValueLoad(Inst->getOperand(0)); | 
|  | printSimpleInstruction("mul"); | 
|  | } | 
|  | printSimpleInstruction("localloc"); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printInstruction(const Instruction* Inst) { | 
|  | const Value *Left = 0, *Right = 0; | 
|  | if (Inst->getNumOperands()>=1) Left = Inst->getOperand(0); | 
|  | if (Inst->getNumOperands()>=2) Right = Inst->getOperand(1); | 
|  | // Print instruction | 
|  | // FIXME: "ShuffleVector","ExtractElement","InsertElement" support. | 
|  | switch (Inst->getOpcode()) { | 
|  | // Terminator | 
|  | case Instruction::Ret: | 
|  | if (Inst->getNumOperands()) { | 
|  | printValueLoad(Left); | 
|  | printSimpleInstruction("ret"); | 
|  | } else | 
|  | printSimpleInstruction("ret"); | 
|  | break; | 
|  | case Instruction::Br: | 
|  | printBranchInstruction(cast<BranchInst>(Inst)); | 
|  | break; | 
|  | // Binary | 
|  | case Instruction::Add: | 
|  | case Instruction::FAdd: | 
|  | printBinaryInstruction("add",Left,Right); | 
|  | break; | 
|  | case Instruction::Sub: | 
|  | case Instruction::FSub: | 
|  | printBinaryInstruction("sub",Left,Right); | 
|  | break; | 
|  | case Instruction::Mul: | 
|  | case Instruction::FMul: | 
|  | printBinaryInstruction("mul",Left,Right); | 
|  | break; | 
|  | case Instruction::UDiv: | 
|  | printBinaryInstruction("div.un",Left,Right); | 
|  | break; | 
|  | case Instruction::SDiv: | 
|  | case Instruction::FDiv: | 
|  | printBinaryInstruction("div",Left,Right); | 
|  | break; | 
|  | case Instruction::URem: | 
|  | printBinaryInstruction("rem.un",Left,Right); | 
|  | break; | 
|  | case Instruction::SRem: | 
|  | case Instruction::FRem: | 
|  | printBinaryInstruction("rem",Left,Right); | 
|  | break; | 
|  | // Binary Condition | 
|  | case Instruction::ICmp: | 
|  | printICmpInstruction(cast<ICmpInst>(Inst)->getPredicate(),Left,Right); | 
|  | break; | 
|  | case Instruction::FCmp: | 
|  | printFCmpInstruction(cast<FCmpInst>(Inst)->getPredicate(),Left,Right); | 
|  | break; | 
|  | // Bitwise Binary | 
|  | case Instruction::And: | 
|  | printBinaryInstruction("and",Left,Right); | 
|  | break; | 
|  | case Instruction::Or: | 
|  | printBinaryInstruction("or",Left,Right); | 
|  | break; | 
|  | case Instruction::Xor: | 
|  | printBinaryInstruction("xor",Left,Right); | 
|  | break; | 
|  | case Instruction::Shl: | 
|  | printValueLoad(Left); | 
|  | printValueLoad(Right); | 
|  | printSimpleInstruction("conv.i4"); | 
|  | printSimpleInstruction("shl"); | 
|  | break; | 
|  | case Instruction::LShr: | 
|  | printValueLoad(Left); | 
|  | printValueLoad(Right); | 
|  | printSimpleInstruction("conv.i4"); | 
|  | printSimpleInstruction("shr.un"); | 
|  | break; | 
|  | case Instruction::AShr: | 
|  | printValueLoad(Left); | 
|  | printValueLoad(Right); | 
|  | printSimpleInstruction("conv.i4"); | 
|  | printSimpleInstruction("shr"); | 
|  | break; | 
|  | case Instruction::Select: | 
|  | printSelectInstruction(Inst->getOperand(0),Inst->getOperand(1),Inst->getOperand(2)); | 
|  | break; | 
|  | case Instruction::Load: | 
|  | printIndirectLoad(Inst->getOperand(0)); | 
|  | break; | 
|  | case Instruction::Store: | 
|  | printIndirectSave(Inst->getOperand(1), Inst->getOperand(0)); | 
|  | break; | 
|  | case Instruction::SExt: | 
|  | printCastInstruction(Inst->getOpcode(),Left, | 
|  | cast<CastInst>(Inst)->getDestTy(), | 
|  | cast<CastInst>(Inst)->getSrcTy()); | 
|  | break; | 
|  | case Instruction::Trunc: | 
|  | case Instruction::ZExt: | 
|  | case Instruction::FPTrunc: | 
|  | case Instruction::FPExt: | 
|  | case Instruction::UIToFP: | 
|  | case Instruction::SIToFP: | 
|  | case Instruction::FPToUI: | 
|  | case Instruction::FPToSI: | 
|  | case Instruction::PtrToInt: | 
|  | case Instruction::IntToPtr: | 
|  | case Instruction::BitCast: | 
|  | printCastInstruction(Inst->getOpcode(),Left, | 
|  | cast<CastInst>(Inst)->getDestTy()); | 
|  | break; | 
|  | case Instruction::GetElementPtr: | 
|  | printGepInstruction(Inst->getOperand(0),gep_type_begin(Inst), | 
|  | gep_type_end(Inst)); | 
|  | break; | 
|  | case Instruction::Call: | 
|  | printCallInstruction(cast<CallInst>(Inst)); | 
|  | break; | 
|  | case Instruction::Invoke: | 
|  | printInvokeInstruction(cast<InvokeInst>(Inst)); | 
|  | break; | 
|  | case Instruction::Unwind: | 
|  | printSimpleInstruction("newobj", | 
|  | "instance void [mscorlib]System.Exception::.ctor()"); | 
|  | printSimpleInstruction("throw"); | 
|  | break; | 
|  | case Instruction::Switch: | 
|  | printSwitchInstruction(cast<SwitchInst>(Inst)); | 
|  | break; | 
|  | case Instruction::Alloca: | 
|  | printAllocaInstruction(cast<AllocaInst>(Inst)); | 
|  | break; | 
|  | case Instruction::Malloc: | 
|  | llvm_unreachable("LowerAllocationsPass used"); | 
|  | break; | 
|  | case Instruction::Free: | 
|  | llvm_unreachable("LowerAllocationsPass used"); | 
|  | break; | 
|  | case Instruction::Unreachable: | 
|  | printSimpleInstruction("ldstr", "\"Unreachable instruction\""); | 
|  | printSimpleInstruction("newobj", | 
|  | "instance void [mscorlib]System.Exception::.ctor(string)"); | 
|  | printSimpleInstruction("throw"); | 
|  | break; | 
|  | case Instruction::VAArg: | 
|  | printVAArgInstruction(cast<VAArgInst>(Inst)); | 
|  | break; | 
|  | default: | 
|  | cerr << "Instruction = " << Inst->getName() << '\n'; | 
|  | llvm_unreachable("Unsupported instruction"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printLoop(const Loop* L) { | 
|  | Out << getLabelName(L->getHeader()->getName()) << ":\n"; | 
|  | const std::vector<BasicBlock*>& blocks = L->getBlocks(); | 
|  | for (unsigned I = 0, E = blocks.size(); I!=E; I++) { | 
|  | BasicBlock* BB = blocks[I]; | 
|  | Loop* BBLoop = LInfo->getLoopFor(BB); | 
|  | if (BBLoop == L) | 
|  | printBasicBlock(BB); | 
|  | else if (BB==BBLoop->getHeader() && BBLoop->getParentLoop()==L) | 
|  | printLoop(BBLoop); | 
|  | } | 
|  | printSimpleInstruction("br",getLabelName(L->getHeader()->getName()).c_str()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printBasicBlock(const BasicBlock* BB) { | 
|  | Out << getLabelName(BB) << ":\n"; | 
|  | for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E; ++I) { | 
|  | const Instruction* Inst = I; | 
|  | // Comment llvm original instruction | 
|  | // Out << "\n//" << *Inst << "\n"; | 
|  | // Do not handle PHI instruction in current block | 
|  | if (Inst->getOpcode()==Instruction::PHI) continue; | 
|  | // Print instruction | 
|  | printInstruction(Inst); | 
|  | // Save result | 
|  | if (Inst->getType()!=Type::VoidTy) { | 
|  | // Do not save value after invoke, it done in "try" block | 
|  | if (Inst->getOpcode()==Instruction::Invoke) continue; | 
|  | printValueSave(Inst); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printLocalVariables(const Function& F) { | 
|  | std::string Name; | 
|  | const Type* Ty = NULL; | 
|  | std::set<const Value*> Printed; | 
|  | const Value* VaList = NULL; | 
|  | unsigned StackDepth = 8; | 
|  | // Find local variables | 
|  | for (const_inst_iterator I = inst_begin(&F), E = inst_end(&F); I!=E; ++I) { | 
|  | if (I->getOpcode()==Instruction::Call || | 
|  | I->getOpcode()==Instruction::Invoke) { | 
|  | // Test stack depth. | 
|  | if (StackDepth<I->getNumOperands()) | 
|  | StackDepth = I->getNumOperands(); | 
|  | } | 
|  | const AllocaInst* AI = dyn_cast<AllocaInst>(&*I); | 
|  | if (AI && !isa<GlobalVariable>(AI)) { | 
|  | // Local variable allocation. | 
|  | Ty = PointerType::getUnqual(AI->getAllocatedType()); | 
|  | Name = getValueName(AI); | 
|  | Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; | 
|  | } else if (I->getType()!=Type::VoidTy) { | 
|  | // Operation result. | 
|  | Ty = I->getType(); | 
|  | Name = getValueName(&*I); | 
|  | Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; | 
|  | } | 
|  | // Test on 'va_list' variable | 
|  | bool isVaList = false; | 
|  | if (const VAArgInst* VaInst = dyn_cast<VAArgInst>(&*I)) { | 
|  | // "va_list" as "va_arg" instruction operand. | 
|  | isVaList = true; | 
|  | VaList = VaInst->getOperand(0); | 
|  | } else if (const IntrinsicInst* Inst = dyn_cast<IntrinsicInst>(&*I)) { | 
|  | // "va_list" as intrinsic function operand. | 
|  | switch (Inst->getIntrinsicID()) { | 
|  | case Intrinsic::vastart: | 
|  | case Intrinsic::vaend: | 
|  | case Intrinsic::vacopy: | 
|  | isVaList = true; | 
|  | VaList = Inst->getOperand(1); | 
|  | break; | 
|  | default: | 
|  | isVaList = false; | 
|  | } | 
|  | } | 
|  | // Print "va_list" variable. | 
|  | if (isVaList && Printed.insert(VaList).second) { | 
|  | Name = getValueName(VaList); | 
|  | Name.insert(Name.length()-1,"$valist"); | 
|  | Out << "\t.locals (valuetype [mscorlib]System.ArgIterator " | 
|  | << Name << ")\n"; | 
|  | } | 
|  | } | 
|  | printSimpleInstruction(".maxstack",utostr(StackDepth*2).c_str()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printFunctionBody(const Function& F) { | 
|  | // Print body | 
|  | for (Function::const_iterator I = F.begin(), E = F.end(); I!=E; ++I) { | 
|  | if (Loop *L = LInfo->getLoopFor(I)) { | 
|  | if (L->getHeader()==I && L->getParentLoop()==0) | 
|  | printLoop(L); | 
|  | } else { | 
|  | printBasicBlock(I); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printConstantExpr(const ConstantExpr* CE) { | 
|  | const Value *left = 0, *right = 0; | 
|  | if (CE->getNumOperands()>=1) left = CE->getOperand(0); | 
|  | if (CE->getNumOperands()>=2) right = CE->getOperand(1); | 
|  | // Print instruction | 
|  | switch (CE->getOpcode()) { | 
|  | case Instruction::Trunc: | 
|  | case Instruction::ZExt: | 
|  | case Instruction::SExt: | 
|  | case Instruction::FPTrunc: | 
|  | case Instruction::FPExt: | 
|  | case Instruction::UIToFP: | 
|  | case Instruction::SIToFP: | 
|  | case Instruction::FPToUI: | 
|  | case Instruction::FPToSI: | 
|  | case Instruction::PtrToInt: | 
|  | case Instruction::IntToPtr: | 
|  | case Instruction::BitCast: | 
|  | printCastInstruction(CE->getOpcode(),left,CE->getType()); | 
|  | break; | 
|  | case Instruction::GetElementPtr: | 
|  | printGepInstruction(CE->getOperand(0),gep_type_begin(CE),gep_type_end(CE)); | 
|  | break; | 
|  | case Instruction::ICmp: | 
|  | printICmpInstruction(CE->getPredicate(),left,right); | 
|  | break; | 
|  | case Instruction::FCmp: | 
|  | printFCmpInstruction(CE->getPredicate(),left,right); | 
|  | break; | 
|  | case Instruction::Select: | 
|  | printSelectInstruction(CE->getOperand(0),CE->getOperand(1),CE->getOperand(2)); | 
|  | break; | 
|  | case Instruction::Add: | 
|  | case Instruction::FAdd: | 
|  | printBinaryInstruction("add",left,right); | 
|  | break; | 
|  | case Instruction::Sub: | 
|  | case Instruction::FSub: | 
|  | printBinaryInstruction("sub",left,right); | 
|  | break; | 
|  | case Instruction::Mul: | 
|  | case Instruction::FMul: | 
|  | printBinaryInstruction("mul",left,right); | 
|  | break; | 
|  | case Instruction::UDiv: | 
|  | printBinaryInstruction("div.un",left,right); | 
|  | break; | 
|  | case Instruction::SDiv: | 
|  | case Instruction::FDiv: | 
|  | printBinaryInstruction("div",left,right); | 
|  | break; | 
|  | case Instruction::URem: | 
|  | printBinaryInstruction("rem.un",left,right); | 
|  | break; | 
|  | case Instruction::SRem: | 
|  | case Instruction::FRem: | 
|  | printBinaryInstruction("rem",left,right); | 
|  | break; | 
|  | case Instruction::And: | 
|  | printBinaryInstruction("and",left,right); | 
|  | break; | 
|  | case Instruction::Or: | 
|  | printBinaryInstruction("or",left,right); | 
|  | break; | 
|  | case Instruction::Xor: | 
|  | printBinaryInstruction("xor",left,right); | 
|  | break; | 
|  | case Instruction::Shl: | 
|  | printBinaryInstruction("shl",left,right); | 
|  | break; | 
|  | case Instruction::LShr: | 
|  | printBinaryInstruction("shr.un",left,right); | 
|  | break; | 
|  | case Instruction::AShr: | 
|  | printBinaryInstruction("shr",left,right); | 
|  | break; | 
|  | default: | 
|  | cerr << "Expression = " << *CE << "\n"; | 
|  | llvm_unreachable("Invalid constant expression"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printStaticInitializerList() { | 
|  | // List of global variables with uninitialized fields. | 
|  | for (std::map<const GlobalVariable*,std::vector<StaticInitializer> >::iterator | 
|  | VarI = StaticInitList.begin(), VarE = StaticInitList.end(); VarI!=VarE; | 
|  | ++VarI) { | 
|  | const std::vector<StaticInitializer>& InitList = VarI->second; | 
|  | if (InitList.empty()) continue; | 
|  | // For each uninitialized field. | 
|  | for (std::vector<StaticInitializer>::const_iterator I = InitList.begin(), | 
|  | E = InitList.end(); I!=E; ++I) { | 
|  | if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(I->constant)) { | 
|  | // Out << "\n// Init " << getValueName(VarI->first) << ", offset " << | 
|  | //  utostr(I->offset) << ", type "<< *I->constant->getType() << "\n\n"; | 
|  | // Load variable address | 
|  | printValueLoad(VarI->first); | 
|  | // Add offset | 
|  | if (I->offset!=0) { | 
|  | printPtrLoad(I->offset); | 
|  | printSimpleInstruction("add"); | 
|  | } | 
|  | // Load value | 
|  | printConstantExpr(CE); | 
|  | // Save result at offset | 
|  | std::string postfix = getTypePostfix(CE->getType(),true); | 
|  | if (*postfix.begin()=='u') *postfix.begin() = 'i'; | 
|  | postfix = "stind."+postfix; | 
|  | printSimpleInstruction(postfix.c_str()); | 
|  | } else { | 
|  | cerr << "Constant = " << *I->constant << '\n'; | 
|  | llvm_unreachable("Invalid static initializer"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printFunction(const Function& F) { | 
|  | bool isSigned = F.paramHasAttr(0, Attribute::SExt); | 
|  | Out << "\n.method static "; | 
|  | Out << (F.hasLocalLinkage() ? "private " : "public "); | 
|  | if (F.isVarArg()) Out << "vararg "; | 
|  | Out << getTypeName(F.getReturnType(),isSigned) << | 
|  | getConvModopt(F.getCallingConv()) << getValueName(&F) << '\n'; | 
|  | // Arguments | 
|  | Out << "\t("; | 
|  | unsigned ArgIdx = 1; | 
|  | for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I!=E; | 
|  | ++I, ++ArgIdx) { | 
|  | isSigned = F.paramHasAttr(ArgIdx, Attribute::SExt); | 
|  | if (I!=F.arg_begin()) Out << ", "; | 
|  | Out << getTypeName(I->getType(),isSigned) << getValueName(I); | 
|  | } | 
|  | Out << ") cil managed\n"; | 
|  | // Body | 
|  | Out << "{\n"; | 
|  | printLocalVariables(F); | 
|  | printFunctionBody(F); | 
|  | Out << "}\n"; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printDeclarations(const TypeSymbolTable& ST) { | 
|  | std::string Name; | 
|  | std::set<const Type*> Printed; | 
|  | for (std::set<const Type*>::const_iterator | 
|  | UI = UsedTypes->begin(), UE = UsedTypes->end(); UI!=UE; ++UI) { | 
|  | const Type* Ty = *UI; | 
|  | if (isa<ArrayType>(Ty) || isa<VectorType>(Ty) || isa<StructType>(Ty)) | 
|  | Name = getTypeName(Ty, false, true); | 
|  | // Type with no need to declare. | 
|  | else continue; | 
|  | // Print not duplicated type | 
|  | if (Printed.insert(Ty).second) { | 
|  | Out << ".class value explicit ansi sealed '" << Name << "'"; | 
|  | Out << " { .pack " << 1 << " .size " << TD->getTypeAllocSize(Ty); | 
|  | Out << " }\n\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | unsigned int MSILWriter::getBitWidth(const Type* Ty) { | 
|  | unsigned int N = Ty->getPrimitiveSizeInBits(); | 
|  | assert(N!=0 && "Invalid type in getBitWidth()"); | 
|  | switch (N) { | 
|  | case 1: | 
|  | case 8: | 
|  | case 16: | 
|  | case 32: | 
|  | case 64: | 
|  | return N; | 
|  | default: | 
|  | cerr << "Bits = " << N << '\n'; | 
|  | llvm_unreachable("Unsupported integer width"); | 
|  | } | 
|  | return 0; // Not reached | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { | 
|  | uint64_t TySize = 0; | 
|  | const Type* Ty = C->getType(); | 
|  | // Print zero initialized constant. | 
|  | if (isa<ConstantAggregateZero>(C) || C->isNullValue()) { | 
|  | TySize = TD->getTypeAllocSize(C->getType()); | 
|  | Offset += TySize; | 
|  | Out << "int8 (0) [" << TySize << "]"; | 
|  | return; | 
|  | } | 
|  | // Print constant initializer | 
|  | switch (Ty->getTypeID()) { | 
|  | case Type::IntegerTyID: { | 
|  | TySize = TD->getTypeAllocSize(Ty); | 
|  | const ConstantInt* Int = cast<ConstantInt>(C); | 
|  | Out << getPrimitiveTypeName(Ty,true) << "(" << Int->getSExtValue() << ")"; | 
|  | break; | 
|  | } | 
|  | case Type::FloatTyID: | 
|  | case Type::DoubleTyID: { | 
|  | TySize = TD->getTypeAllocSize(Ty); | 
|  | const ConstantFP* FP = cast<ConstantFP>(C); | 
|  | if (Ty->getTypeID() == Type::FloatTyID) | 
|  | Out << "int32 (" << | 
|  | (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')'; | 
|  | else | 
|  | Out << "int64 (" << | 
|  | FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')'; | 
|  | break; | 
|  | } | 
|  | case Type::ArrayTyID: | 
|  | case Type::VectorTyID: | 
|  | case Type::StructTyID: | 
|  | for (unsigned I = 0, E = C->getNumOperands(); I<E; I++) { | 
|  | if (I!=0) Out << ",\n"; | 
|  | printStaticConstant(C->getOperand(I),Offset); | 
|  | } | 
|  | break; | 
|  | case Type::PointerTyID: | 
|  | TySize = TD->getTypeAllocSize(C->getType()); | 
|  | // Initialize with global variable address | 
|  | if (const GlobalVariable *G = dyn_cast<GlobalVariable>(C)) { | 
|  | std::string name = getValueName(G); | 
|  | Out << "&(" << name.insert(name.length()-1,"$data") << ")"; | 
|  | } else { | 
|  | // Dynamic initialization | 
|  | if (!isa<ConstantPointerNull>(C) && !C->isNullValue()) | 
|  | InitListPtr->push_back(StaticInitializer(C,Offset)); | 
|  | // Null pointer initialization | 
|  | if (TySize==4) Out << "int32 (0)"; | 
|  | else if (TySize==8) Out << "int64 (0)"; | 
|  | else llvm_unreachable("Invalid pointer size"); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | cerr << "TypeID = " << Ty->getTypeID() << '\n'; | 
|  | llvm_unreachable("Invalid type in printStaticConstant()"); | 
|  | } | 
|  | // Increase offset. | 
|  | Offset += TySize; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printStaticInitializer(const Constant* C, | 
|  | const std::string& Name) { | 
|  | switch (C->getType()->getTypeID()) { | 
|  | case Type::IntegerTyID: | 
|  | case Type::FloatTyID: | 
|  | case Type::DoubleTyID: | 
|  | Out << getPrimitiveTypeName(C->getType(), false); | 
|  | break; | 
|  | case Type::ArrayTyID: | 
|  | case Type::VectorTyID: | 
|  | case Type::StructTyID: | 
|  | case Type::PointerTyID: | 
|  | Out << getTypeName(C->getType()); | 
|  | break; | 
|  | default: | 
|  | cerr << "Type = " << *C << "\n"; | 
|  | llvm_unreachable("Invalid constant type"); | 
|  | } | 
|  | // Print initializer | 
|  | std::string label = Name; | 
|  | label.insert(label.length()-1,"$data"); | 
|  | Out << Name << " at " << label << '\n'; | 
|  | Out << ".data " << label << " = {\n"; | 
|  | uint64_t offset = 0; | 
|  | printStaticConstant(C,offset); | 
|  | Out << "\n}\n\n"; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printVariableDefinition(const GlobalVariable* G) { | 
|  | const Constant* C = G->getInitializer(); | 
|  | if (C->isNullValue() || isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) | 
|  | InitListPtr = 0; | 
|  | else | 
|  | InitListPtr = &StaticInitList[G]; | 
|  | printStaticInitializer(C,getValueName(G)); | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printGlobalVariables() { | 
|  | if (ModulePtr->global_empty()) return; | 
|  | Module::global_iterator I,E; | 
|  | for (I = ModulePtr->global_begin(), E = ModulePtr->global_end(); I!=E; ++I) { | 
|  | // Variable definition | 
|  | Out << ".field static " << (I->isDeclaration() ? "public " : | 
|  | "private "); | 
|  | if (I->isDeclaration()) { | 
|  | Out << getTypeName(I->getType()) << getValueName(&*I) << "\n\n"; | 
|  | } else | 
|  | printVariableDefinition(&*I); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | const char* MSILWriter::getLibraryName(const Function* F) { | 
|  | return getLibraryForSymbol(F->getName(), true, F->getCallingConv()); | 
|  | } | 
|  |  | 
|  |  | 
|  | const char* MSILWriter::getLibraryName(const GlobalVariable* GV) { | 
|  | return getLibraryForSymbol(Mang->getMangledName(GV), false, 0); | 
|  | } | 
|  |  | 
|  |  | 
|  | const char* MSILWriter::getLibraryForSymbol(const StringRef &Name, | 
|  | bool isFunction, | 
|  | unsigned CallingConv) { | 
|  | // TODO: Read *.def file with function and libraries definitions. | 
|  | return "MSVCRT.DLL"; | 
|  | } | 
|  |  | 
|  |  | 
|  | void MSILWriter::printExternals() { | 
|  | Module::const_iterator I,E; | 
|  | // Functions. | 
|  | for (I=ModulePtr->begin(),E=ModulePtr->end(); I!=E; ++I) { | 
|  | // Skip intrisics | 
|  | if (I->isIntrinsic()) continue; | 
|  | if (I->isDeclaration()) { | 
|  | const Function* F = I; | 
|  | std::string Name = getConvModopt(F->getCallingConv())+getValueName(F); | 
|  | std::string Sig = | 
|  | getCallSignature(cast<FunctionType>(F->getFunctionType()), NULL, Name); | 
|  | Out << ".method static hidebysig pinvokeimpl(\"" | 
|  | << getLibraryName(F) << "\")\n\t" << Sig << " preservesig {}\n\n"; | 
|  | } | 
|  | } | 
|  | // External variables and static initialization. | 
|  | Out << | 
|  | ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" | 
|  | "  native int LoadLibrary(string) preservesig {}\n" | 
|  | ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" | 
|  | "  native int GetProcAddress(native int, string) preservesig {}\n"; | 
|  | Out << | 
|  | ".method private static void* $MSIL_Import(string lib,string sym)\n" | 
|  | " managed cil\n{\n" | 
|  | "\tldarg\tlib\n" | 
|  | "\tcall\tnative int LoadLibrary(string)\n" | 
|  | "\tldarg\tsym\n" | 
|  | "\tcall\tnative int GetProcAddress(native int,string)\n" | 
|  | "\tdup\n" | 
|  | "\tbrtrue\tL_01\n" | 
|  | "\tldstr\t\"Can no import variable\"\n" | 
|  | "\tnewobj\tinstance void [mscorlib]System.Exception::.ctor(string)\n" | 
|  | "\tthrow\n" | 
|  | "L_01:\n" | 
|  | "\tret\n" | 
|  | "}\n\n" | 
|  | ".method static private void $MSIL_Init() managed cil\n{\n"; | 
|  | printStaticInitializerList(); | 
|  | // Foreach global variable. | 
|  | for (Module::global_iterator I = ModulePtr->global_begin(), | 
|  | E = ModulePtr->global_end(); I!=E; ++I) { | 
|  | if (!I->isDeclaration() || !I->hasDLLImportLinkage()) continue; | 
|  | // Use "LoadLibrary"/"GetProcAddress" to recive variable address. | 
|  | std::string Label = "not_null$_"+utostr(getUniqID()); | 
|  | std::string Tmp = getTypeName(I->getType())+getValueName(&*I); | 
|  | printSimpleInstruction("ldsflda",Tmp.c_str()); | 
|  | Out << "\tldstr\t\"" << getLibraryName(&*I) << "\"\n"; | 
|  | Out << "\tldstr\t\"" << Mang->getMangledName(&*I) << "\"\n"; | 
|  | printSimpleInstruction("call","void* $MSIL_Import(string,string)"); | 
|  | printIndirectSave(I->getType()); | 
|  | } | 
|  | printSimpleInstruction("ret"); | 
|  | Out << "}\n\n"; | 
|  | } | 
|  |  | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                      External Interface declaration | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, | 
|  | formatted_raw_ostream &o, | 
|  | CodeGenFileType FileType, | 
|  | CodeGenOpt::Level OptLevel) | 
|  | { | 
|  | if (FileType != TargetMachine::AssemblyFile) return true; | 
|  | MSILWriter* Writer = new MSILWriter(o); | 
|  | PM.add(createGCLoweringPass()); | 
|  | PM.add(createLowerAllocationsPass(true)); | 
|  | // FIXME: Handle switch trougth native IL instruction "switch" | 
|  | PM.add(createLowerSwitchPass()); | 
|  | PM.add(createCFGSimplificationPass()); | 
|  | PM.add(new MSILModule(Writer->UsedTypes,Writer->TD)); | 
|  | PM.add(Writer); | 
|  | PM.add(createGCInfoDeleter()); | 
|  | return false; | 
|  | } |