X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMSIL%2FMSILWriter.cpp;h=8bd3c7bc22df918b98f0ff6700707b1211350602;hb=64cc97212346992892b6c92158c08cd93149a882;hp=bab2904bd18d9ff8818da1903eddf2e212bd303c;hpb=099883f7eb4d1265b9c5f8fd416f3ac5f5fdb93c;p=oota-llvm.git diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp index bab2904bd18..8bd3c7bc22d 100644 --- a/lib/Target/MSIL/MSILWriter.cpp +++ b/lib/Target/MSIL/MSILWriter.cpp @@ -1,9 +1,9 @@ //===-- MSILWriter.cpp - Library for converting LLVM code to MSIL ---------===// // -// The LLVM Compiler Infrastructure +// 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 file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -19,21 +19,26 @@ #include "llvm/TypeSymbolTable.h" #include "llvm/Analysis/ConstantsScanner.h" #include "llvm/Support/CallSite.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/InstVisitor.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Transforms/Scalar.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/CodeGen/Passes.h" namespace { // TargetMachine for the MSIL struct VISIBILITY_HIDDEN MSILTarget : public TargetMachine { const TargetData DataLayout; // Calculates type size & alignment - MSILTarget(const Module &M, const std::string &FS) - : DataLayout(&M) {} + MSILTarget(const Target &T, const Module &M, const std::string &FS) + : TargetMachine(T), DataLayout(&M) {} virtual bool WantsWholeFile() const { return true; } - virtual bool addPassesToEmitWholeFile(PassManager &PM, std::ostream &Out, - CodeGenFileType FileType, bool Fast); + virtual bool addPassesToEmitWholeFile(PassManager &PM, + formatted_raw_ostream &Out, + CodeGenFileType FileType, + CodeGenOpt::Level OptLevel); // This class always works, but shouldn't be the default in most cases. static unsigned getModuleMatchQuality(const Module &M) { return 1; } @@ -42,8 +47,11 @@ namespace { }; } +extern Target TheMSILTarget; +static RegisterTarget X(TheMSILTarget, "msil", "MSIL backend"); -RegisterTarget X("msil", " MSIL backend"); +// Force static initialization. +extern "C" void LLVMInitializeMSILTarget() { } bool MSILModule::runOnModule(Module &M) { ModulePtr = &M; @@ -79,9 +87,17 @@ bool MSILModule::runOnModule(Module &M) { 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(); printFunction(F); return false; @@ -90,7 +106,7 @@ bool MSILWriter::runOnFunction(Function &F) { bool MSILWriter::doInitialization(Module &M) { ModulePtr = &M; - Mang = new Mangler(M); + Mang = new Mangler(M); Out << ".assembly extern mscorlib {}\n"; Out << ".assembly MSIL {}\n\n"; Out << "// External\n"; @@ -99,6 +115,8 @@ bool MSILWriter::doInitialization(Module &M) { printDeclarations(M.getTypeSymbolTable()); Out << "// Definitions\n"; printGlobalVariables(); + Out << "// Startup code\n"; + printModuleStartup(); return false; } @@ -109,6 +127,105 @@ bool MSILWriter::doFinalization(Module &M) { } +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(V)) return C->isNullValue(); @@ -117,8 +234,17 @@ bool MSILWriter::isZeroValue(const Value* V) { std::string MSILWriter::getValueName(const Value* V) { + std::string Name; + if (const GlobalValue *GV = cast(V)) + Name = Mang->getMangledName(GV); + else { + unsigned &No = AnonValueNumbers[V]; + if (No == 0) No = ++NextAnonValueNumber; + Name = "tmp" + utostr(No); + } + // Name into the quotes allow control and space characters. - return "'"+Mang->getValueName(V)+"'"; + return "'"+Name+"'"; } @@ -135,7 +261,16 @@ std::string MSILWriter::getLabelName(const std::string& Name) { std::string MSILWriter::getLabelName(const Value* V) { - return getLabelName(Mang->getValueName(V)); + std::string Name; + if (const GlobalValue *GV = cast(V)) + Name = Mang->getMangledName(GV); + else { + unsigned &No = AnonValueNumbers[V]; + if (No == 0) No = ++NextAnonValueNumber; + Name = "tmp" + utostr(No); + } + + return getLabelName(Name); } @@ -151,8 +286,9 @@ std::string MSILWriter::getConvModopt(unsigned CallingConvID) { return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) "; default: cerr << "CallingConvID = " << CallingConvID << '\n'; - assert(0 && "Unsupported calling convention"); + llvm_unreachable("Unsupported calling convention"); } + return ""; // Not reached } @@ -174,7 +310,7 @@ std::string MSILWriter::getArrayTypeName(Type::TypeID TyID, const Type* Ty) { if (ElemTy->getTypeID()!=TyID) break; Tmp += ","; } - return getTypeName(ElemTy)+"["+Tmp+"]"; + return getTypeName(ElemTy, false, true)+"["+Tmp+"]"; } @@ -196,12 +332,14 @@ std::string MSILWriter::getPrimitiveTypeName(const Type* Ty, bool isSigned) { return "float64 "; default: cerr << "Type = " << *Ty << '\n'; - assert(0 && "Invalid primitive type"); + llvm_unreachable("Invalid primitive type"); } + return ""; // Not reached } -std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned) { +std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned, + bool isNested) { if (Ty->isPrimitiveType() || Ty->isInteger()) return getPrimitiveTypeName(Ty,isSigned); // FIXME: "OpaqueType" support @@ -209,15 +347,22 @@ std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned) { 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()"); + llvm_unreachable("Invalid type in getTypeName()"); } + return ""; // Not reached } @@ -227,10 +372,10 @@ MSILWriter::ValueType MSILWriter::getValueLocation(const Value* V) { return ArgumentVT; // Function else if (const Function* F = dyn_cast(V)) - return F->hasInternalLinkage() ? InternalVT : GlobalVT; + return F->hasLocalLinkage() ? InternalVT : GlobalVT; // Variable else if (const GlobalVariable* G = dyn_cast(V)) - return G->hasInternalLinkage() ? InternalVT : GlobalVT; + return G->hasLocalLinkage() ? InternalVT : GlobalVT; // Constant else if (isa(V)) return isa(V) ? ConstExprVT : ConstVT; @@ -256,10 +401,25 @@ std::string MSILWriter::getTypePostfix(const Type* Ty, bool Expand, case Type::DoubleTyID: return "r8"; case Type::PointerTyID: - return "i"+utostr(TD->getTypeSize(Ty)); + return "i"+utostr(TD->getTypeAllocSize(Ty)); default: cerr << "TypeID = " << Ty->getTypeID() << '\n'; - assert(0 && "Invalid type in TypeToPostfix()"); + 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"); } } @@ -269,17 +429,26 @@ void MSILWriter::printPtrLoad(uint64_t N) { case Module::Pointer32: printSimpleInstruction("ldc.i4",utostr(N).c_str()); // FIXME: Need overflow test? - assert(N<0xFFFFFFFF && "32-bit pointer overflowed"); + if (!isUInt32(N)) { + cerr << "Value = " << utostr(N) << '\n'; + llvm_unreachable("32-bit pointer overflowed"); + } break; case Module::Pointer64: printSimpleInstruction("ldc.i8",utostr(N).c_str()); break; default: - assert(0 && "Module use not supporting pointer size"); + 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(C)) { // Integer constant @@ -288,20 +457,32 @@ void MSILWriter::printConstLoad(const Constant* C) { Out << CInt->getSExtValue(); else Out << CInt->getZExtValue(); - } else if (const ConstantFP* CFp = dyn_cast(C)) { + } else if (const ConstantFP* FP = dyn_cast(C)) { // Float constant - Out << "\tldc." << getTypePostfix(C->getType(),true) << '\t' << - CFp->getValue(); + 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(C)) { + // Undefined constant value = NULL. + printPtrLoad(0); } else { cerr << "Constant = " << *C << '\n'; - assert(0 && "Invalid constant value"); + llvm_unreachable("Invalid constant value"); } Out << '\n'; } void MSILWriter::printValueLoad(const Value* V) { - switch (getValueLocation(V)) { + MSILWriter::ValueType Location = getValueLocation(V); + switch (Location) { // Global variable or function address. case GlobalVT: case InternalVT: @@ -310,9 +491,15 @@ void MSILWriter::printValueLoad(const Value* V) { printSimpleInstruction("ldftn", getCallSignature(F->getFunctionType(),NULL,Name).c_str()); } else { + std::string Tmp; const Type* ElemTy = cast(V->getType())->getElementType(); - std::string Tmp = getTypeName(ElemTy)+getValueName(V); - printSimpleInstruction("ldsflda",Tmp.c_str()); + if (Location==GlobalVT && cast(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. @@ -336,7 +523,7 @@ void MSILWriter::printValueLoad(const Value* V) { break; default: cerr << "Value = " << *V << '\n'; - assert(0 && "Invalid value location"); + llvm_unreachable("Invalid value location"); } } @@ -351,7 +538,7 @@ void MSILWriter::printValueSave(const Value* V) { break; default: cerr << "Value = " << *V << '\n'; - assert(0 && "Invalid value location"); + llvm_unreachable("Invalid value location"); } } @@ -451,21 +638,25 @@ void MSILWriter::printSelectInstruction(const Value* Cond, const Value* VTrue, void MSILWriter::printIndirectLoad(const Value* V) { + const Type* Ty = V->getType(); printValueLoad(V); - std::string Tmp = "ldind."+getTypePostfix(V->getType(),false); + if (const PointerType* P = dyn_cast(Ty)) + Ty = P->getElementType(); + std::string Tmp = "ldind."+getTypePostfix(Ty, false); printSimpleInstruction(Tmp.c_str()); } -void MSILWriter::printStoreInstruction(const Instruction* Inst) { - const Value* Val = Inst->getOperand(0); - const Value* Ptr = Inst->getOperand(1); - // Load destination address. +void MSILWriter::printIndirectSave(const Value* Ptr, const Value* Val) { printValueLoad(Ptr); - // Load value. printValueLoad(Val); + printIndirectSave(Val->getType()); +} + + +void MSILWriter::printIndirectSave(const Type* Ty) { // Instruction need signed postfix for any type. - std::string postfix = getTypePostfix(Val->getType(),false); + std::string postfix = getTypePostfix(Ty, false); if (*postfix.begin()=='u') *postfix.begin() = 'i'; postfix = "stind."+postfix; printSimpleInstruction(postfix.c_str()); @@ -473,12 +664,19 @@ void MSILWriter::printStoreInstruction(const Instruction* Inst) { void MSILWriter::printCastInstruction(unsigned int Op, const Value* V, - const Type* Ty) { + 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); @@ -502,62 +700,46 @@ void MSILWriter::printCastInstruction(unsigned int Op, const Value* V, break; default: cerr << "Opcode = " << Op << '\n'; - assert(0 && "Invalid conversion instruction"); + llvm_unreachable("Invalid conversion instruction"); } } void MSILWriter::printGepInstruction(const Value* V, gep_type_iterator I, gep_type_iterator E) { + unsigned Size; // Load address - printValueLoad(V); + printValuePtrLoad(V); // Calculate element offset. - unsigned TySize; - for (++I; I!=E; ++I){ - const Type* Ty = I.getIndexedType(); - const Value* Idx = I.getOperand(); - // Get size of type. - switch (Ty->getTypeID()) { - case Type::IntegerTyID: - case Type::FloatTyID: - case Type::DoubleTyID: - case Type::PointerTyID: - TySize = TD->getTypeSize(Ty); - break; - case Type::StructTyID: - TySize = 0; - break; - case Type::ArrayTyID: - TySize = TD->getTypeSize(cast(Ty)->getElementType()); - break; - case Type::VectorTyID: - TySize = TD->getTypeSize(cast(Ty)->getElementType()); - break; - default: - cerr << "Type = " << *Ty << '\n'; - assert(0 && "Invalid index type in printGepInstruction()"); - } - // Calculate offset to structure field. - if (const StructType* STy = dyn_cast(Ty)) { - TySize = 0; - uint64_t FieldIdx = cast(Idx)->getZExtValue(); - // Offset is the summ of all previous structure fields. - for (uint64_t F = 0; FgetTypeSize(STy->getContainedType(unsigned(F))); - // Add field offset to stack top. - printPtrLoad(TySize); + for (; I!=E; ++I){ + Size = 0; + const Value* IndexValue = I.getOperand(); + if (const StructType* StrucTy = dyn_cast(*I)) { + uint64_t FieldIndex = cast(IndexValue)->getZExtValue(); + // Offset is the sum of all previous structure fields. + for (uint64_t F = 0; FgetTypeAllocSize(StrucTy->getContainedType((unsigned)F)); + printPtrLoad(Size); printSimpleInstruction("add"); continue; + } else if (const SequentialType* SeqTy = dyn_cast(*I)) { + Size = TD->getTypeAllocSize(SeqTy->getElementType()); + } else { + Size = TD->getTypeAllocSize(*I); } // Add offset of current element to stack top. - if (!isZeroValue(Idx)) { - uint64_t TySize = TD->getTypeSize(I.getIndexedType()); - // Constant optimization - if (const ConstantInt* CInt = dyn_cast(Idx)) { - printPtrLoad(CInt->getZExtValue()*TySize); + if (!isZeroValue(IndexValue)) { + // Constant optimization. + if (const ConstantInt* C = dyn_cast(IndexValue)) { + if (C->getValue().isNegative()) { + printPtrLoad(C->getValue().abs().getZExtValue()*Size); + printSimpleInstruction("sub"); + continue; + } else + printPtrLoad(C->getZExtValue()*Size); } else { - printPtrLoad(TySize); - printValueLoad(Idx); + printPtrLoad(Size); + printValuePtrLoad(IndexValue); printSimpleInstruction("mul"); } printSimpleInstruction("add"); @@ -569,7 +751,7 @@ void MSILWriter::printGepInstruction(const Value* V, gep_type_iterator I, std::string MSILWriter::getCallSignature(const FunctionType* Ty, const Instruction* Inst, std::string Name) { - std::string Tmp = ""; + std::string Tmp(""); if (Ty->isVarArg()) Tmp += "vararg "; // Name and return type. Tmp += getTypeName(Ty->getReturnType())+Name+"("; @@ -582,7 +764,7 @@ std::string MSILWriter::getCallSignature(const FunctionType* Ty, // 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" + // Origin to function arguments in "CallInst" or "InvokeInst". unsigned Org = isa(Inst) ? 3 : 1; // Print variable argument types. unsigned NumOperands = Inst->getNumOperands()-Org; @@ -601,7 +783,7 @@ std::string MSILWriter::getCallSignature(const FunctionType* Ty, void MSILWriter::printFunctionCall(const Value* FnVal, const Instruction* Inst) { - // Get function calling convention + // Get function calling convention. std::string Name = ""; if (const CallInst* Call = dyn_cast(Inst)) Name = getConvModopt(Call->getCallingConv()); @@ -609,30 +791,69 @@ void MSILWriter::printFunctionCall(const Value* FnVal, Name = getConvModopt(Invoke->getCallingConv()); else { cerr << "Instruction = " << Inst->getName() << '\n'; - assert(0 && "Need \"Invoke\" or \"Call\" instruction only"); + llvm_unreachable("Need \"Invoke\" or \"Call\" instruction only"); } - if (const Function* F = dyn_cast(FnVal)) { - // Direct call + // Direct call. Name += getValueName(F); printSimpleInstruction("call", getCallSignature(F->getFunctionType(),Inst,Name).c_str()); } else { - // Indirect function call + // Indirect function call. const PointerType* PTy = cast(FnVal->getType()); const FunctionType* FTy = cast(PTy->getElementType()); - // Load function address + // Load function address. printValueLoad(FnVal); printSimpleInstruction("calli",getCallSignature(FTy,Inst,Name).c_str()); } } +void MSILWriter::printIntrinsicCall(const IntrinsicInst* Inst) { + std::string Name; + switch (Inst->getIntrinsicID()) { + case Intrinsic::vastart: + Name = getValueName(Inst->getOperand(1)); + Name.insert(Name.length()-1,"$valist"); + // Obtain the argument handle. + printSimpleInstruction("ldloca",Name.c_str()); + printSimpleInstruction("arglist"); + printSimpleInstruction("call", + "instance void [mscorlib]System.ArgIterator::.ctor" + "(valuetype [mscorlib]System.RuntimeArgumentHandle)"); + // Save as pointer type "void*" + printValueLoad(Inst->getOperand(1)); + printSimpleInstruction("ldloca",Name.c_str()); + printIndirectSave(PointerType::getUnqual(IntegerType::get(8))); + break; + case Intrinsic::vaend: + // Close argument list handle. + printIndirectLoad(Inst->getOperand(1)); + printSimpleInstruction("call","instance void [mscorlib]System.ArgIterator::End()"); + break; + case Intrinsic::vacopy: + // Copy "ArgIterator" valuetype. + printIndirectLoad(Inst->getOperand(1)); + printIndirectLoad(Inst->getOperand(2)); + printSimpleInstruction("cpobj","[mscorlib]System.ArgIterator"); + break; + default: + cerr << "Intrinsic ID = " << Inst->getIntrinsicID() << '\n'; + llvm_unreachable("Invalid intrinsic function"); + } +} + + void MSILWriter::printCallInstruction(const Instruction* Inst) { - // Load arguments to stack - for (int I = 1, E = Inst->getNumOperands(); I!=E; ++I) - printValueLoad(Inst->getOperand(I)); - printFunctionCall(Inst->getOperand(0),Inst); + if (isa(Inst)) { + // Handle intrinsic function. + printIntrinsicCall(cast(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); + } } @@ -643,8 +864,9 @@ void MSILWriter::printICmpInstruction(unsigned Predicate, const Value* Left, printBinaryInstruction("ceq",Left,Right); break; case ICmpInst::ICMP_NE: - // Emulate = not (Op1 eq Op2) + // Emulate = not neg (Op1 eq Op2) printBinaryInstruction("ceq",Left,Right); + printSimpleInstruction("neg"); printSimpleInstruction("not"); break; case ICmpInst::ICMP_ULE: @@ -675,12 +897,13 @@ void MSILWriter::printICmpInstruction(unsigned Predicate, const Value* Left, break; case ICmpInst::ICMP_UGT: printBinaryInstruction("cgt.un",Left,Right); + break; case ICmpInst::ICMP_SGT: printBinaryInstruction("cgt",Left,Right); break; default: cerr << "Predicate = " << Predicate << '\n'; - assert(0 && "Invalid icmp predicate"); + llvm_unreachable("Invalid icmp predicate"); } } @@ -751,6 +974,7 @@ void MSILWriter::printFCmpInstruction(unsigned Predicate, const Value* Left, case FCmpInst::FCMP_UNE: // X != Y printBinaryInstruction("ceq",Left,Right); + printSimpleInstruction("neg"); printSimpleInstruction("not"); break; case FCmpInst::FCMP_ONE: @@ -773,7 +997,7 @@ void MSILWriter::printFCmpInstruction(unsigned Predicate, const Value* Left, printSimpleInstruction("or"); break; default: - assert(0 && "Illegal FCmp predicate"); + llvm_unreachable("Illegal FCmp predicate"); } } @@ -815,12 +1039,37 @@ void MSILWriter::printSwitchInstruction(const SwitchInst* Inst) { } +void MSILWriter::printVAArgInstruction(const VAArgInst* Inst) { + printIndirectLoad(Inst->getOperand(0)); + printSimpleInstruction("call", + "instance typedref [mscorlib]System.ArgIterator::GetNextArg()"); + printSimpleInstruction("refanyval","void*"); + std::string Name = + "ldind."+getTypePostfix(PointerType::getUnqual(IntegerType::get(8)),false); + printSimpleInstruction(Name.c_str()); +} + + +void MSILWriter::printAllocaInstruction(const AllocaInst* Inst) { + uint64_t Size = TD->getTypeAllocSize(Inst->getAllocatedType()); + // Constant optimization. + if (const ConstantInt* CInt = dyn_cast(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","VAArg" support. + // FIXME: "ShuffleVector","ExtractElement","InsertElement" support. switch (Inst->getOpcode()) { // Terminator case Instruction::Ret: @@ -835,12 +1084,15 @@ void MSILWriter::printInstruction(const Instruction* 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::Mul: + case Instruction::FMul: printBinaryInstruction("mul",Left,Right); break; case Instruction::UDiv: @@ -875,13 +1127,22 @@ void MSILWriter::printInstruction(const Instruction* Inst) { printBinaryInstruction("xor",Left,Right); break; case Instruction::Shl: - printBinaryInstruction("shl",Left,Right); + printValueLoad(Left); + printValueLoad(Right); + printSimpleInstruction("conv.i4"); + printSimpleInstruction("shl"); break; case Instruction::LShr: - printBinaryInstruction("shr.un",Left,Right); + printValueLoad(Left); + printValueLoad(Right); + printSimpleInstruction("conv.i4"); + printSimpleInstruction("shr.un"); break; case Instruction::AShr: - printBinaryInstruction("shr",Left,Right); + printValueLoad(Left); + printValueLoad(Right); + printSimpleInstruction("conv.i4"); + printSimpleInstruction("shr"); break; case Instruction::Select: printSelectInstruction(Inst->getOperand(0),Inst->getOperand(1),Inst->getOperand(2)); @@ -890,11 +1151,15 @@ void MSILWriter::printInstruction(const Instruction* Inst) { printIndirectLoad(Inst->getOperand(0)); break; case Instruction::Store: - printStoreInstruction(Inst); + printIndirectSave(Inst->getOperand(1), Inst->getOperand(0)); + break; + case Instruction::SExt: + printCastInstruction(Inst->getOpcode(),Left, + cast(Inst)->getDestTy(), + cast(Inst)->getSrcTy()); break; case Instruction::Trunc: case Instruction::ZExt: - case Instruction::SExt: case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::UIToFP: @@ -917,32 +1182,35 @@ void MSILWriter::printInstruction(const Instruction* Inst) { case Instruction::Invoke: printInvokeInstruction(cast(Inst)); break; - case Instruction::Unwind: { - std::string Class = "instance void [mscorlib]System.Exception::.ctor()"; - printSimpleInstruction("newobj",Class.c_str()); + case Instruction::Unwind: + printSimpleInstruction("newobj", + "instance void [mscorlib]System.Exception::.ctor()"); printSimpleInstruction("throw"); break; - } case Instruction::Switch: printSwitchInstruction(cast(Inst)); break; case Instruction::Alloca: - printValueLoad(Inst->getOperand(0)); - printSimpleInstruction("localloc"); + printAllocaInstruction(cast(Inst)); break; case Instruction::Malloc: - assert(0 && "LowerAllocationsPass used"); + llvm_unreachable("LowerAllocationsPass used"); break; case Instruction::Free: - assert(0 && "LowerAllocationsPass used"); + llvm_unreachable("LowerAllocationsPass used"); break; case Instruction::Unreachable: - printSimpleInstruction("ldnull"); + printSimpleInstruction("ldstr", "\"Unreachable instruction\""); + printSimpleInstruction("newobj", + "instance void [mscorlib]System.Exception::.ctor(string)"); printSimpleInstruction("throw"); break; + case Instruction::VAArg: + printVAArgInstruction(cast(Inst)); + break; default: cerr << "Instruction = " << Inst->getName() << '\n'; - assert(0 && "Unsupported instruction"); + llvm_unreachable("Unsupported instruction"); } } @@ -967,7 +1235,7 @@ void MSILWriter::printBasicBlock(const BasicBlock* BB) { 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"; + // Out << "\n//" << *Inst << "\n"; // Do not handle PHI instruction in current block if (Inst->getOpcode()==Instruction::PHI) continue; // Print instruction @@ -985,18 +1253,57 @@ void MSILWriter::printBasicBlock(const BasicBlock* BB) { void MSILWriter::printLocalVariables(const Function& F) { std::string Name; const Type* Ty = NULL; - // Find variables + std::set 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 (StackDepthgetNumOperands()) + StackDepth = I->getNumOperands(); + } const AllocaInst* AI = dyn_cast(&*I); if (AI && !isa(AI)) { - Ty = PointerType::get(AI->getAllocatedType()); + // Local variable allocation. + Ty = PointerType::getUnqual(AI->getAllocatedType()); Name = getValueName(AI); + Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; } else if (I->getType()!=Type::VoidTy) { + // Operation result. Ty = I->getType(); Name = getValueName(&*I); - } else continue; - Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; + Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; + } + // Test on 'va_list' variable + bool isVaList = false; + if (const VAArgInst* VaInst = dyn_cast(&*I)) { + // "va_list" as "va_arg" instruction operand. + isVaList = true; + VaList = VaInst->getOperand(0); + } else if (const IntrinsicInst* Inst = dyn_cast(&*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()); } @@ -1046,12 +1353,15 @@ void MSILWriter::printConstantExpr(const ConstantExpr* CE) { 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: @@ -1088,7 +1398,7 @@ void MSILWriter::printConstantExpr(const ConstantExpr* CE) { break; default: cerr << "Expression = " << *CE << "\n"; - assert(0 && "Invalid constant expression"); + llvm_unreachable("Invalid constant expression"); } } @@ -1104,8 +1414,8 @@ void MSILWriter::printStaticInitializerList() { for (std::vector::const_iterator I = InitList.begin(), E = InitList.end(); I!=E; ++I) { if (const ConstantExpr *CE = dyn_cast(I->constant)) { - Out << "\n// Init " << getValueName(VarI->first) << ", offset " << - utostr(I->offset) << ", type "<< *I->constant->getType() << "\n\n"; + // Out << "\n// Init " << getValueName(VarI->first) << ", offset " << + // utostr(I->offset) << ", type "<< *I->constant->getType() << "\n\n"; // Load variable address printValueLoad(VarI->first); // Add offset @@ -1122,7 +1432,7 @@ void MSILWriter::printStaticInitializerList() { printSimpleInstruction(postfix.c_str()); } else { cerr << "Constant = " << *I->constant << '\n'; - assert(0 && "Invalid static initializer"); + llvm_unreachable("Invalid static initializer"); } } } @@ -1130,10 +1440,9 @@ void MSILWriter::printStaticInitializerList() { void MSILWriter::printFunction(const Function& F) { - const FunctionType* FTy = F.getFunctionType(); - bool isSigned = FTy->paramHasAttr(0,FunctionType::SExtAttribute); + bool isSigned = F.paramHasAttr(0, Attribute::SExt); Out << "\n.method static "; - Out << (F.hasInternalLinkage() ? "private " : "public "); + Out << (F.hasLocalLinkage() ? "private " : "public "); if (F.isVarArg()) Out << "vararg "; Out << getTypeName(F.getReturnType(),isSigned) << getConvModopt(F.getCallingConv()) << getValueName(&F) << '\n'; @@ -1142,21 +1451,14 @@ void MSILWriter::printFunction(const Function& F) { unsigned ArgIdx = 1; for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I!=E; ++I, ++ArgIdx) { - isSigned = FTy->paramHasAttr(ArgIdx,FunctionType::SExtAttribute); + 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"; - // FIXME: Convert "string[]" to "argc,argv" - if (F.getName()=="main") { - printSimpleInstruction(".entrypoint"); - printLocalVariables(F); - printStaticInitializerList(); - } else { - printLocalVariables(F); - } + printLocalVariables(F); printFunctionBody(F); Out << "}\n"; } @@ -1165,22 +1467,18 @@ void MSILWriter::printFunction(const Function& F) { void MSILWriter::printDeclarations(const TypeSymbolTable& ST) { std::string Name; std::set Printed; - //cerr << "UsedTypes = " << UsedTypes << '\n'; for (std::set::const_iterator UI = UsedTypes->begin(), UE = UsedTypes->end(); UI!=UE; ++UI) { const Type* Ty = *UI; - if (isa(Ty)) - Name = getArrayTypeName(Ty->getTypeID(),Ty); - else if (isa(Ty)) - Name = getArrayTypeName(Ty->getTypeID(),Ty); - else if (isa(Ty)) - Name = ModulePtr->getTypeName(Ty); + if (isa(Ty) || isa(Ty) || isa(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->getTypeSize(Ty) << " }\n\n"; + Out << " { .pack " << 1 << " .size " << TD->getTypeAllocSize(Ty); + Out << " }\n\n"; } } } @@ -1198,8 +1496,9 @@ unsigned int MSILWriter::getBitWidth(const Type* Ty) { return N; default: cerr << "Bits = " << N << '\n'; - assert(0 && "Unsupported integer width"); + llvm_unreachable("Unsupported integer width"); } + return 0; // Not reached } @@ -1208,7 +1507,7 @@ void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { const Type* Ty = C->getType(); // Print zero initialized constant. if (isa(C) || C->isNullValue()) { - TySize = TD->getTypeSize(C->getType()); + TySize = TD->getTypeAllocSize(C->getType()); Offset += TySize; Out << "int8 (0) [" << TySize << "]"; return; @@ -1216,16 +1515,21 @@ void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { // Print constant initializer switch (Ty->getTypeID()) { case Type::IntegerTyID: { - TySize = TD->getTypeSize(Ty); + TySize = TD->getTypeAllocSize(Ty); const ConstantInt* Int = cast(C); Out << getPrimitiveTypeName(Ty,true) << "(" << Int->getSExtValue() << ")"; break; } case Type::FloatTyID: case Type::DoubleTyID: { - TySize = TD->getTypeSize(Ty); - const ConstantFP* CFp = cast(C); - Out << getPrimitiveTypeName(Ty,true) << "(" << CFp->getValue() << ")"; + TySize = TD->getTypeAllocSize(Ty); + const ConstantFP* FP = cast(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: @@ -1237,7 +1541,7 @@ void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { } break; case Type::PointerTyID: - TySize = TD->getTypeSize(C->getType()); + TySize = TD->getTypeAllocSize(C->getType()); // Initialize with global variable address if (const GlobalVariable *G = dyn_cast(C)) { std::string name = getValueName(G); @@ -1249,12 +1553,12 @@ void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { // Null pointer initialization if (TySize==4) Out << "int32 (0)"; else if (TySize==8) Out << "int64 (0)"; - else assert(0 && "Invalid pointer size"); + else llvm_unreachable("Invalid pointer size"); } break; default: cerr << "TypeID = " << Ty->getTypeID() << '\n'; - assert(0 && "Invalid type in printStaticConstant()"); + llvm_unreachable("Invalid type in printStaticConstant()"); } // Increase offset. Offset += TySize; @@ -1267,7 +1571,7 @@ void MSILWriter::printStaticInitializer(const Constant* C, case Type::IntegerTyID: case Type::FloatTyID: case Type::DoubleTyID: - Out << getPrimitiveTypeName(C->getType(),true); + Out << getPrimitiveTypeName(C->getType(), false); break; case Type::ArrayTyID: case Type::VectorTyID: @@ -1277,7 +1581,7 @@ void MSILWriter::printStaticInitializer(const Constant* C, break; default: cerr << "Type = " << *C << "\n"; - assert(0 && "Invalid constant type"); + llvm_unreachable("Invalid constant type"); } // Print initializer std::string label = Name; @@ -1305,46 +1609,107 @@ void MSILWriter::printGlobalVariables() { Module::global_iterator I,E; for (I = ModulePtr->global_begin(), E = ModulePtr->global_end(); I!=E; ++I) { // Variable definition - if (I->isDeclaration()) continue; - Out << ".field static " << (I->hasExternalLinkage() ? "public " : - "private "); - printVariableDefinition(&*I); + 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->getMangledName(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->getIntrinsicID()) continue; - // FIXME: Treat as standard library function + if (I->isIntrinsic()) continue; if (I->isDeclaration()) { - const Function* F = &*I; - const FunctionType* FTy = F->getFunctionType(); + const Function* F = I; std::string Name = getConvModopt(F->getCallingConv())+getValueName(F); - std::string Sig = getCallSignature(FTy,NULL,Name); - Out << ".method static hidebysig pinvokeimpl(\"msvcrt.dll\" cdecl)\n\t" - << Sig << " preservesig {}\n\n"; + std::string Sig = + getCallSignature(cast(F->getFunctionType()), NULL, Name); + Out << ".method static hidebysig pinvokeimpl(\"" + << getLibraryName(F) << "\")\n\t" << Sig << " preservesig {}\n\n"; } } + // External variables and static initialization. + Out << + ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" + " native int LoadLibrary(string) preservesig {}\n" + ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" + " native int GetProcAddress(native int, string) preservesig {}\n"; + Out << + ".method private static void* $MSIL_Import(string lib,string sym)\n" + " managed cil\n{\n" + "\tldarg\tlib\n" + "\tcall\tnative int LoadLibrary(string)\n" + "\tldarg\tsym\n" + "\tcall\tnative int GetProcAddress(native int,string)\n" + "\tdup\n" + "\tbrtrue\tL_01\n" + "\tldstr\t\"Can no import variable\"\n" + "\tnewobj\tinstance void [mscorlib]System.Exception::.ctor(string)\n" + "\tthrow\n" + "L_01:\n" + "\tret\n" + "}\n\n" + ".method static private void $MSIL_Init() managed cil\n{\n"; + printStaticInitializerList(); + // Foreach global variable. + for (Module::global_iterator I = ModulePtr->global_begin(), + E = ModulePtr->global_end(); I!=E; ++I) { + if (!I->isDeclaration() || !I->hasDLLImportLinkage()) continue; + // Use "LoadLibrary"/"GetProcAddress" to recive variable address. + std::string Label = "not_null$_"+utostr(getUniqID()); + std::string Tmp = getTypeName(I->getType())+getValueName(&*I); + printSimpleInstruction("ldsflda",Tmp.c_str()); + Out << "\tldstr\t\"" << getLibraryName(&*I) << "\"\n"; + Out << "\tldstr\t\"" << Mang->getMangledName(&*I) << "\"\n"; + printSimpleInstruction("call","void* $MSIL_Import(string,string)"); + printIndirectSave(I->getType()); + } + printSimpleInstruction("ret"); + Out << "}\n\n"; } + //===----------------------------------------------------------------------===// -// External Interface declaration +// External Interface declaration //===----------------------------------------------------------------------===// -bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, std::ostream &o, - CodeGenFileType FileType, bool Fast) +bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, + formatted_raw_ostream &o, + CodeGenFileType FileType, + CodeGenOpt::Level OptLevel) { if (FileType != TargetMachine::AssemblyFile) return true; MSILWriter* Writer = new MSILWriter(o); - PM.add(createLowerGCPass()); + PM.add(createGCLoweringPass()); PM.add(createLowerAllocationsPass(true)); // FIXME: Handle switch trougth native IL instruction "switch" PM.add(createLowerSwitchPass()); PM.add(createCFGSimplificationPass()); PM.add(new MSILModule(Writer->UsedTypes,Writer->TD)); PM.add(Writer); + PM.add(createGCInfoDeleter()); return false; }