//
// The LLVM Compiler Infrastructure
//
-// This file was developed by Roman Samoilov and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#include "llvm/DerivedTypes.h"
#include "llvm/Intrinsics.h"
#include "llvm/IntrinsicInst.h"
-#include "llvm/ParameterAttributes.h"
#include "llvm/TypeSymbolTable.h"
#include "llvm/Analysis/ConstantsScanner.h"
#include "llvm/Support/CallSite.h"
+#include "llvm/Support/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 {
+namespace llvm {
// TargetMachine for the MSIL
- struct VISIBILITY_HIDDEN MSILTarget : public TargetMachine {
- const TargetData DataLayout; // Calculates type size & alignment
-
- MSILTarget(const Module &M, const std::string &FS)
- : DataLayout(&M) {}
+ struct MSILTarget : public TargetMachine {
+ MSILTarget(const Target &T, const std::string &TT, const std::string &FS)
+ : TargetMachine(T) {}
virtual bool WantsWholeFile() const { return true; }
- virtual bool addPassesToEmitWholeFile(PassManager &PM, std::ostream &Out,
- CodeGenFileType FileType, bool Fast);
-
- // This class always works, but shouldn't be the default in most cases.
- static unsigned getModuleMatchQuality(const Module &M) { return 1; }
+ virtual bool addPassesToEmitWholeFile(PassManager &PM,
+ formatted_raw_ostream &Out,
+ CodeGenFileType FileType,
+ CodeGenOpt::Level OptLevel);
- virtual const TargetData *getTargetData() const { return &DataLayout; }
+ virtual const TargetData *getTargetData() const { return 0; }
};
}
-
-RegisterTarget<MSILTarget> X("msil", " MSIL backend");
+extern "C" void LLVMInitializeMSILTarget() {
+ // Register the target.
+ RegisterTargetMachine<MSILTarget> X(TheMSILTarget);
+}
bool MSILModule::runOnModule(Module &M) {
ModulePtr = &M;
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;
- Mang = new Mangler(M);
+ Mang = new Mangler(M);
Out << ".assembly extern mscorlib {}\n";
Out << ".assembly MSIL {}\n\n";
Out << "// External\n";
printDeclarations(M.getTypeSymbolTable());
Out << "// Definitions\n";
printGlobalVariables();
+ Out << "// Startup code\n";
+ printModuleStartup();
return false;
}
}
+void MSILWriter::printModuleStartup() {
+ Out <<
+ ".method static public int32 $MSIL_Startup() {\n"
+ "\t.entrypoint\n"
+ "\t.locals (native int i)\n"
+ "\t.locals (native int argc)\n"
+ "\t.locals (native int ptr)\n"
+ "\t.locals (void* argv)\n"
+ "\t.locals (string[] args)\n"
+ "\tcall\tstring[] [mscorlib]System.Environment::GetCommandLineArgs()\n"
+ "\tdup\n"
+ "\tstloc\targs\n"
+ "\tldlen\n"
+ "\tconv.i4\n"
+ "\tdup\n"
+ "\tstloc\targc\n";
+ printPtrLoad(TD->getPointerSize());
+ Out <<
+ "\tmul\n"
+ "\tlocalloc\n"
+ "\tstloc\targv\n"
+ "\tldc.i4.0\n"
+ "\tstloc\ti\n"
+ "L_01:\n"
+ "\tldloc\ti\n"
+ "\tldloc\targc\n"
+ "\tceq\n"
+ "\tbrtrue\tL_02\n"
+ "\tldloc\targs\n"
+ "\tldloc\ti\n"
+ "\tldelem.ref\n"
+ "\tcall\tnative int [mscorlib]System.Runtime.InteropServices.Marshal::"
+ "StringToHGlobalAnsi(string)\n"
+ "\tstloc\tptr\n"
+ "\tldloc\targv\n"
+ "\tldloc\ti\n";
+ printPtrLoad(TD->getPointerSize());
+ Out <<
+ "\tmul\n"
+ "\tadd\n"
+ "\tldloc\tptr\n"
+ "\tstind.i\n"
+ "\tldloc\ti\n"
+ "\tldc.i4.1\n"
+ "\tadd\n"
+ "\tstloc\ti\n"
+ "\tbr\tL_01\n"
+ "L_02:\n"
+ "\tcall void $MSIL_Init()\n";
+
+ // Call user 'main' function.
+ const Function* F = ModulePtr->getFunction("main");
+ if (!F || F->isDeclaration()) {
+ Out << "\tldc.i4.0\n\tret\n}\n";
+ return;
+ }
+ bool BadSig = true;
+ std::string Args("");
+ Function::const_arg_iterator Arg1,Arg2;
+
+ switch (F->arg_size()) {
+ case 0:
+ BadSig = false;
+ break;
+ case 1:
+ Arg1 = F->arg_begin();
+ if (Arg1->getType()->isInteger()) {
+ Out << "\tldloc\targc\n";
+ Args = getTypeName(Arg1->getType());
+ BadSig = false;
+ }
+ break;
+ case 2:
+ Arg1 = Arg2 = F->arg_begin(); ++Arg2;
+ if (Arg1->getType()->isInteger() &&
+ Arg2->getType()->getTypeID() == Type::PointerTyID) {
+ Out << "\tldloc\targc\n\tldloc\targv\n";
+ Args = getTypeName(Arg1->getType())+","+getTypeName(Arg2->getType());
+ BadSig = false;
+ }
+ break;
+ default:
+ BadSig = true;
+ }
+
+ bool RetVoid = (F->getReturnType()->getTypeID() == Type::VoidTyID);
+ if (BadSig || (!F->getReturnType()->isInteger() && !RetVoid)) {
+ Out << "\tldc.i4.0\n";
+ } else {
+ Out << "\tcall\t" << getTypeName(F->getReturnType()) <<
+ getConvModopt(F->getCallingConv()) << "main(" << Args << ")\n";
+ if (RetVoid)
+ Out << "\tldc.i4.0\n";
+ else
+ Out << "\tconv.i4\n";
+ }
+ Out << "\tret\n}\n";
+}
+
bool MSILWriter::isZeroValue(const Value* V) {
if (const Constant *C = dyn_cast<Constant>(V))
return C->isNullValue();
std::string MSILWriter::getValueName(const Value* V) {
+ std::string Name;
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
+ Name = Mang->getMangledName(GV);
+ else {
+ unsigned &No = AnonValueNumbers[V];
+ if (No == 0) No = ++NextAnonValueNumber;
+ Name = "tmp" + utostr(No);
+ }
+
// Name into the quotes allow control and space characters.
- return "'"+Mang->getValueName(V)+"'";
+ return "'"+Name+"'";
}
std::string MSILWriter::getLabelName(const Value* V) {
- return getLabelName(Mang->getValueName(V));
+ std::string Name;
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
+ Name = Mang->getMangledName(GV);
+ else {
+ unsigned &No = AnonValueNumbers[V];
+ if (No == 0) No = ++NextAnonValueNumber;
+ Name = "tmp" + utostr(No);
+ }
+
+ return getLabelName(Name);
}
-std::string MSILWriter::getConvModopt(unsigned CallingConvID) {
+std::string MSILWriter::getConvModopt(CallingConv::ID CallingConvID) {
switch (CallingConvID) {
case CallingConv::C:
case CallingConv::Cold:
case CallingConv::X86_StdCall:
return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) ";
default:
- cerr << "CallingConvID = " << CallingConvID << '\n';
- assert(0 && "Unsupported calling convention");
+ errs() << "CallingConvID = " << CallingConvID << '\n';
+ llvm_unreachable("Unsupported calling convention");
}
+ return ""; // Not reached
}
if (ElemTy->getTypeID()!=TyID) break;
Tmp += ",";
}
- return getTypeName(ElemTy)+"["+Tmp+"]";
+ return getTypeName(ElemTy, false, true)+"["+Tmp+"]";
}
case Type::DoubleTyID:
return "float64 ";
default:
- cerr << "Type = " << *Ty << '\n';
- assert(0 && "Invalid primitive type");
+ errs() << "Type = " << *Ty << '\n';
+ llvm_unreachable("Invalid primitive type");
}
+ return ""; // Not reached
}
-std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned) {
+std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned,
+ bool isNested) {
if (Ty->isPrimitiveType() || Ty->isInteger())
return getPrimitiveTypeName(Ty,isSigned);
// FIXME: "OpaqueType" support
case Type::PointerTyID:
return "void* ";
case Type::StructTyID:
+ if (isNested)
+ return ModulePtr->getTypeName(Ty);
return "valuetype '"+ModulePtr->getTypeName(Ty)+"' ";
case Type::ArrayTyID:
+ if (isNested)
+ return getArrayTypeName(Ty->getTypeID(),Ty);
return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' ";
case Type::VectorTyID:
+ if (isNested)
+ return getArrayTypeName(Ty->getTypeID(),Ty);
return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' ";
default:
- cerr << "Type = " << *Ty << '\n';
- assert(0 && "Invalid type in getTypeName()");
+ errs() << "Type = " << *Ty << '\n';
+ llvm_unreachable("Invalid type in getTypeName()");
}
+ return ""; // Not reached
}
return ArgumentVT;
// Function
else if (const Function* F = dyn_cast<Function>(V))
- return F->hasInternalLinkage() ? InternalVT : GlobalVT;
+ return F->hasLocalLinkage() ? InternalVT : GlobalVT;
// Variable
else if (const GlobalVariable* G = dyn_cast<GlobalVariable>(V))
- return G->hasInternalLinkage() ? InternalVT : GlobalVT;
+ return G->hasLocalLinkage() ? InternalVT : GlobalVT;
// Constant
else if (isa<Constant>(V))
return isa<ConstantExpr>(V) ? ConstExprVT : ConstVT;
case Type::DoubleTyID:
return "r8";
case Type::PointerTyID:
- return "i"+utostr(TD->getTypeSize(Ty));
+ 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:
- cerr << "TypeID = " << Ty->getTypeID() << '\n';
- assert(0 && "Invalid type in TypeToPostfix()");
+ llvm_unreachable("Module use not supporting pointer size");
}
}
case Module::Pointer32:
printSimpleInstruction("ldc.i4",utostr(N).c_str());
// FIXME: Need overflow test?
- assert(N<0xFFFFFFFF && "32-bit pointer overflowed");
+ if (!isUInt32(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:
- assert(0 && "Module use not supporting pointer size");
+ llvm_unreachable("Module use not supporting pointer size");
}
}
+void MSILWriter::printValuePtrLoad(const Value* V) {
+ printValueLoad(V);
+ printConvToPtr();
+}
+
+
void MSILWriter::printConstLoad(const Constant* C) {
if (const ConstantInt* CInt = dyn_cast<ConstantInt>(C)) {
// Integer constant
Out << CInt->getSExtValue();
else
Out << CInt->getZExtValue();
- } else if (const ConstantFP* CFp = dyn_cast<ConstantFP>(C)) {
+ } else if (const ConstantFP* FP = dyn_cast<ConstantFP>(C)) {
// Float constant
- Out << "\tldc." << getTypePostfix(C->getType(),true) << '\t' <<
- CFp->getValue();
+ uint64_t X;
+ unsigned Size;
+ if (FP->getType()->getTypeID()==Type::FloatTyID) {
+ X = (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue();
+ Size = 4;
+ } else {
+ X = FP->getValueAPF().bitcastToAPInt().getZExtValue();
+ Size = 8;
+ }
+ Out << "\tldc.r" << Size << "\t( " << utohexstr(X) << ')';
+ } else if (isa<UndefValue>(C)) {
+ // Undefined constant value = NULL.
+ printPtrLoad(0);
} else {
- cerr << "Constant = " << *C << '\n';
- assert(0 && "Invalid constant value");
+ errs() << "Constant = " << *C << '\n';
+ llvm_unreachable("Invalid constant value");
}
Out << '\n';
}
void MSILWriter::printValueLoad(const Value* V) {
- switch (getValueLocation(V)) {
+ MSILWriter::ValueType Location = getValueLocation(V);
+ switch (Location) {
// Global variable or function address.
case GlobalVT:
case InternalVT:
printSimpleInstruction("ldftn",
getCallSignature(F->getFunctionType(),NULL,Name).c_str());
} else {
+ std::string Tmp;
const Type* ElemTy = cast<PointerType>(V->getType())->getElementType();
- std::string Tmp = getTypeName(ElemTy)+getValueName(V);
- printSimpleInstruction("ldsflda",Tmp.c_str());
+ 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.
printConstantExpr(cast<ConstantExpr>(V));
break;
default:
- cerr << "Value = " << *V << '\n';
- assert(0 && "Invalid value location");
+ errs() << "Value = " << *V << '\n';
+ llvm_unreachable("Invalid value location");
}
}
printSimpleInstruction("stloc",getValueName(V).c_str());
break;
default:
- cerr << "Value = " << *V << '\n';
- assert(0 && "Invalid value location");
+ errs() << "Value = " << *V << '\n';
+ llvm_unreachable("Invalid value location");
}
}
void MSILWriter::printIndirectLoad(const Value* V) {
+ const Type* Ty = V->getType();
printValueLoad(V);
- std::string Tmp = "ldind."+getTypePostfix(V->getType(),false);
+ if (const PointerType* P = dyn_cast<PointerType>(Ty))
+ Ty = P->getElementType();
+ std::string Tmp = "ldind."+getTypePostfix(Ty, false);
printSimpleInstruction(Tmp.c_str());
}
-void MSILWriter::printStoreInstruction(const Instruction* Inst) {
- const Value* Val = Inst->getOperand(0);
- const Value* Ptr = Inst->getOperand(1);
- // Load destination address.
+void MSILWriter::printIndirectSave(const Value* Ptr, const Value* Val) {
printValueLoad(Ptr);
- // Load value.
printValueLoad(Val);
+ printIndirectSave(Val->getType());
+}
+
+
+void MSILWriter::printIndirectSave(const Type* Ty) {
// Instruction need signed postfix for any type.
- std::string postfix = getTypePostfix(Val->getType(),false);
+ std::string postfix = getTypePostfix(Ty, false);
if (*postfix.begin()=='u') *postfix.begin() = 'i';
postfix = "stind."+postfix;
printSimpleInstruction(postfix.c_str());
void MSILWriter::printCastInstruction(unsigned int Op, const Value* V,
- const Type* Ty) {
+ const Type* Ty, const Type* SrcTy) {
std::string Tmp("");
printValueLoad(V);
switch (Op) {
// Signed
case Instruction::SExt:
+ // If sign extending int, convert first from unsigned to signed
+ // with the same bit size - because otherwise we will loose the sign.
+ if (SrcTy) {
+ Tmp = "conv."+getTypePostfix(SrcTy,false,true);
+ printSimpleInstruction(Tmp.c_str());
+ }
+ // FALLTHROUGH
case Instruction::SIToFP:
case Instruction::FPToSI:
Tmp = "conv."+getTypePostfix(Ty,false,true);
// FIXME: meaning that ld*/st* instruction do not change data format.
break;
default:
- cerr << "Opcode = " << Op << '\n';
- assert(0 && "Invalid conversion instruction");
+ 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
- printValueLoad(V);
+ printValuePtrLoad(V);
// Calculate element offset.
- unsigned TySize;
- for (++I; I!=E; ++I){
- const Type* Ty = I.getIndexedType();
- const Value* Idx = I.getOperand();
- // Get size of type.
- switch (Ty->getTypeID()) {
- case Type::IntegerTyID:
- case Type::FloatTyID:
- case Type::DoubleTyID:
- case Type::PointerTyID:
- TySize = TD->getTypeSize(Ty);
- break;
- case Type::StructTyID:
- TySize = 0;
- break;
- case Type::ArrayTyID:
- TySize = TD->getTypeSize(cast<ArrayType>(Ty)->getElementType());
- break;
- case Type::VectorTyID:
- TySize = TD->getTypeSize(cast<VectorType>(Ty)->getElementType());
- break;
- default:
- cerr << "Type = " << *Ty << '\n';
- assert(0 && "Invalid index type in printGepInstruction()");
- }
- // Calculate offset to structure field.
- if (const StructType* STy = dyn_cast<StructType>(Ty)) {
- TySize = 0;
- uint64_t FieldIdx = cast<ConstantInt>(Idx)->getZExtValue();
- // Offset is the summ of all previous structure fields.
- for (uint64_t F = 0; F<FieldIdx; ++F)
- TySize += TD->getTypeSize(STy->getContainedType(unsigned(F)));
- // Add field offset to stack top.
- printPtrLoad(TySize);
+ for (; I!=E; ++I){
+ Size = 0;
+ const Value* IndexValue = I.getOperand();
+ if (const StructType* StrucTy = dyn_cast<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(Idx)) {
- uint64_t TySize = TD->getTypeSize(I.getIndexedType());
- // Constant optimization
- if (const ConstantInt* CInt = dyn_cast<ConstantInt>(Idx)) {
- printPtrLoad(CInt->getZExtValue()*TySize);
+ 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(TySize);
- printValueLoad(Idx);
+ printPtrLoad(Size);
+ printValuePtrLoad(IndexValue);
printSimpleInstruction("mul");
}
printSimpleInstruction("add");
std::string MSILWriter::getCallSignature(const FunctionType* Ty,
const Instruction* Inst,
std::string Name) {
- std::string Tmp = "";
+ std::string Tmp("");
if (Ty->isVarArg()) Tmp += "vararg ";
// Name and return type.
Tmp += getTypeName(Ty->getReturnType())+Name+"(";
// CLR needs to know the exact amount of parameters received by vararg
// function, because caller cleans the stack.
if (Ty->isVarArg() && Inst) {
- // Origin to function arguments in "CallInst" or "InvokeInst"
+ // Origin to function arguments in "CallInst" or "InvokeInst".
unsigned Org = isa<InvokeInst>(Inst) ? 3 : 1;
// Print variable argument types.
unsigned NumOperands = Inst->getNumOperands()-Org;
void MSILWriter::printFunctionCall(const Value* FnVal,
const Instruction* Inst) {
- // Get function calling convention
+ // Get function calling convention.
std::string Name = "";
if (const CallInst* Call = dyn_cast<CallInst>(Inst))
Name = getConvModopt(Call->getCallingConv());
else if (const InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst))
Name = getConvModopt(Invoke->getCallingConv());
else {
- cerr << "Instruction = " << Inst->getName() << '\n';
- assert(0 && "Need \"Invoke\" or \"Call\" instruction only");
+ errs() << "Instruction = " << Inst->getName() << '\n';
+ llvm_unreachable("Need \"Invoke\" or \"Call\" instruction only");
}
-
if (const Function* F = dyn_cast<Function>(FnVal)) {
- // Direct call
+ // Direct call.
Name += getValueName(F);
printSimpleInstruction("call",
getCallSignature(F->getFunctionType(),Inst,Name).c_str());
} else {
- // Indirect function call
+ // Indirect function call.
const PointerType* PTy = cast<PointerType>(FnVal->getType());
const FunctionType* FTy = cast<FunctionType>(PTy->getElementType());
- // Load function address
+ // Load function address.
printValueLoad(FnVal);
printSimpleInstruction("calli",getCallSignature(FTy,Inst,Name).c_str());
}
}
+void MSILWriter::printIntrinsicCall(const IntrinsicInst* Inst) {
+ std::string Name;
+ switch (Inst->getIntrinsicID()) {
+ case Intrinsic::vastart:
+ Name = getValueName(Inst->getOperand(1));
+ Name.insert(Name.length()-1,"$valist");
+ // Obtain the argument handle.
+ printSimpleInstruction("ldloca",Name.c_str());
+ printSimpleInstruction("arglist");
+ printSimpleInstruction("call",
+ "instance void [mscorlib]System.ArgIterator::.ctor"
+ "(valuetype [mscorlib]System.RuntimeArgumentHandle)");
+ // Save as pointer type "void*"
+ printValueLoad(Inst->getOperand(1));
+ printSimpleInstruction("ldloca",Name.c_str());
+ printIndirectSave(PointerType::getUnqual(
+ IntegerType::get(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) {
- // Load arguments to stack
- for (int I = 1, E = Inst->getNumOperands(); I!=E; ++I)
- printValueLoad(Inst->getOperand(I));
- printFunctionCall(Inst->getOperand(0),Inst);
+ if (isa<IntrinsicInst>(Inst)) {
+ // Handle intrinsic function.
+ printIntrinsicCall(cast<IntrinsicInst>(Inst));
+ } else {
+ // Load arguments to stack and call function.
+ for (int I = 1, E = Inst->getNumOperands(); I!=E; ++I)
+ printValueLoad(Inst->getOperand(I));
+ printFunctionCall(Inst->getOperand(0),Inst);
+ }
}
printBinaryInstruction("ceq",Left,Right);
break;
case ICmpInst::ICMP_NE:
- // Emulate = not (Op1 eq Op2)
+ // Emulate = not neg (Op1 eq Op2)
printBinaryInstruction("ceq",Left,Right);
+ printSimpleInstruction("neg");
printSimpleInstruction("not");
break;
case ICmpInst::ICMP_ULE:
break;
case ICmpInst::ICMP_UGT:
printBinaryInstruction("cgt.un",Left,Right);
+ break;
case ICmpInst::ICMP_SGT:
printBinaryInstruction("cgt",Left,Right);
break;
default:
- cerr << "Predicate = " << Predicate << '\n';
- assert(0 && "Invalid icmp predicate");
+ errs() << "Predicate = " << Predicate << '\n';
+ llvm_unreachable("Invalid icmp predicate");
}
}
case FCmpInst::FCMP_UNE:
// X != Y
printBinaryInstruction("ceq",Left,Right);
+ printSimpleInstruction("neg");
printSimpleInstruction("not");
break;
case FCmpInst::FCMP_ONE:
printSimpleInstruction("or");
break;
default:
- assert(0 && "Illegal FCmp predicate");
+ llvm_unreachable("Illegal FCmp predicate");
}
}
}
+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","VAArg" support.
+ // FIXME: "ShuffleVector","ExtractElement","InsertElement" support.
switch (Inst->getOpcode()) {
// Terminator
case Instruction::Ret:
break;
// Binary
case Instruction::Add:
+ case Instruction::FAdd:
printBinaryInstruction("add",Left,Right);
break;
case Instruction::Sub:
+ case Instruction::FSub:
printBinaryInstruction("sub",Left,Right);
break;
- case Instruction::Mul:
+ case Instruction::Mul:
+ case Instruction::FMul:
printBinaryInstruction("mul",Left,Right);
break;
case Instruction::UDiv:
printBinaryInstruction("xor",Left,Right);
break;
case Instruction::Shl:
- printBinaryInstruction("shl",Left,Right);
+ printValueLoad(Left);
+ printValueLoad(Right);
+ printSimpleInstruction("conv.i4");
+ printSimpleInstruction("shl");
break;
case Instruction::LShr:
- printBinaryInstruction("shr.un",Left,Right);
+ printValueLoad(Left);
+ printValueLoad(Right);
+ printSimpleInstruction("conv.i4");
+ printSimpleInstruction("shr.un");
break;
case Instruction::AShr:
- printBinaryInstruction("shr",Left,Right);
+ printValueLoad(Left);
+ printValueLoad(Right);
+ printSimpleInstruction("conv.i4");
+ printSimpleInstruction("shr");
break;
case Instruction::Select:
printSelectInstruction(Inst->getOperand(0),Inst->getOperand(1),Inst->getOperand(2));
printIndirectLoad(Inst->getOperand(0));
break;
case Instruction::Store:
- printStoreInstruction(Inst);
+ printIndirectSave(Inst->getOperand(1), Inst->getOperand(0));
+ break;
+ case Instruction::SExt:
+ printCastInstruction(Inst->getOpcode(),Left,
+ cast<CastInst>(Inst)->getDestTy(),
+ cast<CastInst>(Inst)->getSrcTy());
break;
case Instruction::Trunc:
case Instruction::ZExt:
- case Instruction::SExt:
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::UIToFP:
case Instruction::Invoke:
printInvokeInstruction(cast<InvokeInst>(Inst));
break;
- case Instruction::Unwind: {
- std::string Class = "instance void [mscorlib]System.Exception::.ctor()";
- printSimpleInstruction("newobj",Class.c_str());
+ case Instruction::Unwind:
+ printSimpleInstruction("newobj",
+ "instance void [mscorlib]System.Exception::.ctor()");
printSimpleInstruction("throw");
break;
- }
case Instruction::Switch:
printSwitchInstruction(cast<SwitchInst>(Inst));
break;
case Instruction::Alloca:
- printValueLoad(Inst->getOperand(0));
- printSimpleInstruction("localloc");
- break;
- case Instruction::Malloc:
- assert(0 && "LowerAllocationsPass used");
- break;
- case Instruction::Free:
- assert(0 && "LowerAllocationsPass used");
+ printAllocaInstruction(cast<AllocaInst>(Inst));
break;
case Instruction::Unreachable:
- printSimpleInstruction("ldnull");
+ printSimpleInstruction("ldstr", "\"Unreachable instruction\"");
+ printSimpleInstruction("newobj",
+ "instance void [mscorlib]System.Exception::.ctor(string)");
printSimpleInstruction("throw");
break;
+ case Instruction::VAArg:
+ printVAArgInstruction(cast<VAArgInst>(Inst));
+ break;
default:
- cerr << "Instruction = " << Inst->getName() << '\n';
- assert(0 && "Unsupported instruction");
+ errs() << "Instruction = " << Inst->getName() << '\n';
+ llvm_unreachable("Unsupported instruction");
}
}
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E; ++I) {
const Instruction* Inst = I;
// Comment llvm original instruction
- Out << "\n//" << *Inst << "\n";
+ // Out << "\n//" << *Inst << "\n";
// Do not handle PHI instruction in current block
if (Inst->getOpcode()==Instruction::PHI) continue;
// Print instruction
printInstruction(Inst);
// Save result
- if (Inst->getType()!=Type::VoidTy) {
+ 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;
- // Find variables
+ 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)) {
- Ty = PointerType::get(AI->getAllocatedType());
+ // Local variable allocation.
+ Ty = PointerType::getUnqual(AI->getAllocatedType());
Name = getValueName(AI);
- } else if (I->getType()!=Type::VoidTy) {
+ Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n";
+ } else if (I->getType()!=Type::getVoidTy(F.getContext())) {
+ // Operation result.
Ty = I->getType();
Name = getValueName(&*I);
- } else continue;
- Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n";
+ Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n";
+ }
+ // Test on 'va_list' variable
+ bool isVaList = false;
+ if (const VAArgInst* VaInst = dyn_cast<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());
}
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("shr",left,right);
break;
default:
- cerr << "Expression = " << *CE << "\n";
- assert(0 && "Invalid constant expression");
+ errs() << "Expression = " << *CE << "\n";
+ llvm_unreachable("Invalid constant expression");
}
}
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";
+ // Out << "\n// Init " << getValueName(VarI->first) << ", offset " <<
+ // utostr(I->offset) << ", type "<< *I->constant->getType() << "\n\n";
// Load variable address
printValueLoad(VarI->first);
// Add offset
postfix = "stind."+postfix;
printSimpleInstruction(postfix.c_str());
} else {
- cerr << "Constant = " << *I->constant << '\n';
- assert(0 && "Invalid static initializer");
+ errs() << "Constant = " << *I->constant << '\n';
+ llvm_unreachable("Invalid static initializer");
}
}
}
void MSILWriter::printFunction(const Function& F) {
- const FunctionType* FTy = F.getFunctionType();
- const ParamAttrsList *Attrs = FTy->getParamAttrs();
- bool isSigned = Attrs && Attrs->paramHasAttr(0, ParamAttr::SExt);
+ bool isSigned = F.paramHasAttr(0, Attribute::SExt);
Out << "\n.method static ";
- Out << (F.hasInternalLinkage() ? "private " : "public ");
+ Out << (F.hasLocalLinkage() ? "private " : "public ");
if (F.isVarArg()) Out << "vararg ";
Out << getTypeName(F.getReturnType(),isSigned) <<
getConvModopt(F.getCallingConv()) << getValueName(&F) << '\n';
unsigned ArgIdx = 1;
for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I!=E;
++I, ++ArgIdx) {
- isSigned = Attrs && Attrs->paramHasAttr(ArgIdx, ParamAttr::SExt);
+ isSigned = F.paramHasAttr(ArgIdx, Attribute::SExt);
if (I!=F.arg_begin()) Out << ", ";
Out << getTypeName(I->getType(),isSigned) << getValueName(I);
}
Out << ") cil managed\n";
// Body
Out << "{\n";
- // FIXME: Convert "string[]" to "argc,argv"
- if (F.getName()=="main") {
- printSimpleInstruction(".entrypoint");
- printLocalVariables(F);
- printStaticInitializerList();
- } else {
- printLocalVariables(F);
- }
+ printLocalVariables(F);
printFunctionBody(F);
Out << "}\n";
}
void MSILWriter::printDeclarations(const TypeSymbolTable& ST) {
std::string Name;
std::set<const Type*> Printed;
- //cerr << "UsedTypes = " << UsedTypes << '\n';
for (std::set<const Type*>::const_iterator
UI = UsedTypes->begin(), UE = UsedTypes->end(); UI!=UE; ++UI) {
const Type* Ty = *UI;
- if (isa<ArrayType>(Ty))
- Name = getArrayTypeName(Ty->getTypeID(),Ty);
- else if (isa<VectorType>(Ty))
- Name = getArrayTypeName(Ty->getTypeID(),Ty);
- else if (isa<StructType>(Ty))
- Name = ModulePtr->getTypeName(Ty);
+ if (isa<ArrayType>(Ty) || isa<VectorType>(Ty) || isa<StructType>(Ty))
+ Name = getTypeName(Ty, false, true);
// Type with no need to declare.
else continue;
// Print not duplicated type
if (Printed.insert(Ty).second) {
Out << ".class value explicit ansi sealed '" << Name << "'";
- Out << " { .pack " << 1 << " .size " << TD->getTypeSize(Ty) << " }\n\n";
+ Out << " { .pack " << 1 << " .size " << TD->getTypeAllocSize(Ty);
+ Out << " }\n\n";
}
}
}
case 64:
return N;
default:
- cerr << "Bits = " << N << '\n';
- assert(0 && "Unsupported integer width");
+ errs() << "Bits = " << N << '\n';
+ llvm_unreachable("Unsupported integer width");
}
+ return 0; // Not reached
}
const Type* Ty = C->getType();
// Print zero initialized constant.
if (isa<ConstantAggregateZero>(C) || C->isNullValue()) {
- TySize = TD->getTypeSize(C->getType());
+ TySize = TD->getTypeAllocSize(C->getType());
Offset += TySize;
Out << "int8 (0) [" << TySize << "]";
return;
// Print constant initializer
switch (Ty->getTypeID()) {
case Type::IntegerTyID: {
- TySize = TD->getTypeSize(Ty);
+ 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->getTypeSize(Ty);
- const ConstantFP* CFp = cast<ConstantFP>(C);
- Out << getPrimitiveTypeName(Ty,true) << "(" << CFp->getValue() << ")";
+ 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::StructTyID:
for (unsigned I = 0, E = C->getNumOperands(); I<E; I++) {
if (I!=0) Out << ",\n";
- printStaticConstant(C->getOperand(I),Offset);
+ printStaticConstant(cast<Constant>(C->getOperand(I)), Offset);
}
break;
case Type::PointerTyID:
- TySize = TD->getTypeSize(C->getType());
+ TySize = TD->getTypeAllocSize(C->getType());
// Initialize with global variable address
if (const GlobalVariable *G = dyn_cast<GlobalVariable>(C)) {
std::string name = getValueName(G);
// Null pointer initialization
if (TySize==4) Out << "int32 (0)";
else if (TySize==8) Out << "int64 (0)";
- else assert(0 && "Invalid pointer size");
+ else llvm_unreachable("Invalid pointer size");
}
break;
default:
- cerr << "TypeID = " << Ty->getTypeID() << '\n';
- assert(0 && "Invalid type in printStaticConstant()");
+ errs() << "TypeID = " << Ty->getTypeID() << '\n';
+ llvm_unreachable("Invalid type in printStaticConstant()");
}
// Increase offset.
Offset += TySize;
case Type::IntegerTyID:
case Type::FloatTyID:
case Type::DoubleTyID:
- Out << getPrimitiveTypeName(C->getType(),true);
+ Out << getPrimitiveTypeName(C->getType(), false);
break;
case Type::ArrayTyID:
case Type::VectorTyID:
Out << getTypeName(C->getType());
break;
default:
- cerr << "Type = " << *C << "\n";
- assert(0 && "Invalid constant type");
+ errs() << "Type = " << *C << "\n";
+ llvm_unreachable("Invalid constant type");
}
// Print initializer
std::string label = Name;
Module::global_iterator I,E;
for (I = ModulePtr->global_begin(), E = ModulePtr->global_end(); I!=E; ++I) {
// Variable definition
- if (I->isDeclaration()) continue;
- Out << ".field static " << (I->hasExternalLinkage() ? "public " :
- "private ");
- printVariableDefinition(&*I);
+ Out << ".field static " << (I->isDeclaration() ? "public " :
+ "private ");
+ if (I->isDeclaration()) {
+ Out << getTypeName(I->getType()) << getValueName(&*I) << "\n\n";
+ } else
+ printVariableDefinition(&*I);
}
}
+const char* MSILWriter::getLibraryName(const Function* F) {
+ return getLibraryForSymbol(F->getName(), true, F->getCallingConv());
+}
+
+
+const char* MSILWriter::getLibraryName(const GlobalVariable* GV) {
+ return getLibraryForSymbol(Mang->getMangledName(GV), 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->getIntrinsicID()) continue;
- // FIXME: Treat as standard library function
+ if (I->isIntrinsic()) continue;
if (I->isDeclaration()) {
- const Function* F = &*I;
- const FunctionType* FTy = F->getFunctionType();
+ const Function* F = I;
std::string Name = getConvModopt(F->getCallingConv())+getValueName(F);
- std::string Sig = getCallSignature(FTy,NULL,Name);
- Out << ".method static hidebysig pinvokeimpl(\"msvcrt.dll\" cdecl)\n\t"
- << Sig << " preservesig {}\n\n";
+ std::string Sig =
+ getCallSignature(cast<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\"" << Mang->getMangledName(&*I) << "\"\n";
+ printSimpleInstruction("call","void* $MSIL_Import(string,string)");
+ printIndirectSave(I->getType());
+ }
+ printSimpleInstruction("ret");
+ Out << "}\n\n";
}
+
//===----------------------------------------------------------------------===//
// External Interface declaration
//===----------------------------------------------------------------------===//
-bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, std::ostream &o,
- CodeGenFileType FileType, bool Fast)
+bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM,
+ formatted_raw_ostream &o,
+ CodeGenFileType FileType,
+ CodeGenOpt::Level OptLevel)
{
if (FileType != TargetMachine::AssemblyFile) return true;
MSILWriter* Writer = new MSILWriter(o);
- PM.add(createLowerGCPass());
- PM.add(createLowerAllocationsPass(true));
+ PM.add(createGCLoweringPass());
// FIXME: Handle switch trougth native IL instruction "switch"
PM.add(createLowerSwitchPass());
PM.add(createCFGSimplificationPass());
PM.add(new MSILModule(Writer->UsedTypes,Writer->TD));
PM.add(Writer);
+ PM.add(createGCInfoDeleter());
return false;
}