diff options
Diffstat (limited to 'contrib/llvm/lib/Target/MSIL')
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/CMakeLists.txt | 3 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/MSILWriter.cpp | 1706 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/MSILWriter.h | 258 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/Makefile | 16 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/README.TXT | 26 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/TargetInfo/CMakeLists.txt | 6 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp | 26 | ||||
-rw-r--r-- | contrib/llvm/lib/Target/MSIL/TargetInfo/Makefile | 15 |
8 files changed, 2056 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/MSIL/CMakeLists.txt b/contrib/llvm/lib/Target/MSIL/CMakeLists.txt new file mode 100644 index 0000000..b1d47ef --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_target(MSIL + MSILWriter.cpp + ) diff --git a/contrib/llvm/lib/Target/MSIL/MSILWriter.cpp b/contrib/llvm/lib/Target/MSIL/MSILWriter.cpp new file mode 100644 index 0000000..3de173c --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/MSILWriter.cpp @@ -0,0 +1,1706 @@ +//===-- 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/Target/TargetRegistry.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/CodeGen/Passes.h" +using namespace llvm; + +namespace llvm { + // TargetMachine for the MSIL + struct MSILTarget : public TargetMachine { + MSILTarget(const Target &T, const std::string &TT, const std::string &FS) + : TargetMachine(T) {} + + virtual bool addPassesToEmitFile(PassManagerBase &PM, + formatted_raw_ostream &Out, + CodeGenFileType FileType, + CodeGenOpt::Level OptLevel, + bool DisableVerify); + + virtual const TargetData *getTargetData() const { return 0; } + }; +} + +extern "C" void LLVMInitializeMSILTarget() { + // Register the target. + RegisterTargetMachine<MSILTarget> X(TheMSILTarget); +} + +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 (!I->second->isStructTy() && !I->second->isOpaqueTy()) + 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; + 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) { + 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()->isIntegerTy()) { + Out << "\tldloc\targc\n"; + Args = getTypeName(Arg1->getType()); + BadSig = false; + } + break; + case 2: + Arg1 = Arg2 = F->arg_begin(); ++Arg2; + if (Arg1->getType()->isIntegerTy() && + 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()->isIntegerTy() && !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 = GV->getName(); + 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 = GV->getName(); + else { + unsigned &No = AnonValueNumbers[V]; + if (No == 0) No = ++NextAnonValueNumber; + Name = "tmp" + utostr(No); + } + + return getLabelName(Name); +} + + +std::string MSILWriter::getConvModopt(CallingConv::ID 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) "; + case CallingConv::X86_ThisCall: + return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) "; + default: + errs() << "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: + errs() << "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->isIntegerTy()) + 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: + errs() << "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: + errs() << "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 (!isUInt<32>(N)) { + errs() << "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 { + errs() << "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: + errs() << "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: + errs() << "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(); 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: + errs() << "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 { + errs() << "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(Inst->getContext(), 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: + errs() << "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: + errs() << "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(Inst->getContext(), 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::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: + errs() << "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::getVoidTy(BB->getContext())) { + // 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::getVoidTy(F.getContext())) { + // 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: + errs() << "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 { + errs() << "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 (Ty->isArrayTy() || Ty->isVectorTy() || Ty->isStructTy()) + 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: + errs() << "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(cast<Constant>(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: + errs() << "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: + errs() << "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(GV->getName(), false, CallingConv::C); +} + + +const char* MSILWriter::getLibraryForSymbol(const StringRef &Name, + bool isFunction, + CallingConv::ID 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 Tmp = getTypeName(I->getType())+getValueName(&*I); + printSimpleInstruction("ldsflda",Tmp.c_str()); + Out << "\tldstr\t\"" << getLibraryName(&*I) << "\"\n"; + Out << "\tldstr\t\"" << I->getName() << "\"\n"; + printSimpleInstruction("call","void* $MSIL_Import(string,string)"); + printIndirectSave(I->getType()); + } + printSimpleInstruction("ret"); + Out << "}\n\n"; +} + + +//===----------------------------------------------------------------------===// +// External Interface declaration +//===----------------------------------------------------------------------===// + +bool MSILTarget::addPassesToEmitFile(PassManagerBase &PM, + formatted_raw_ostream &o, + CodeGenFileType FileType, + CodeGenOpt::Level OptLevel, + bool DisableVerify) +{ + if (FileType != TargetMachine::CGFT_AssemblyFile) return true; + MSILWriter* Writer = new MSILWriter(o); + PM.add(createGCLoweringPass()); + // FIXME: Handle switch through 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; +} diff --git a/contrib/llvm/lib/Target/MSIL/MSILWriter.h b/contrib/llvm/lib/Target/MSIL/MSILWriter.h new file mode 100644 index 0000000..a95ae23 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/MSILWriter.h @@ -0,0 +1,258 @@ +//===-- MSILWriter.h - TargetMachine for the MSIL ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MSILWriter that is used by the MSIL. +// +//===----------------------------------------------------------------------===// +#ifndef MSILWRITER_H +#define MSILWRITER_H + +#include "llvm/CallingConv.h" +#include "llvm/Constants.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/FindUsedTypes.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/GetElementPtrTypeIterator.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + extern Target TheMSILTarget; + + class MSILModule : public ModulePass { + Module *ModulePtr; + const std::set<const Type *>*& UsedTypes; + const TargetData*& TD; + + public: + static char ID; + MSILModule(const std::set<const Type *>*& _UsedTypes, + const TargetData*& _TD) + : ModulePass(&ID), UsedTypes(_UsedTypes), TD(_TD) {} + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<FindUsedTypes>(); + AU.addRequired<TargetData>(); + } + + virtual const char *getPassName() const { + return "MSIL backend definitions"; + } + + virtual bool runOnModule(Module &M); + + }; + + class MSILWriter : public FunctionPass { + struct StaticInitializer { + const Constant* constant; + uint64_t offset; + + StaticInitializer() + : constant(0), offset(0) {} + + StaticInitializer(const Constant* _constant, uint64_t _offset) + : constant(_constant), offset(_offset) {} + }; + + uint64_t UniqID; + + uint64_t getUniqID() { + return ++UniqID; + } + + public: + formatted_raw_ostream &Out; + Module* ModulePtr; + const TargetData* TD; + LoopInfo *LInfo; + std::vector<StaticInitializer>* InitListPtr; + std::map<const GlobalVariable*,std::vector<StaticInitializer> > + StaticInitList; + const std::set<const Type *>* UsedTypes; + static char ID; + DenseMap<const Value*, unsigned> AnonValueNumbers; + unsigned NextAnonValueNumber; + + MSILWriter(formatted_raw_ostream &o) : FunctionPass(&ID), Out(o), + NextAnonValueNumber(0) { + UniqID = 0; + } + + enum ValueType { + UndefVT, + GlobalVT, + InternalVT, + ArgumentVT, + LocalVT, + ConstVT, + ConstExprVT + }; + + bool isVariable(ValueType V) { + return V==GlobalVT || V==InternalVT || V==ArgumentVT || V==LocalVT; + } + + bool isConstValue(ValueType V) { + return V==ConstVT || V==ConstExprVT; + } + + virtual const char *getPassName() const { return "MSIL backend"; } + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<LoopInfo>(); + AU.setPreservesAll(); + } + + bool runOnFunction(Function &F); + + virtual bool doInitialization(Module &M); + + virtual bool doFinalization(Module &M); + + void printModuleStartup(); + + bool isZeroValue(const Value* V); + + std::string getValueName(const Value* V); + + std::string getLabelName(const Value* V); + + std::string getLabelName(const std::string& Name); + + std::string getConvModopt(CallingConv::ID CallingConvID); + + std::string getArrayTypeName(Type::TypeID TyID, const Type* Ty); + + std::string getPrimitiveTypeName(const Type* Ty, bool isSigned); + + std::string getFunctionTypeName(const Type* Ty); + + std::string getPointerTypeName(const Type* Ty); + + std::string getTypeName(const Type* Ty, bool isSigned = false, + bool isNested = false); + + ValueType getValueLocation(const Value* V); + + std::string getTypePostfix(const Type* Ty, bool Expand, + bool isSigned = false); + + void printConvToPtr(); + + void printPtrLoad(uint64_t N); + + void printValuePtrLoad(const Value* V); + + void printConstLoad(const Constant* C); + + void printValueLoad(const Value* V); + + void printValueSave(const Value* V); + + void printBinaryInstruction(const char* Name, const Value* Left, + const Value* Right); + + void printSimpleInstruction(const char* Inst, const char* Operand = NULL); + + void printPHICopy(const BasicBlock* Src, const BasicBlock* Dst); + + void printBranchToBlock(const BasicBlock* CurrBB, + const BasicBlock* TrueBB, + const BasicBlock* FalseBB); + + void printBranchInstruction(const BranchInst* Inst); + + void printSelectInstruction(const Value* Cond, const Value* VTrue, + const Value* VFalse); + + void printIndirectLoad(const Value* V); + + void printIndirectSave(const Value* Ptr, const Value* Val); + + void printIndirectSave(const Type* Ty); + + void printCastInstruction(unsigned int Op, const Value* V, + const Type* Ty, const Type* SrcTy=0); + + void printGepInstruction(const Value* V, gep_type_iterator I, + gep_type_iterator E); + + std::string getCallSignature(const FunctionType* Ty, + const Instruction* Inst, + std::string Name); + + void printFunctionCall(const Value* FnVal, const Instruction* Inst); + + void printIntrinsicCall(const IntrinsicInst* Inst); + + void printCallInstruction(const Instruction* Inst); + + void printICmpInstruction(unsigned Predicate, const Value* Left, + const Value* Right); + + void printFCmpInstruction(unsigned Predicate, const Value* Left, + const Value* Right); + + void printInvokeInstruction(const InvokeInst* Inst); + + void printSwitchInstruction(const SwitchInst* Inst); + + void printVAArgInstruction(const VAArgInst* Inst); + + void printAllocaInstruction(const AllocaInst* Inst); + + void printInstruction(const Instruction* Inst); + + void printLoop(const Loop* L); + + void printBasicBlock(const BasicBlock* BB); + + void printLocalVariables(const Function& F); + + void printFunctionBody(const Function& F); + + void printConstantExpr(const ConstantExpr* CE); + + void printStaticInitializerList(); + + void printFunction(const Function& F); + + void printDeclarations(const TypeSymbolTable& ST); + + unsigned int getBitWidth(const Type* Ty); + + void printStaticConstant(const Constant* C, uint64_t& Offset); + + void printStaticInitializer(const Constant* C, const std::string& Name); + + void printVariableDefinition(const GlobalVariable* G); + + void printGlobalVariables(); + + const char* getLibraryName(const Function* F); + + const char* getLibraryName(const GlobalVariable* GV); + + const char* getLibraryForSymbol(const StringRef &Name, bool isFunction, + CallingConv::ID CallingConv); + + void printExternals(); + }; + +} + +#endif + diff --git a/contrib/llvm/lib/Target/MSIL/Makefile b/contrib/llvm/lib/Target/MSIL/Makefile new file mode 100644 index 0000000..70eadb3 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/MSIL/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMMSIL +DIRS = TargetInfo + +include $(LEVEL)/Makefile.common + +CompileCommonOpts := $(CompileCommonOpts) -Wno-format diff --git a/contrib/llvm/lib/Target/MSIL/README.TXT b/contrib/llvm/lib/Target/MSIL/README.TXT new file mode 100644 index 0000000..d797c71 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/README.TXT @@ -0,0 +1,26 @@ +//===---------------------------------------------------------------------===// + +Vector instructions support. + +ShuffleVector +ExtractElement +InsertElement + +//===---------------------------------------------------------------------===// + +Add "OpaqueType" type. + +//===---------------------------------------------------------------------===// + +"switch" instruction emulation with CLI "switch" instruction. + +//===---------------------------------------------------------------------===// + +Write linker for external function, because function export need to know +dynamic library where function located. + +.method static hidebysig pinvokeimpl("msvcrt.dll" cdecl) + void free(void*) preservesig {} + + + diff --git a/contrib/llvm/lib/Target/MSIL/TargetInfo/CMakeLists.txt b/contrib/llvm/lib/Target/MSIL/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000..9f0c3a0 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/TargetInfo/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMSILInfo + MSILTargetInfo.cpp + ) + diff --git a/contrib/llvm/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp b/contrib/llvm/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp new file mode 100644 index 0000000..dfd4281 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp @@ -0,0 +1,26 @@ +//===-- MSILTargetInfo.cpp - MSIL Target Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MSILWriter.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMSILTarget; + +static unsigned MSIL_TripleMatchQuality(const std::string &TT) { + // This class always works, but shouldn't be the default in most cases. + return 1; +} + +extern "C" void LLVMInitializeMSILTargetInfo() { + TargetRegistry::RegisterTarget(TheMSILTarget, "msil", + "MSIL backend", + &MSIL_TripleMatchQuality); +} diff --git a/contrib/llvm/lib/Target/MSIL/TargetInfo/Makefile b/contrib/llvm/lib/Target/MSIL/TargetInfo/Makefile new file mode 100644 index 0000000..30b0950 --- /dev/null +++ b/contrib/llvm/lib/Target/MSIL/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/MSIL/TargetInfo/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMMSILInfo + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common |