| //===-- MSILWriter.cpp - Library for converting LLVM code to MSIL ---------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by Roman Samoilov and 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/ParameterAttributes.h" |
| #include "llvm/TypeSymbolTable.h" |
| #include "llvm/Analysis/ConstantsScanner.h" |
| #include "llvm/Support/CallSite.h" |
| #include "llvm/Support/InstVisitor.h" |
| #include "llvm/Support/MathExtras.h" |
| #include "llvm/Transforms/Scalar.h" |
| #include "llvm/ADT/StringExtras.h" |
| |
| namespace { |
| // TargetMachine for the MSIL |
| struct VISIBILITY_HIDDEN MSILTarget : public TargetMachine { |
| const TargetData DataLayout; // Calculates type size & alignment |
| |
| MSILTarget(const Module &M, const std::string &FS) |
| : DataLayout(&M) {} |
| |
| virtual bool WantsWholeFile() const { return true; } |
| virtual bool addPassesToEmitWholeFile(PassManager &PM, std::ostream &Out, |
| CodeGenFileType FileType, bool Fast); |
| |
| // 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; } |
| }; |
| } |
| |
| |
| RegisterTarget<MSILTarget> X("msil", " MSIL backend"); |
| |
| 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; |
| 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) { |
| // Name into the quotes allow control and space characters. |
| return "'"+Mang->getValueName(V)+"'"; |
| } |
| |
| |
| 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) { |
| return getLabelName(Mang->getValueName(V)); |
| } |
| |
| |
| 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'; |
| assert(0 && "Unsupported calling convention"); |
| } |
| } |
| |
| |
| 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'; |
| assert(0 && "Invalid primitive type"); |
| } |
| } |
| |
| |
| 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'; |
| assert(0 && "Invalid type in getTypeName()"); |
| } |
| } |
| |
| |
| 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->hasInternalLinkage() ? InternalVT : GlobalVT; |
| // Variable |
| else if (const GlobalVariable* G = dyn_cast<GlobalVariable>(V)) |
| return G->hasInternalLinkage() ? 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->getABITypeSize(Ty)); |
| default: |
| cerr << "TypeID = " << Ty->getTypeID() << '\n'; |
| assert(0 && "Invalid type in TypeToPostfix()"); |
| } |
| } |
| |
| |
| void MSILWriter::printConvToPtr() { |
| switch (ModulePtr->getPointerSize()) { |
| case Module::Pointer32: |
| printSimpleInstruction("conv.u4"); |
| break; |
| case Module::Pointer64: |
| printSimpleInstruction("conv.u8"); |
| break; |
| default: |
| assert(0 && "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'; |
| assert(0 && "32-bit pointer overflowed"); |
| } |
| break; |
| case Module::Pointer64: |
| printSimpleInstruction("ldc.i8",utostr(N).c_str()); |
| break; |
| default: |
| assert(0 && "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().convertToAPInt().getZExtValue(); |
| Size = 4; |
| } else { |
| X = FP->getValueAPF().convertToAPInt().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'; |
| assert(0 && "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'; |
| assert(0 && "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'; |
| assert(0 && "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) { |
| std::string Tmp(""); |
| printValueLoad(V); |
| switch (Op) { |
| // Signed |
| case Instruction::SExt: |
| 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'; |
| assert(0 && "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->getABITypeSize(StrucTy->getContainedType((unsigned)F)); |
| printPtrLoad(Size); |
| printSimpleInstruction("add"); |
| continue; |
| } else if (const SequentialType* SeqTy = dyn_cast<SequentialType>(*I)) { |
| Size = TD->getABITypeSize(SeqTy->getElementType()); |
| } else { |
| Size = TD->getABITypeSize(*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'; |
| assert(0 && "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::get(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'; |
| assert(0 && "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); |
| case ICmpInst::ICMP_SGT: |
| printBinaryInstruction("cgt",Left,Right); |
| break; |
| default: |
| cerr << "Predicate = " << Predicate << '\n'; |
| assert(0 && "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: |
| assert(0 && "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::get(IntegerType::get(8)),false); |
| printSimpleInstruction(Name.c_str()); |
| } |
| |
| |
| void MSILWriter::printAllocaInstruction(const AllocaInst* Inst) { |
| uint64_t Size = TD->getABITypeSize(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: |
| printBinaryInstruction("add",Left,Right); |
| break; |
| case Instruction::Sub: |
| printBinaryInstruction("sub",Left,Right); |
| break; |
| case Instruction::Mul: |
| 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::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(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: |
| assert(0 && "LowerAllocationsPass used"); |
| break; |
| case Instruction::Free: |
| assert(0 && "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'; |
| assert(0 && "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::get(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: |
| printBinaryInstruction("add",left,right); |
| break; |
| case Instruction::Sub: |
| printBinaryInstruction("sub",left,right); |
| break; |
| case Instruction::Mul: |
| 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"; |
| assert(0 && "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'; |
| assert(0 && "Invalid static initializer"); |
| } |
| } |
| } |
| } |
| |
| |
| void MSILWriter::printFunction(const Function& F) { |
| bool isSigned = F.paramHasAttr(0, ParamAttr::SExt); |
| Out << "\n.method static "; |
| Out << (F.hasInternalLinkage() ? "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, ParamAttr::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->getABITypeSize(Ty)<< " }\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'; |
| assert(0 && "Unsupported integer width"); |
| } |
| } |
| |
| |
| 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->getABITypeSize(C->getType()); |
| Offset += TySize; |
| Out << "int8 (0) [" << TySize << "]"; |
| return; |
| } |
| // Print constant initializer |
| switch (Ty->getTypeID()) { |
| case Type::IntegerTyID: { |
| TySize = TD->getABITypeSize(Ty); |
| const ConstantInt* Int = cast<ConstantInt>(C); |
| Out << getPrimitiveTypeName(Ty,true) << "(" << Int->getSExtValue() << ")"; |
| break; |
| } |
| case Type::FloatTyID: |
| case Type::DoubleTyID: { |
| TySize = TD->getABITypeSize(Ty); |
| const ConstantFP* FP = cast<ConstantFP>(C); |
| if (Ty->getTypeID() == Type::FloatTyID) |
| Out << "int32 (" << |
| (uint32_t)FP->getValueAPF().convertToAPInt().getZExtValue() << ')'; |
| else |
| Out << "int64 (" << |
| FP->getValueAPF().convertToAPInt().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->getABITypeSize(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 assert(0 && "Invalid pointer size"); |
| } |
| break; |
| default: |
| cerr << "TypeID = " << Ty->getTypeID() << '\n'; |
| assert(0 && "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"; |
| assert(0 && "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().c_str(), true, F->getCallingConv()); |
| } |
| |
| |
| const char* MSILWriter::getLibraryName(const GlobalVariable* GV) { |
| return getLibraryForSymbol(Mang->getValueName(GV).c_str(), false, 0); |
| } |
| |
| |
| const char* MSILWriter::getLibraryForSymbol(const char* 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->getValueName(&*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, std::ostream &o, |
| CodeGenFileType FileType, bool Fast) |
| { |
| if (FileType != TargetMachine::AssemblyFile) return true; |
| MSILWriter* Writer = new MSILWriter(o); |
| PM.add(createLowerGCPass()); |
| 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); |
| return false; |
| } |