mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-23 15:29:51 +00:00
22a5b29820
encapsulation to force the users of these classes to know about the internal data structure of the Operands structure. It also can lead to errors, like in the MSIL writer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@105539 91177308-0d34-0410-b5e6-96231b3b80d8
1708 lines
53 KiB
C++
1708 lines
53 KiB
C++
//===-- 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 {
|
|
const CallInst *CI = cast<CallInst>(Inst);
|
|
// Load arguments to stack and call function.
|
|
for (int I = 0, E = CI->getNumArgOperands(); I!=E; ++I)
|
|
printValueLoad(CI->getArgOperand(I));
|
|
printFunctionCall(CI->getCalledFunction(), 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 = 0, E = Inst->getNumArgOperands(); I!=E; ++I)
|
|
printValueLoad(Inst->getArgOperand(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;
|
|
}
|