+//===-- MSILWriter.cpp - Library for converting LLVM code to MSIL ---------===//
//
-// The LLVM Compiler Infrastructure
+// The LLVM Compiler Infrastructure
//
-// This file was developed by Roman Samoilov and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
#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/Transforms/Scalar.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/CodeGen/Passes.h"
namespace {
// TargetMachine for the MSIL
struct VISIBILITY_HIDDEN MSILTarget : public TargetMachine {
const TargetData DataLayout; // Calculates type size & alignment
- MSILTarget(const Module &M, const std::string &FS)
- : DataLayout(&M) {}
+ MSILTarget(const Target &T, const Module &M, const std::string &FS)
+ : TargetMachine(T), DataLayout(&M) {}
virtual bool WantsWholeFile() const { return true; }
- virtual bool addPassesToEmitWholeFile(PassManager &PM, std::ostream &Out,
- CodeGenFileType FileType, bool Fast);
+ virtual bool addPassesToEmitWholeFile(PassManager &PM,
+ formatted_raw_ostream &Out,
+ CodeGenFileType FileType,
+ CodeGenOpt::Level OptLevel);
// This class always works, but shouldn't be the default in most cases.
static unsigned getModuleMatchQuality(const Module &M) { return 1; }
};
}
+extern Target TheMSILTarget;
+static RegisterTarget<MSILTarget> X(TheMSILTarget, "msil", "MSIL backend");
-RegisterTarget<MSILTarget> X("msil", " MSIL backend");
+// Force static initialization.
+extern "C" void LLVMInitializeMSILTarget() { }
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;
Out << "\tldc.i4.0\n\tret\n}\n";
return;
}
- bool BadSig = true;;
+ bool BadSig = true;
std::string Args("");
Function::const_arg_iterator Arg1,Arg2;
}
bool RetVoid = (F->getReturnType()->getTypeID() == Type::VoidTyID);
- if (BadSig || !F->getReturnType()->isInteger() && !RetVoid) {
+ if (BadSig || (!F->getReturnType()->isInteger() && !RetVoid)) {
Out << "\tldc.i4.0\n";
} else {
Out << "\tcall\t" << getTypeName(F->getReturnType()) <<
std::string MSILWriter::getValueName(const Value* V) {
+ std::string Name;
+ if (const GlobalValue *GV = 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 = cast<GlobalValue>(V))
+ Name = Mang->getMangledName(GV);
+ else {
+ unsigned &No = AnonValueNumbers[V];
+ if (No == 0) No = ++NextAnonValueNumber;
+ Name = "tmp" + utostr(No);
+ }
+
+ return getLabelName(Name);
}
return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) ";
default:
cerr << "CallingConvID = " << CallingConvID << '\n';
- assert(0 && "Unsupported calling convention");
+ llvm_unreachable("Unsupported calling convention");
}
+ return ""; // Not reached
}
return "float64 ";
default:
cerr << "Type = " << *Ty << '\n';
- assert(0 && "Invalid primitive type");
+ llvm_unreachable("Invalid primitive type");
}
+ return ""; // Not reached
}
return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' ";
default:
cerr << "Type = " << *Ty << '\n';
- assert(0 && "Invalid type in getTypeName()");
+ llvm_unreachable("Invalid type in getTypeName()");
}
+ return ""; // Not reached
}
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:
cerr << "TypeID = " << Ty->getTypeID() << '\n';
- assert(0 && "Invalid type in TypeToPostfix()");
+ llvm_unreachable("Invalid type in TypeToPostfix()");
}
+ return ""; // Not reached
}
printSimpleInstruction("conv.u8");
break;
default:
- assert(0 && "Module use not supporting pointer size");
+ llvm_unreachable("Module use not supporting pointer size");
}
}
// FIXME: Need overflow test?
if (!isUInt32(N)) {
cerr << "Value = " << utostr(N) << '\n';
- assert(0 && "32-bit pointer overflowed");
+ 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");
}
}
uint64_t X;
unsigned Size;
if (FP->getType()->getTypeID()==Type::FloatTyID) {
- X = FloatToBits(FP->getValue());
+ X = (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue();
Size = 4;
} else {
- X = DoubleToBits(FP->getValue());
+ X = FP->getValueAPF().bitcastToAPInt().getZExtValue();
Size = 8;
}
Out << "\tldc.r" << Size << "\t( " << utohexstr(X) << ')';
printPtrLoad(0);
} else {
cerr << "Constant = " << *C << '\n';
- assert(0 && "Invalid constant value");
+ llvm_unreachable("Invalid constant value");
}
Out << '\n';
}
break;
default:
cerr << "Value = " << *V << '\n';
- assert(0 && "Invalid value location");
+ llvm_unreachable("Invalid value location");
}
}
break;
default:
cerr << "Value = " << *V << '\n';
- assert(0 && "Invalid value location");
+ llvm_unreachable("Invalid value location");
}
}
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);
break;
default:
cerr << "Opcode = " << Op << '\n';
- assert(0 && "Invalid conversion instruction");
+ llvm_unreachable("Invalid conversion instruction");
}
}
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->getTypeSize(StrucTy->getContainedType((unsigned)F));
+ Size += TD->getTypeAllocSize(StrucTy->getContainedType((unsigned)F));
printPtrLoad(Size);
printSimpleInstruction("add");
continue;
} else if (const SequentialType* SeqTy = dyn_cast<SequentialType>(*I)) {
- Size = TD->getTypeSize(SeqTy->getElementType());
+ Size = TD->getTypeAllocSize(SeqTy->getElementType());
} else {
- Size = TD->getTypeSize(*I);
+ Size = TD->getTypeAllocSize(*I);
}
// Add offset of current element to stack top.
if (!isZeroValue(IndexValue)) {
Name = getConvModopt(Invoke->getCallingConv());
else {
cerr << "Instruction = " << Inst->getName() << '\n';
- assert(0 && "Need \"Invoke\" or \"Call\" instruction only");
+ llvm_unreachable("Need \"Invoke\" or \"Call\" instruction only");
}
if (const Function* F = dyn_cast<Function>(FnVal)) {
// Direct call.
// Save as pointer type "void*"
printValueLoad(Inst->getOperand(1));
printSimpleInstruction("ldloca",Name.c_str());
- printIndirectSave(PointerType::get(IntegerType::get(8)));
+ printIndirectSave(PointerType::getUnqual(IntegerType::get(8)));
break;
case Intrinsic::vaend:
// Close argument list handle.
break;
default:
cerr << "Intrinsic ID = " << Inst->getIntrinsicID() << '\n';
- assert(0 && "Invalid intrinsic function");
+ llvm_unreachable("Invalid intrinsic function");
}
}
break;
case ICmpInst::ICMP_UGT:
printBinaryInstruction("cgt.un",Left,Right);
+ break;
case ICmpInst::ICMP_SGT:
printBinaryInstruction("cgt",Left,Right);
break;
default:
cerr << "Predicate = " << Predicate << '\n';
- assert(0 && "Invalid icmp predicate");
+ llvm_unreachable("Invalid icmp predicate");
}
}
printSimpleInstruction("or");
break;
default:
- assert(0 && "Illegal FCmp predicate");
+ llvm_unreachable("Illegal FCmp predicate");
}
}
printSimpleInstruction("call",
"instance typedref [mscorlib]System.ArgIterator::GetNextArg()");
printSimpleInstruction("refanyval","void*");
- std::string Name = "ldind."+getTypePostfix(PointerType::get(IntegerType::get(8)),false);
+ std::string Name =
+ "ldind."+getTypePostfix(PointerType::getUnqual(IntegerType::get(8)),false);
printSimpleInstruction(Name.c_str());
}
void MSILWriter::printAllocaInstruction(const AllocaInst* Inst) {
- uint64_t Size = TD->getTypeSize(Inst->getAllocatedType());
+ uint64_t Size = TD->getTypeAllocSize(Inst->getAllocatedType());
// Constant optimization.
if (const ConstantInt* CInt = dyn_cast<ConstantInt>(Inst->getOperand(0))) {
printPtrLoad(CInt->getZExtValue()*Size);
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:
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::SExt:
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::UIToFP:
printAllocaInstruction(cast<AllocaInst>(Inst));
break;
case Instruction::Malloc:
- assert(0 && "LowerAllocationsPass used");
+ llvm_unreachable("LowerAllocationsPass used");
break;
case Instruction::Free:
- assert(0 && "LowerAllocationsPass used");
+ llvm_unreachable("LowerAllocationsPass used");
break;
case Instruction::Unreachable:
printSimpleInstruction("ldstr", "\"Unreachable instruction\"");
break;
default:
cerr << "Instruction = " << Inst->getName() << '\n';
- assert(0 && "Unsupported instruction");
+ 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
const AllocaInst* AI = dyn_cast<AllocaInst>(&*I);
if (AI && !isa<GlobalVariable>(AI)) {
// Local variable allocation.
- Ty = PointerType::get(AI->getAllocatedType());
+ Ty = PointerType::getUnqual(AI->getAllocatedType());
Name = getValueName(AI);
Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n";
} else if (I->getType()!=Type::VoidTy) {
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:
break;
default:
cerr << "Expression = " << *CE << "\n";
- assert(0 && "Invalid constant expression");
+ 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
printSimpleInstruction(postfix.c_str());
} else {
cerr << "Constant = " << *I->constant << '\n';
- assert(0 && "Invalid static initializer");
+ 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);
}
// 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";
}
}
}
return N;
default:
cerr << "Bits = " << N << '\n';
- assert(0 && "Unsupported integer width");
+ 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);
+ TySize = TD->getTypeAllocSize(Ty);
const ConstantFP* FP = cast<ConstantFP>(C);
if (Ty->getTypeID() == Type::FloatTyID)
- Out << "int32 (" << FloatToBits(FP->getValue()) << ')';
+ Out << "int32 (" <<
+ (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')';
else
- Out << "int64 (" << DoubleToBits(FP->getValue()) << ')';
+ Out << "int64 (" <<
+ FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')';
break;
}
case Type::ArrayTyID:
}
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()");
+ llvm_unreachable("Invalid type in printStaticConstant()");
}
// Increase offset.
Offset += TySize;
break;
default:
cerr << "Type = " << *C << "\n";
- assert(0 && "Invalid constant type");
+ llvm_unreachable("Invalid constant type");
}
// Print initializer
std::string label = Name;
const char* MSILWriter::getLibraryName(const GlobalVariable* GV) {
- return getLibraryForSymbol(Mang->getValueName(GV).c_str(), false, 0);
+ return getLibraryForSymbol(Mang->getMangledName(GV).c_str(), false, 0);
}
// Functions.
for (I=ModulePtr->begin(),E=ModulePtr->end(); I!=E; ++I) {
// Skip intrisics
- if (I->getIntrinsicID()) continue;
+ if (I->isIntrinsic()) continue;
if (I->isDeclaration()) {
const Function* F = I;
std::string Name = getConvModopt(F->getCallingConv())+getValueName(F);
std::string Tmp = getTypeName(I->getType())+getValueName(&*I);
printSimpleInstruction("ldsflda",Tmp.c_str());
Out << "\tldstr\t\"" << getLibraryName(&*I) << "\"\n";
- Out << "\tldstr\t\"" << Mang->getValueName(&*I) << "\"\n";
+ Out << "\tldstr\t\"" << Mang->getMangledName(&*I) << "\"\n";
printSimpleInstruction("call","void* $MSIL_Import(string,string)");
printIndirectSave(I->getType());
}
//===----------------------------------------------------------------------===//
-// External Interface declaration
+// External Interface declaration
//===----------------------------------------------------------------------===//
-bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM, std::ostream &o,
- CodeGenFileType FileType, bool Fast)
+bool MSILTarget::addPassesToEmitWholeFile(PassManager &PM,
+ formatted_raw_ostream &o,
+ CodeGenFileType FileType,
+ CodeGenOpt::Level OptLevel)
{
if (FileType != TargetMachine::AssemblyFile) return true;
MSILWriter* Writer = new MSILWriter(o);
- PM.add(createLowerGCPass());
+ PM.add(createGCLoweringPass());
PM.add(createLowerAllocationsPass(true));
// FIXME: Handle switch trougth native IL instruction "switch"
PM.add(createLowerSwitchPass());
PM.add(createCFGSimplificationPass());
PM.add(new MSILModule(Writer->UsedTypes,Writer->TD));
PM.add(Writer);
+ PM.add(createGCInfoDeleter());
return false;
}