llvm-6502/lib/Target/MSIL/MSILWriter.cpp
Bill Wendling 22a5b29820 Create new accessors to get arguments for call/invoke instructions. It breaks
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
2010-06-07 19:05:06 +00:00

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;
}