blob: 1dd9069930b466fda25df9c04886a280f5c49b3a [file] [log] [blame]
//===-- HLVM to LLVM Code Generator -----------------------------*- C++ -*-===//
//
// High Level Virtual Machine (HLVM)
//
// Copyright (C) 2006 Reid Spencer. All Rights Reserved.
//
// This software is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This software is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library in the file named LICENSE.txt; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
//
//===----------------------------------------------------------------------===//
/// @file hlvm/CodeGen/LLVMGenerator.cpp
/// @author Reid Spencer <rspencer@x10sys.com>
/// @date 2006/05/12
/// @since 0.1.0
/// @brief Provides the implementation of the HLVM -> LLVM Code Generator
//===----------------------------------------------------------------------===//
#include <hlvm/CodeGen/LLVMGenerator.h>
#include <hlvm/AST/AST.h>
#include <hlvm/AST/Bundle.h>
#include <hlvm/AST/Documentation.h>
#include <hlvm/AST/ContainerType.h>
#include <hlvm/AST/Linkables.h>
#include <hlvm/AST/ControlFlow.h>
#include <hlvm/AST/MemoryOps.h>
#include <hlvm/AST/InputOutput.h>
#include <hlvm/AST/Arithmetic.h>
#include <hlvm/AST/RealMath.h>
#include <hlvm/AST/BooleanOps.h>
#include <hlvm/AST/Constants.h>
#include <hlvm/Base/Assert.h>
#include <hlvm/Pass/Pass.h>
#include <hlvm/CodeGen/LLVMEmitter.h>
#include <llvm/Linker.h>
#include <llvm/PassManager.h>
#include <llvm/Analysis/LoadValueNumbering.h>
#include <llvm/Analysis/LoopPass.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Assembly/Parser.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Analysis/Dominators.h>
#include <llvm/Assembly/PrintModulePass.h>
#include <llvm/Support/CommandLine.h>
namespace llvm {
void dump(llvm::Value* V) {
V->dump();
}
void dumpType(llvm::Type* T) {
T->dump();
}
}
namespace
{
using namespace hlvm;
class LLVMGeneratorPass : public hlvm::Pass
{
LLVMEmitter* em;
typedef std::map<const hlvm::Operator*,llvm::Value*> OperandMap;
typedef std::map<const hlvm::Block*,llvm::BasicBlock*> BlockMap;
typedef std::map<const hlvm::Operator*,llvm::BasicBlock*> LoopMap;
typedef std::map<const hlvm::Block*,llvm::Instruction*> ResultsMap;
typedef std::map<const hlvm::Variable*,llvm::Value*> VariableMap;
typedef std::map<const hlvm::AutoVarOp*,llvm::Value*> AutoVarMap;
typedef std::map<const hlvm::Constant*,llvm::Constant*> ConstantMap;
typedef std::map<const hlvm::Function*,llvm::Function*> FunctionMap;
ModuleList modules; ///< The list of modules we construct
OperandMap operands; ///< The current list of instruction operands
BlockMap enters; ///< Map of Block to entry BasicBlock
BlockMap exits; ///< Map of Block to exit BasicBlock
BlockStack blocks; ///< The stack of blocks we're constructing
BranchList breaks; ///< The list of break instructions to fix up
BranchList continues; ///< The list of continue instructions to fix up
VariableMap gvars; ///< Map of HLVM -> LLVM gvars
AutoVarMap lvars; ///< Map of HLVM -> LLVM auto vars
llvm::TypeSymbolTable ltypes; ///< The cached LLVM types we've generated
ConstantMap consts; ///< The cached LLVM constants we've generated
FunctionMap funcs; ///< The cached LLVM constants we've generated
const AST* ast; ///< The current Tree we're traversing
const Bundle* bundle; ///< The current Bundle we're traversing
const hlvm::Function* function; ///< The current Function we're traversing
const Block* block; ///< The current Block we're traversing
std::vector<llvm::Function*> progs; ///< The list of programs to emit
public:
LLVMGeneratorPass(const AST* tree)
: Pass(0,Pass::PreAndPostOrderTraversal), em(),
modules(), operands(), blocks(), breaks(),
continues(),
gvars(), lvars(), ltypes(), consts(), funcs(),
ast(tree), bundle(0), function(0), block(0)
{
em = new_LLVMEmitter();
}
~LLVMGeneratorPass() { }
/// Conversion functions
const llvm::Type* getType(const hlvm::Type* ty);
inline const llvm::Type* getFirstClassType(const hlvm::Type* ty);
llvm::Constant* getConstant(const hlvm::Constant* C);
llvm::Value* getVariable(const hlvm::Variable* V);
llvm::Function* getFunction(const hlvm::Function* F);
llvm::Argument* getArgument(const hlvm::Argument* arg);
inline llvm::GlobalValue::LinkageTypes getLinkageTypes(LinkageKinds lk);
inline std::string getLinkageName(const Linkable* li);
inline llvm::Value* getReferent(hlvm::GetOp* r);
inline llvm::Value* toBoolean(llvm::Value* op);
inline llvm::Value* ptr2Value(llvm::Value* op);
inline llvm::Value* coerce(llvm::Value* op);
inline void pushOperand(llvm::Value* v, const Operator* op);
inline llvm::Value* popOperand(const Operator*op);
inline llvm::Value* popOperandAsBlock(
const Operator* op, const std::string&,
llvm::BasicBlock*& entry_block, llvm::BasicBlock*& exit_block);
inline llvm::Value* popOperandAsCondition(
const Operator* op, const std::string&,
llvm::BasicBlock*& entry_block, llvm::BasicBlock*& exit_block);
inline llvm::BasicBlock* newBlock(const std::string& name);
inline llvm::BasicBlock* pushBlock(const std::string& name);
inline llvm::BasicBlock* popBlock(llvm::BasicBlock* curBlock);
inline bool hasResult(hlvm::Block* B) const;
llvm::AllocaInst* getOperatorResult(Operator* op, const std::string& name);
llvm::Value* getBlockResult(Block* blk);
inline void branchIfNotTerminated(
llvm::BasicBlock* to, llvm::BasicBlock* from);
inline void startNewFunction(llvm::Function* f);
/// Generator
template <class NodeClass>
inline void gen(NodeClass *nc);
void genProgramLinkage();
virtual void handleInitialize(AST* tree);
virtual void handle(Node* n,Pass::TraversalKinds mode);
virtual void handleTerminate();
inline llvm::Module* linkModules();
};
std::string
LLVMGeneratorPass::getLinkageName(const Linkable* lk)
{
// if (lk->isProgram())
// return std::string("_hlvm_entry_") + lk->getName();
// FIXME: This needs to incorporate the bundle name
return lk->getName();
}
const llvm::Type*
LLVMGeneratorPass::getType(const hlvm::Type* ty)
{
// First, lets see if its cached already
const llvm::Type* result = ltypes.lookup(ty->getName());
if (result)
return result;
// Okay, we haven't seen this type before so let's construct it
switch (ty->getID()) {
case BooleanTypeID: result = llvm::Type::Int1Ty; break;
case CharacterTypeID: result = llvm::Type::Int32Ty; break;
case AnyTypeID:
hlvmNotImplemented("Any Type");
break;
case StringTypeID:
result = llvm::PointerType::get(llvm::Type::Int8Ty);
break;
case EnumerationTypeID:
result = llvm::Type::Int32Ty;
break;
case IntegerTypeID:
{
const hlvm::IntegerType* IT = llvm::cast<hlvm::IntegerType>(ty);
uint16_t bits = IT->getBits();
if (bits <= 8)
result = (IT->isSigned() ? llvm::Type::Int8Ty : llvm::Type::Int8Ty);
else if (bits <= 16)
result = (IT->isSigned() ? llvm::Type::Int16Ty : llvm::Type::Int16Ty);
else if (bits <= 32)
result = (IT->isSigned() ? llvm::Type::Int32Ty : llvm::Type::Int32Ty);
else if (bits <= 64)
result = (IT->isSigned() ? llvm::Type::Int64Ty : llvm::Type::Int64Ty);
else if (bits <= 128)
hlvmNotImplemented("128-bit integer");
else
hlvmNotImplemented("arbitrary precision integer");
break;
}
case RangeTypeID:
{
const RangeType* RT = llvm::cast<hlvm::RangeType>(ty);
if (RT->getMin() < 0) {
if (RT->getMin() >= SHRT_MIN && RT->getMax() <= SHRT_MAX)
return llvm::Type::Int16Ty;
else if (RT->getMin() >= INT_MIN && RT->getMax() <= INT_MAX)
return llvm::Type::Int32Ty;
else
return llvm::Type::Int64Ty;
} else {
if (RT->getMax() <= USHRT_MAX)
return llvm::Type::Int16Ty;
else if (RT->getMax() <= UINT_MAX)
return llvm::Type::Int32Ty;
else
return llvm::Type::Int64Ty;
}
}
case RationalTypeID:
hlvmNotImplemented("RationalType");
break;
case RealTypeID:
{
const RealType *RT = llvm::cast<hlvm::RealType>(ty);
uint16_t bits = RT->getBits();
if (bits <= 32)
result = llvm::Type::FloatTy;
else if (bits <= 64)
result = llvm::Type::DoubleTy;
else
hlvmNotImplemented("arbitrary precision real");
break;
}
case TextTypeID:
result = em->getTextType();
break;
case StreamTypeID:
result = em->getStreamType();
break;
case BufferTypeID:
result = em->getBufferType();
break;
case PointerTypeID:
{
const hlvm::Type* hElemType =
llvm::cast<hlvm::PointerType>(ty)->getElementType();
const llvm::Type* lElemType = getType(hElemType);
result = llvm::PointerType::get(lElemType);
// If the element type is opaque then we need to add a type name for this
// pointer type because all opaques are unique unless named similarly.
if (llvm::isa<llvm::OpaqueType>(lElemType))
em->AddType(result, ty->getName());
break;
}
case VectorTypeID: {
const hlvm::VectorType* VT = llvm::cast<hlvm::VectorType>(ty);
const llvm::Type* elemType = getType(VT->getElementType());
result = llvm::ArrayType::get(elemType, VT->getSize());
break;
}
case ArrayTypeID: {
const hlvm::ArrayType* AT = llvm::cast<hlvm::ArrayType>(ty);
const llvm::Type* elemType = getType(AT->getElementType());
std::vector<const llvm::Type*> Fields;
Fields.push_back(llvm::Type::Int32Ty);
Fields.push_back(llvm::PointerType::get(elemType));
result = llvm::StructType::get(Fields);
break;
}
case StructureTypeID: {
const hlvm::StructureType* ST = llvm::cast<hlvm::StructureType>(ty);
std::vector<const llvm::Type*> Fields;
for (StructureType::const_iterator I = ST->begin(), E = ST->end();
I != E; ++I)
Fields.push_back(getType((*I)->getType()));
result = llvm::StructType::get(Fields);
break;
}
case SignatureTypeID:
{
TypeList params;
const SignatureType* st = llvm::cast<SignatureType>(ty);
// Now, push the arguments onto the argument list
for (SignatureType::const_iterator I = st->begin(), E = st->end();
I != E; ++I)
params.push_back(getType((*I)->getType()));
// Get the Result Type
const llvm::Type* resultTy = getType(st->getResultType());
result =
em->getFunctionType(st->getName(), resultTy, params, st->isVarArgs());
break;
}
case OpaqueTypeID: {
return llvm::OpaqueType::get();
break;
}
default:
hlvmDeadCode("Invalid type code");
break;
}
if (result)
ltypes.insert(ty->getName(),result);
return result;
}
const llvm::Type*
LLVMGeneratorPass::getFirstClassType(const hlvm::Type* ty)
{
const llvm::Type* Ty = getType(ty);
if (!Ty->isFirstClassType())
return llvm::PointerType::get(Ty);
return Ty;
}
llvm::Constant*
LLVMGeneratorPass::getConstant(const hlvm::Constant* C)
{
hlvmAssert(C!=0);
hlvmAssert(C->isConstantValue());
// First, lets see if its cached already
ConstantMap::iterator I =
consts.find(const_cast<hlvm::Constant*>(C));
if (I != consts.end())
return I->second;
const hlvm::Type* hType = C->getType();
const llvm::Type* lType = getType(hType);
llvm::Constant* result = 0;
switch (C->getID())
{
case ConstantBooleanID:
{
const ConstantBoolean* CI = llvm::cast<const ConstantBoolean>(C);
result = llvm::ConstantInt::get(llvm::Type::Int1Ty, CI->getValue());
break;
}
case ConstantCharacterID:
{
const ConstantCharacter* CE = llvm::cast<ConstantCharacter>(C);
const std::string& cVal = CE->getValue();
hlvmAssert(!cVal.empty() && "Empty constant character?");
uint32_t val = 0;
if (cVal[0] == '#') {
const char* startptr = &cVal.c_str()[1];
char* endptr = 0;
val = strtoul(startptr,&endptr,16);
hlvmAssert(startptr != endptr);
} else {
val = cVal[0];
}
result = em->getUVal(llvm::Type::Int32Ty,val);
break;
}
case ConstantEnumeratorID:
{
const ConstantEnumerator* CE = llvm::cast<ConstantEnumerator>(C);
const EnumerationType* eType = llvm::cast<EnumerationType>(C->getType());
uint64_t val = 0;
bool gotEnumValue = eType->getEnumValue( CE->getValue(), val );
hlvmAssert(gotEnumValue && "Enumerator not valid for type");
result = em->getUVal(lType,val);
break;
}
case ConstantIntegerID:
{
const ConstantInteger* CI = llvm::cast<const ConstantInteger>(C);
if (const hlvm::IntegerType* iType =
llvm::dyn_cast<hlvm::IntegerType>(hType)) {
if (iType->isSigned()) {
int64_t val = strtoll(CI->getValue().c_str(),0,CI->getBase());
result = em->getSVal(lType,val);
}
else {
uint64_t val = strtoull(CI->getValue().c_str(),0,CI->getBase());
result = em->getUVal(lType,val);
}
} else if (const RangeType* rType = llvm::dyn_cast<RangeType>(hType)) {
int64_t val = strtoll(CI->getValue().c_str(),0,CI->getBase());
result = em->getSVal(lType,val);
}
break;
}
case ConstantRealID:
{
const ConstantReal* CR = llvm::cast<const ConstantReal>(C);
double val = strtod(CR->getValue().c_str(),0);
result = llvm::ConstantFP::get(lType, val);
break;
}
case ConstantStringID:
{
const hlvm::ConstantString* CT = llvm::cast<hlvm::ConstantString>(C);
llvm::Constant* CA = llvm::ConstantArray::get(CT->getValue(), true);
llvm::GlobalVariable* GV = em->NewGConst(CA->getType(), CA, C->getName());
std::vector<llvm::Constant*> indices;
indices.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty));
indices.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty));
result = llvm::ConstantExpr::getGetElementPtr(GV, &indices[0], 2);
break;
}
case ConstantPointerID:
{
const hlvm::ConstantPointer* hCT = llvm::cast<hlvm::ConstantPointer>(C);
const hlvm::Constant* hC = hCT->getValue();
const llvm::Type* Ty = getType(hC->getType());
llvm::Constant* Init = getConstant(hC);
result = em->NewGConst(Ty,Init, hCT->getName());
break;
}
case ConstantArrayID:
{
const hlvm::ConstantArray* hCA = llvm::cast<hlvm::ConstantArray>(C);
const llvm::Type* elemType = getType(hCA->getElementType());
const llvm::ArrayType* lAT = llvm::ArrayType::get(elemType,hCA->size());
std::vector<llvm::Constant*> elems;
for (hlvm::ConstantArray::const_iterator I = hCA->begin(), E = hCA->end();
I != E; ++I )
elems.push_back(getConstant(*I));
llvm::Constant* lCA = llvm::ConstantArray::get(lAT,elems);
llvm::GlobalVariable* lGV = em->NewGConst(lAT,lCA,hCA->getName()+"_init");
llvm::Constant* lCE = em->getFirstElement(lGV);
const llvm::StructType* Ty =
llvm::cast<llvm::StructType>(getType(hCA->getType()));
elems.clear();
elems.push_back(em->getUVal(llvm::Type::Int32Ty,hCA->size()));
elems.push_back(lCE);
result = llvm::ConstantStruct::get(Ty,elems);
break;
}
case ConstantVectorID:
{
const hlvm::ConstantVector* hCA = llvm::cast<hlvm::ConstantVector>(C);
const llvm::ArrayType* Ty =
llvm::cast<llvm::ArrayType>(getType(hCA->getType()));
std::vector<llvm::Constant*> elems;
for (hlvm::ConstantArray::const_iterator I = hCA->begin(), E = hCA->end();
I != E; ++I )
elems.push_back(getConstant(*I));
result = llvm::ConstantArray::get(Ty,elems);
break;
}
case ConstantStructureID:
{
const ConstantStructure* hCS = llvm::cast<ConstantStructure>(C);
const llvm::StructType* Ty =
llvm::cast<llvm::StructType>(getType(hCS->getType()));
std::vector<llvm::Constant*> fields;
for (ConstantStructure::const_iterator I = hCS->begin(), E = hCS->end();
I != E; ++I)
fields.push_back(getConstant(*I));
result = llvm::ConstantStruct::get(Ty,fields);
break;
}
case ConstantContinuationID:
{
const ConstantContinuation* hCC = llvm::cast<ConstantContinuation>(C);
const llvm::StructType* Ty =
llvm::cast<llvm::StructType>(getType(hCC->getType()));
std::vector<llvm::Constant*> fields;
for (ConstantStructure::const_iterator I = hCC->begin(), E = hCC->end();
I != E; ++I)
fields.push_back(getConstant(*I));
// FIXME: Need to add extra fields required for Continuation
result = llvm::ConstantStruct::get(Ty,fields);
break;
}
default:
break;
}
if (result)
consts[const_cast<hlvm::Constant*>(C)] = result;
else
hlvmDeadCode("Didn't find constant");
return result;
}
llvm::Value*
LLVMGeneratorPass::getVariable(const hlvm::Variable* V)
{
hlvmAssert(V != 0);
hlvmAssert(V->is(VariableID));
// First, lets see if its cached already
VariableMap::iterator I =
gvars.find(const_cast<hlvm::Variable*>(V));
if (I != gvars.end())
return I->second;
// Not found, create it
llvm::Constant* Initializer = 0;
if (V->hasInitializer())
Initializer = getConstant(V->getInitializer());
else
Initializer = llvm::Constant::getNullValue(getType(V->getType()));
llvm::Value* gv = em->NewGVar(
/*Ty=*/ getType(V->getType()),
/*Linkage=*/ getLinkageTypes(V->getLinkageKind()),
/*Initializer=*/ Initializer,
/*Name=*/ getLinkageName(V)
);
gvars[V] = gv;
return gv;
}
llvm::Function*
LLVMGeneratorPass::getFunction(const hlvm::Function* F)
{
hlvmAssert(F != 0);
hlvmAssert(F->is(FunctionID));
// First, lets see if its cached already
FunctionMap::iterator I = funcs.find(const_cast<hlvm::Function*>(F));
if (I != funcs.end())
return I->second;
return funcs[F] = em->NewFunction(
/*Type=*/ llvm::cast<llvm::FunctionType>(getType(F->getType())),
/*Linkage=*/ getLinkageTypes(F->getLinkageKind()),
/*Name=*/ getLinkageName(F)
);
}
llvm::Argument*
LLVMGeneratorPass::getArgument(const hlvm::Argument* arg)
{
unsigned argNum = arg->getArgNum();
hlvmAssert(argNum != 0);
argNum--;
hlvm::Function* hF = llvm::cast<hlvm::Function>(arg->getParent());
llvm::Function* lF = getFunction(hF);
llvm::Function::ArgumentListType& arglist = lF->getArgumentList();
// Bump the argument number to accommodate the first argument being
// a pointer to the result, if the type of the result is not first-class.
if (!getType(hF->getResultType())->isFirstClassType())
argNum++;
llvm::Function::arg_iterator I = lF->arg_begin(), E = lF->arg_end();
for (; I != E && argNum; ++I, --argNum)
;
hlvmAssert(I != E);
return I;
}
llvm::GlobalValue::LinkageTypes
LLVMGeneratorPass::getLinkageTypes(LinkageKinds lk)
{
switch (lk) {
case hlvm::ExternalLinkage : return llvm::GlobalValue::ExternalLinkage;
case hlvm::LinkOnceLinkage : return llvm::GlobalValue::LinkOnceLinkage;
case hlvm::WeakLinkage : return llvm::GlobalValue::WeakLinkage;
case hlvm::AppendingLinkage: return llvm::GlobalValue::AppendingLinkage;
case hlvm::InternalLinkage : return llvm::GlobalValue::InternalLinkage;
default:
hlvmAssert(!lk && "Bad LinkageKinds");
}
return llvm::GlobalValue::InternalLinkage;
}
llvm::Value*
LLVMGeneratorPass::getReferent(hlvm::GetOp* r)
{
const hlvm::Value* referent = r->getReferent();
llvm::Value* v = 0;
if (llvm::isa<AutoVarOp>(referent)) {
AutoVarMap::const_iterator I =
lvars.find(llvm::cast<AutoVarOp>(referent));
hlvmAssert(I != lvars.end());
v = I->second;
} else if (llvm::isa<ConstantValue>(referent)) {
const hlvm::ConstantValue* cval = llvm::cast<ConstantValue>(referent);
llvm::Constant* C = getConstant(cval);
hlvmAssert(C && "Can't generate constant?");
v = C;
} else if (llvm::isa<Variable>(referent)) {
llvm::Value* V = getVariable(llvm::cast<hlvm::Variable>(referent));
hlvmAssert(V && "Variable not found?");
v = V;
} else if (llvm::isa<hlvm::Function>(referent)) {
llvm::Function* F = getFunction(llvm::cast<hlvm::Function>(referent));
hlvmAssert(F && "Function not found?");
v = F;
} else if (llvm::isa<hlvm::Argument>(referent)) {
llvm::Argument* arg = getArgument(llvm::cast<hlvm::Argument>(referent));
hlvmAssert(arg && "Argument not found?");
v = arg;
} else
hlvmDeadCode("Referent not a linkable or autovar?");
return v;
}
llvm::Value*
LLVMGeneratorPass::toBoolean(llvm::Value* V)
{
const llvm::Type* Ty = V->getType();
if (Ty == llvm::Type::Int1Ty)
return V;
if (Ty->isInteger() || Ty->isFloatingPoint()) {
llvm::Constant* C = llvm::Constant::getNullValue(V->getType());
return em->emitNE(V,C);
} else if (llvm::isa<llvm::GlobalValue>(V)) {
// GlobalValues always have non-zero constant address values, so always true
return em->getTrue();
}
hlvmAssert(!"Don't know how to convert V into bool");
return em->getTrue();
}
llvm::Value*
LLVMGeneratorPass::ptr2Value(llvm::Value* V)
{
if (!llvm::isa<llvm::PointerType>(V->getType()))
return V;
return em->emitLoad(V,"ptr2Value");
}
void
LLVMGeneratorPass::pushOperand(llvm::Value* v, const Operator* op)
{
hlvmAssert(v && "No value to push for operand?");
hlvmAssert(op && "No operator for value to be pushed?");
operands[op] = v;
}
llvm::Value*
LLVMGeneratorPass::popOperand(const Operator* op)
{
hlvmAssert(op && "No operator to pop?");
OperandMap::iterator I = operands.find(op);
if (I == operands.end())
return 0;
llvm::Value* result = I->second;
operands.erase(I);
return result;
}
llvm::Value*
LLVMGeneratorPass::popOperandAsBlock(
const Operator* op, const std::string& name,
llvm::BasicBlock*& entry_block, llvm::BasicBlock*& exit_block)
{
llvm::Value* result = 0;
llvm::Value* operand = popOperand(op);
if (const hlvm::Block* B = llvm::dyn_cast<hlvm::Block>(op)) {
// Get the corresponding entry and exit blocks for B1
entry_block = enters[B];
hlvmAssert(entry_block && "No entry block?");
exit_block = exits[B];
hlvmAssert(exit_block && "No exit block?");
// Set the name of the entry block to match its purpose here
if (entry_block != exit_block) {
entry_block->setName(name + "_entry");
exit_block->setName(name + "_exit");
} else {
entry_block->setName(name);
}
result = operand;
} else {
hlvmAssert(operand && "No operand for operator?");
entry_block = exit_block = new llvm::BasicBlock(name,em->getFunction());
llvm::Value* V = operand;
hlvmAssert(V && "No value for operand?");
if (llvm::Instruction* ins = llvm::dyn_cast<llvm::Instruction>(V)) {
ins->removeFromParent();
entry_block->getInstList().push_back(ins);
result = ins;
} else {
// Its just a value or a constant or something, just cast it to itself
// so we can get its value
result =
new llvm::BitCastInst(V, V->getType(), "", entry_block);
}
}
if (result && result->getType() != llvm::Type::VoidTy)
result->setName(name + "_rslt");
return result;
}
llvm::Value*
LLVMGeneratorPass::popOperandAsCondition(
const Operator* op, const std::string& name,
llvm::BasicBlock*& entry_block, llvm::BasicBlock*& exit_block)
{
llvm::Value* result =
popOperandAsBlock(op,name+"_cond",entry_block,exit_block);
hlvmAssert(result);
hlvmAssert(result->getType() == llvm::Type::Int1Ty);
return result;
}
llvm::AllocaInst*
LLVMGeneratorPass::getOperatorResult(Operator* op, const std::string& name)
{
llvm::AllocaInst* result = 0;
if (!llvm::isa<Block>(op->getParent())) {
const llvm::Type* Ty = getType(op->getType());
result = em->NewAutoVar(Ty, name + "_var");
em->emitAssign(result,em->getNullValue(Ty));
}
return result;
}
llvm::Value*
LLVMGeneratorPass::getBlockResult(Block* B)
{
if (B->getResult() && !em->getBlockTerminator()) {
llvm::Value* result = operands[B];
if (llvm::isa<llvm::LoadInst>(result))
result = llvm::cast<llvm::LoadInst>(result)->getOperand(0);
result = em->emitLoad(result,em->getBlockName()+"_result");
pushOperand(result,B);
return result;
}
return 0;
}
void
LLVMGeneratorPass::branchIfNotTerminated(
llvm::BasicBlock* to, llvm::BasicBlock* from )
{
if (!from->getTerminator())
new llvm::BranchInst(to,from);
}
void
LLVMGeneratorPass::startNewFunction(llvm::Function* F)
{
em->StartFunction(F);
// Clear the function related variables
operands.clear();
enters.clear();
exits.clear();
blocks.clear();
lvars.clear();
}
template<> void
LLVMGeneratorPass::gen(AutoVarOp* av)
{
// Emit an automatic variable. Note that this is inserted into the entry
// block, not the current block, for efficiency. This makes automatic
// variables zero cost as well as safeguarding against stack growth if the
// alloca is in a block that is in a loop.
const llvm::Type* elemType = getType(av->getType());
llvm::Value* alloca = em->NewAutoVar(elemType,av->getName());
llvm::Value* init = 0;
if (av->hasInitializer())
init = popOperand(av->getInitializer());
else
init = em->getNullValue(elemType);
em->emitAssign(alloca,init);
pushOperand(alloca,av);
lvars[av] = alloca;
}
template<> void
LLVMGeneratorPass::gen(NegateOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
hlvmAssert((operand->getType()->isInteger() ||
operand->getType()->isFloatingPoint()) &&
"Can't negate non-numeric");
pushOperand(em->emitNeg(operand),op);
}
template<> void
LLVMGeneratorPass::gen(ComplementOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
operand = ptr2Value(operand);
const llvm::Type* lType = operand->getType();
hlvmAssert(lType->isInteger() && "Can't complement non-integral type");
pushOperand(em->emitCmpl(operand),op);
}
template<> void
LLVMGeneratorPass::gen(PreIncrOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
const llvm::Type* lType = operand->getType();
hlvmAssert(llvm::isa<llvm::PointerType>(lType));
const llvm::PointerType* PT = llvm::cast<llvm::PointerType>(lType);
lType = PT->getElementType();
llvm::LoadInst* load = em->emitLoad(operand,"preincr");
if (lType->isFloatingPoint()) {
llvm::Constant* one = em->getFPOne(lType);
llvm::BinaryOperator* add = em->emitAdd(load,one);
pushOperand(em->emitStore(add,operand),op);
} else if (lType->isInteger()) {
llvm::Constant* one = em->getOne(lType);
llvm::BinaryOperator* add = em->emitAdd(load,one);
pushOperand(em->emitStore(add,operand),op);
} else {
hlvmAssert(!"PreIncrOp on non-numeric");
}
}
template<> void
LLVMGeneratorPass::gen(PreDecrOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
const llvm::Type* lType = operand->getType();
hlvmAssert(llvm::isa<llvm::PointerType>(lType));
const llvm::PointerType* PT = llvm::cast<llvm::PointerType>(lType);
lType = PT->getElementType();
llvm::LoadInst* load = em->emitLoad(operand,"predecr");
if (lType->isFloatingPoint()) {
llvm::Constant* one = em->getFPOne(lType);
llvm::BinaryOperator* sub = em->emitSub(load,one);
pushOperand(em->emitStore(sub,operand),op);
} else if (lType->isInteger()) {
llvm::Constant* one = em->getOne(lType);
llvm::BinaryOperator* sub = em->emitSub(load, one);
pushOperand(em->emitStore(sub,operand),op);
} else {
hlvmAssert(!"PreIncrOp on non-numeric");
}
}
template<> void
LLVMGeneratorPass::gen(PostIncrOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
const llvm::Type* lType = operand->getType();
hlvmAssert(llvm::isa<llvm::PointerType>(lType));
const llvm::PointerType* PT = llvm::cast<llvm::PointerType>(lType);
lType = PT->getElementType();
llvm::LoadInst* load = em->emitLoad(operand,"postincr");
if (lType->isFloatingPoint()) {
llvm::Constant* one = em->getFPOne(lType);
llvm::BinaryOperator* add = em->emitAdd(load,one);
em->emitStore(add,operand);
pushOperand(load,op);
} else if (lType->isInteger()) {
llvm::Constant* one = em->getOne(lType);
llvm::BinaryOperator* add = em->emitAdd(load,one);
em->emitStore(add,operand);
pushOperand(load,op);
} else {
hlvmAssert(!"PostDecrOp on non-numeric");
}
}
template<> void
LLVMGeneratorPass::gen(PostDecrOp* op)
{
llvm::Value* operand = popOperand(op->getOperand(0));
const llvm::Type* lType = operand->getType();
hlvmAssert(llvm::isa<llvm::PointerType>(lType));
const llvm::PointerType* PT = llvm::cast<llvm::PointerType>(lType);
lType = PT->getElementType();
llvm::LoadInst* load = em->emitLoad(operand,"postdecr");
if (lType->isFloatingPoint()) {
llvm::Constant* one = em->getFPOne(lType);
llvm::BinaryOperator* sub = em->emitSub(load, one);
em->emitStore(sub,operand);
pushOperand(load,op);
} else if (lType->isInteger()) {
llvm::Constant* one = em->getOne(lType);
llvm::BinaryOperator* sub = em->emitSub(load, one);
em->emitStore(sub,operand);
pushOperand(load,op);
} else {
hlvmAssert(!"PostDecrOp on non-numeric");
}
}
template<> void
LLVMGeneratorPass::gen(SizeOfOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitSizeOf(op1),op);
}
template<> void
LLVMGeneratorPass::gen(ConvertOp* op)
{
// Get the value to be converted
hlvm::Operator* op1 = op->getOperand(0);
// Get the type of the value to be converted
const hlvm::Type* srcTy = op1->getType();
// Get the llvm Value for the value to be converted
llvm::Value* v1 = popOperand(op1);
// Get the target type
const hlvm::Type* tgtTy = op->getType();
// Get the source and target types as an llvm type
const llvm::Type* lsrcTy = getType(srcTy);
const llvm::Type* ltgtTy = getType(tgtTy);
// First, deal with the easy case of conversion of first class types. This
// can just be done with the LLVM cast operator
if (lsrcTy->isFirstClassType() && ltgtTy->isFirstClassType()) {
pushOperand(em->CastToType(v1, srcTy->isSigned(), ltgtTy, tgtTy->isSigned(),
v1->getName() + "_converted"),op);
return;
}
// Okay, this isn't going to be pretty. HLVM gaurantees that an object of
// any type is coercible to any other type. The following code makes this
// happen.
switch (srcTy->getID())
{
default: // FIXME!!
hlvmNotImplemented("Conversion of non-first-class types");
}
}
template<> void
LLVMGeneratorPass::gen(AddOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitAdd(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(SubtractOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitSub(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(MultiplyOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitMul(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(DivideOp* op)
{
bool isSigned =
op->getOperand(0)->getType()->isSigned() ||
op->getOperand(1)->getType()->isSigned();
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
if (isSigned)
pushOperand(em->emitSDiv(op1,op2),op);
else
pushOperand(em->emitUDiv(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(ModuloOp* op)
{
bool isSigned =
op->getOperand(0)->getType()->isSigned() ||
op->getOperand(1)->getType()->isSigned();
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
if (isSigned)
pushOperand(em->emitSRem(op1,op2),op);
else
pushOperand(em->emitURem(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(BAndOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitBAnd(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(BOrOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitBOr(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(BXorOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitBXor(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(BNorOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitBNor(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(NotOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
pushOperand(em->emitNot(op1),op);
}
template<> void
LLVMGeneratorPass::gen(AndOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitAnd(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(OrOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitOr(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(NorOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitNor(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(XorOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitXor(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(EqualityOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitEQ(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(InequalityOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitNE(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(LessThanOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitLT(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(GreaterThanOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitLT(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(GreaterEqualOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitGE(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(LessEqualOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
op1 = ptr2Value(op1);
op2 = ptr2Value(op2);
pushOperand(em->emitLE(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(IsPInfOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitIsPInf(op1),op);
}
template<> void
LLVMGeneratorPass::gen(IsNInfOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitIsNInf(op1),op);
}
template<> void
LLVMGeneratorPass::gen(IsNanOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitIsNan(op1),op);
}
template<> void
LLVMGeneratorPass::gen(TruncOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitTrunc(op1),op);
}
template<> void
LLVMGeneratorPass::gen(RoundOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitRound(op1),op);
}
template<> void
LLVMGeneratorPass::gen(FloorOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitFloor(op1),op);
}
template<> void
LLVMGeneratorPass::gen(CeilingOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitCeiling(op1),op);
}
template<> void
LLVMGeneratorPass::gen(LogEOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitLogE(op1),op);
}
template<> void
LLVMGeneratorPass::gen(Log2Op* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitLog2(op1),op);
}
template<> void
LLVMGeneratorPass::gen(Log10Op* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitLog10(op1),op);
}
template<> void
LLVMGeneratorPass::gen(SquareRootOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitSquareRoot(op1),op);
}
template<> void
LLVMGeneratorPass::gen(CubeRootOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitCubeRoot(op1),op);
}
template<> void
LLVMGeneratorPass::gen(FactorialOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
pushOperand(em->emitFactorial(op1),op);
}
template<> void
LLVMGeneratorPass::gen(PowerOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
pushOperand(em->emitPower(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(RootOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
pushOperand(em->emitRoot(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(GCDOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
pushOperand(em->emitGCD(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(LCMOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
pushOperand(em->emitLCM(op1,op2),op);
}
template<> void
LLVMGeneratorPass::gen(SelectOp* op)
{
// If none of the operands are blocks then we can use LLVM's select
// instruction to just switch out the result
if (!llvm::isa<Block>(op->getOperand(0)) &&
!llvm::isa<Block>(op->getOperand(1)) &&
!llvm::isa<Block>(op->getOperand(2)))
{
// Since HLVM only places on the operand stack things that are of LLVM
// first class type, we are safe to use select operator here.
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
llvm::Value* op3 = popOperand(op->getOperand(2));
hlvmAssert(op1->getType() == llvm::Type::Int1Ty);
hlvmAssert(op2->getType()->isFirstClassType());
hlvmAssert(op3->getType()->isFirstClassType());
pushOperand(em->emitSelect(op1,op2,op3,"select"),op);
return;
}
// Using the LLVM SelectInst won't work. We must get each operand as a block
// and use a branch instruction instead.
// Get the result of the select operator
llvm::AllocaInst* select_result = getOperatorResult(op,"select_result");
// Get the condition block
llvm::BasicBlock* cond_entry, *cond_exit;
llvm::Value* op1 =
popOperandAsCondition(op->getOperand(0),"select",cond_entry,cond_exit);
// Branch the current block into the condition block
em->emitBranch(cond_entry);
// Get the true case
llvm::BasicBlock *true_entry, *true_exit;
llvm::Value* op2 =
popOperandAsBlock(op->getOperand(1),"select_true",true_entry,true_exit);
if (select_result && op2)
new llvm::StoreInst(op2,select_result,true_exit);
// Get the false case
llvm::BasicBlock *false_entry, *false_exit;
llvm::Value* op3 =
popOperandAsBlock(op->getOperand(2),"select_false",false_entry,false_exit);
if (select_result && op3)
new llvm::StoreInst(op3,select_result,false_exit);
// Create the exit block
llvm::BasicBlock* select_exit = em->newBlock("select_exit");
// Branch the the true and false cases to the exit
branchIfNotTerminated(select_exit,true_exit);
branchIfNotTerminated(select_exit,false_exit);
// Finally, install the conditional branch
new llvm::BranchInst(true_entry,false_entry,op1,cond_exit);
if (select_result)
pushOperand(new llvm::LoadInst(select_result,"select_result",select_exit),op);
}
template<> void
LLVMGeneratorPass::gen(SwitchOp* op)
{
llvm::Value* op1 = popOperand(op->getOperand(0));
llvm::Value* op2 = popOperand(op->getOperand(1));
}
template<> void
LLVMGeneratorPass::gen(WhileOp* op)
{
// Get the result of this while block, if there should be one
llvm::AllocaInst* while_result = getOperatorResult(op,"while_result");
// Get the condition block
llvm::BasicBlock* cond_entry, *cond_exit;
llvm::Value* op1 =
popOperandAsCondition(op->getOperand(0),"while",cond_entry,cond_exit);
// Branch the current block into the condition block
em->emitBranch(cond_entry);
// Get the while loop's body
llvm::BasicBlock *body_entry, *body_exit;
llvm::Value* op2 =
popOperandAsBlock(op->getOperand(1),"while_body",body_entry,body_exit);
// Save the result of the while body, if there should be one
if (while_result && op2)
new llvm::StoreInst(op2,while_result,body_exit);
// Create the exit block
llvm::BasicBlock* while_exit = em->newBlock("while_exit");
// Branch the the body block back to the condition branch
branchIfNotTerminated(cond_entry,body_exit);
// Finally, install the conditional branch into the branch block
new llvm::BranchInst(body_entry,while_exit,op1,cond_exit);
// If there's a result, push it now
if (while_result)
pushOperand(new llvm::LoadInst(while_result,"while_result",while_exit),op);
// Fix up any break or continue operators
em->ResolveBreaks(while_exit);
em->ResolveContinues(cond_entry);
}
template<> void
LLVMGeneratorPass::gen(UnlessOp* op)
{
// Get the result of this unless block, if there should be one
llvm::AllocaInst* unless_result = getOperatorResult(op,"unless_result");
// Get the condition block
llvm::BasicBlock* cond_entry, *cond_exit;
llvm::Value* op1 =
popOperandAsCondition(op->getOperand(0),"unless",cond_entry,cond_exit);
// Branch the current block into the condition block
em->emitBranch(cond_entry);
// Get the unless block's body
llvm::BasicBlock *body_entry, *body_exit;
llvm::Value* op2 =
popOperandAsBlock(op->getOperand(1),"unless_body",body_entry,body_exit);
// Save the result of the unless body, if there should be one
if (unless_result && op2)
new llvm::StoreInst(op2,unless_result,body_exit);
// Create the exit block
llvm::BasicBlock* unless_exit = em->newBlock("unless_exit");
// Branch the the body block back to the condition branch
branchIfNotTerminated(cond_entry,body_exit);
// Finally, install the conditional branch into the branch block
new llvm::BranchInst(unless_exit,body_entry,op1,cond_exit);
// If there's a result, push it now
if (unless_result)
pushOperand(
new llvm::LoadInst(unless_result,"unless_result",unless_exit),op);
// Fix up any break or continue operators
em->ResolveBreaks(unless_exit);
em->ResolveContinues(cond_entry);
}
template<> void
LLVMGeneratorPass::gen(UntilOp* op)
{
// Get the result of this until block, if there should be one
llvm::AllocaInst* until_result = getOperatorResult(op,"until_result");
// Get the condition block
llvm::BasicBlock* cond_entry, *cond_exit;
llvm::Value* op2 =
popOperandAsCondition(op->getOperand(1),"until",cond_entry,cond_exit);
// Get the until block's body
llvm::BasicBlock *body_entry, *body_exit;
llvm::Value* op1 =
popOperandAsBlock(op->getOperand(0),"until_body",body_entry,body_exit);
// Save the result of the until body, if there should be one
if (until_result && op1)
new llvm::StoreInst(op1,until_result,body_exit);
// Branch the current block into the body block
em->emitBranch(body_entry);
// Branch the body block to the condition block
branchIfNotTerminated(cond_entry,body_exit);
// Create the exit block
llvm::BasicBlock* until_exit = em->newBlock("until_exit");
// Finally, install the conditional branch into condition block
new llvm::BranchInst(until_exit,body_entry,op2,cond_exit);
// If there's a result, push it now
if (until_result)
pushOperand(new llvm::LoadInst(until_result,"until_result",until_exit),op);
// Fix up any break or continue operators
em->ResolveBreaks(until_exit);
em->ResolveContinues(cond_entry);
}
template<> void
LLVMGeneratorPass::gen(LoopOp* op)
{
// Get the result of this loop block, if there should be one
llvm::AllocaInst* loop_result = getOperatorResult(op,"loop_result");
// Get the start condition block
llvm::BasicBlock* start_cond_entry, *start_cond_exit;
llvm::Value* op1 =
popOperandAsCondition(op->getOperand(0),"loop_start",
start_cond_entry,start_cond_exit);
// Branch the current block into the start condition block
em->emitBranch(start_cond_entry);
// Get the loop body
llvm::BasicBlock *body_entry, *body_exit;
llvm::Value* op2 =
popOperandAsBlock(op->getOperand(1),"loop_body",body_entry,body_exit);
// Save the result of the loop body, if there should be one
if (loop_result && op2)
new llvm::StoreInst(op2,loop_result,body_exit);
// Get the end condition block
llvm::BasicBlock* end_cond_entry, *end_cond_exit;
llvm::Value* op3 =
popOperandAsCondition(op->getOperand(2),"loop_end",
end_cond_entry,end_cond_exit);
// Branch the loop body to the end condition block
branchIfNotTerminated(end_cond_entry,body_exit);
// Create the exit block
llvm::BasicBlock* loop_exit = em->newBlock("loop_exit");
// Install the conditional branches for start and end condition blocks
new llvm::BranchInst(body_entry,loop_exit,op1,start_cond_exit);
new llvm::BranchInst(start_cond_entry,loop_exit,op3,end_cond_exit);
// If there's a result, push it now
if (loop_result)
pushOperand(new llvm::LoadInst(loop_result,"loop_result",loop_exit),op);
// Fix up any break or continue operators
em->ResolveBreaks(loop_exit);
em->ResolveContinues(end_cond_entry);
}
template<> void
LLVMGeneratorPass::gen(BreakOp* op)
{
// Make sure the block result is stored
Block* B = llvm::cast<Block>(op->getContainingBlock());
getBlockResult(B);
// Just push a place-holder branch onto the breaks list so it can
// be fixed up later once we know the destination
llvm::BranchInst* brnch = em->emitBreak();
pushOperand(brnch,op);
}
template<> void
LLVMGeneratorPass::gen(ContinueOp* op)
{
// Make sure the block result is stored
Block* B = llvm::cast<Block>(op->getParent());
getBlockResult(B);
// Just push a place-holder branch onto the continues list so it can
// be fixed up later once we know the destination
llvm::BranchInst* brnch = em->emitContinue();
pushOperand(brnch,op);
}
template<> void
LLVMGeneratorPass::gen(ResultOp* r)
{
// Get the result operand
llvm::Value* src = popOperand(r->getOperand(0));
if (llvm::isa<llvm::AllocaInst>(src))
src = em->emitLoad(src,src->getName() + "_load");
// Get the block this result applies to
hlvm::Block* B = llvm::cast<hlvm::Block>(r->getParent());
// Get the location into which we will store the result
llvm::Value* dest = operands[B];
// Assign the source to the destination
em->emitAssign(dest, src);
}
template<> void
LLVMGeneratorPass::gen(ReturnOp* r)
{
// First, if this function returns nothing (void) then just issue a void
// return instruction.
const hlvm::Type* resTy = function->getResultType();
if (resTy == 0) {
em->emitReturn(0);
return;
}
// If we get here then the function has a result.
llvm::Value* result = operands[function->getBlock()];
em->emitReturn(result);
}
template<> void
LLVMGeneratorPass::gen(CallOp* co)
{
hlvm::Function* hFunc = co->getCalledFunction();
const SignatureType* sigTy = hFunc->getSignature();
// Set up the loop
CallOp::iterator I = co->begin();
CallOp::iterator E = co->end();
// Get the function (first operand)
llvm::Value* funcToCall = popOperand(*I++);
hlvmAssert(funcToCall && "No function to call?");
hlvmAssert(llvm::isa<llvm::Function>(funcToCall));
// Get the function call arguments
std::vector<llvm::Value*> args;
for ( ; I != E; ++I ) {
llvm::Value* arg = popOperand(*I);
hlvmAssert(arg && "No argument for CallOp?");
args.push_back(arg);
}
// Make sure we have sanity with varargs functions
hlvmAssert(sigTy->isVarArgs() || args.size() == sigTy->size());
hlvmAssert(!sigTy->isVarArgs() || args.size() >= sigTy->size());
// convert to function type
llvm::Function* F = const_cast<llvm::Function*>(
llvm::cast<llvm::Function>(funcToCall));
// Make the call
pushOperand(em->emitCall(F,args),co);
}
template<> void
LLVMGeneratorPass::gen(StoreOp* s)
{
llvm::Value* location = popOperand(s->getOperand(0));
llvm::Value* value = popOperand(s->getOperand(1));
// We don't push the StoreInst as an operand because it has no value and
// therefore cannot be an operand.
em->emitAssign(location,value);
}
template<> void
LLVMGeneratorPass::gen(LoadOp* l)
{
llvm::Value* location = popOperand(l->getOperand(0));
const llvm::PointerType* PT =
llvm::dyn_cast<llvm::PointerType>(location->getType());
hlvmAssert(PT && "Attempt to load non-pointer?");
const llvm::Type* ET = PT->getElementType();
if (!ET->isFirstClassType())
pushOperand(location,l);
else
pushOperand(em->emitLoad(location,location->getName()),l);
}
template<> void
LLVMGeneratorPass::gen(GetOp* r)
{
llvm::Value* referent = getReferent(r);
pushOperand(referent,r);
}
template<> void
LLVMGeneratorPass::gen(GetFieldOp* i)
{
hlvm::Operator* loc = i->getOperand(0);
hlvm::Operator* field = i->getOperand(1);
if (hlvm::GetOp* Ref = llvm::dyn_cast<GetOp>(field))
if (const hlvm::Value* referent = Ref->getReferent())
if (const hlvm::ConstantString* CS =
llvm::dyn_cast<ConstantString>(referent)) {
const std::string& fldName = CS->getValue();
const DisparateContainerType* DCT =
llvm::cast<DisparateContainerType>(loc->getType());
unsigned index = DCT->getFieldIndex(fldName);
hlvmAssert(index != 0 && "Invalid field name");
llvm::Constant* idx = llvm::ConstantInt::get(llvm::Type::Int32Ty,index);
llvm::Value* location = popOperand(loc);
pushOperand(em->emitGEP(location,idx),i);
return;
}
// The operand is not a constant string. We must look the field up at runtime
hlvmNotImplemented("Lookup of field at runtime");
llvm::Value* location = popOperand(loc);
llvm::Value* fld = popOperand(field);
}
template<> void
LLVMGeneratorPass::gen(GetIndexOp* i)
{
llvm::Value* location = popOperand(i->getOperand(0));
llvm::Value* index = popOperand(i->getOperand(1));
pushOperand(em->emitGEP(location,index),i);
}
template<> void
LLVMGeneratorPass::gen(OpenOp* o)
{
llvm::Value* strm = popOperand(o->getOperand(0));
pushOperand(em->emitOpen(strm),o);
}
template<> void
LLVMGeneratorPass::gen(WriteOp* o)
{
llvm::Value* strm = popOperand(o->getOperand(0));
llvm::Value* arg2 = popOperand(o->getOperand(1));
pushOperand(em->emitWrite(strm,arg2),o);
}
template<> void
LLVMGeneratorPass::gen(ReadOp* o)
{
llvm::Value* strm = popOperand(o->getOperand(0));
llvm::Value* arg2 = popOperand(o->getOperand(1));
llvm::Value* arg3 = popOperand(o->getOperand(2));
pushOperand(em->emitRead(strm,arg2,arg3),o);
}
template<> void
LLVMGeneratorPass::gen(CloseOp* o)
{
llvm::Value* strm = popOperand(o->getOperand(0));
pushOperand(em->emitClose(strm),o);
}
void
LLVMGeneratorPass::genProgramLinkage()
{
// Short circuit if there's nothing to do
if (progs.empty())
return;
// Define the type of the array elements (a structure with a pointer to
// a string and a pointer to the function).
std::vector<const llvm::Type*> Fields;
Fields.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
Fields.push_back(llvm::PointerType::get(em->getProgramType()));
llvm::StructType* entry_elem_type = llvm::StructType::get(Fields);
// Define the type of the array for the entry points
llvm::ArrayType* entry_points_type =
llvm::ArrayType::get(entry_elem_type,progs.size());
// Create a vector to hold the entry elements as they are created.
std::vector<llvm::Constant*> entry_points_items;
for (std::vector<llvm::Function*>::iterator I = progs.begin(),
E = progs.end(); I != E; ++I )
{
const std::string& funcName = (*I)->getName();
// Get a constant for the name of the entry point (char array)
llvm::Constant* name_val = llvm::ConstantArray::get(funcName,true);
// Create a constant global variable to hold the name of the program.
llvm::GlobalVariable* name = em->NewGConst(
/*Type=*/name_val->getType(),
/*Initializer=*/name_val,
/*name=*/"prog_name"
);
llvm::Constant* index = em->getFirstElement(name);
// Get a constant structure for the entry containing the name and pointer
// to the function.
std::vector<llvm::Constant*> items;
items.push_back(index);
items.push_back(*I);
llvm::Constant* entry = llvm::ConstantStruct::get(entry_elem_type,items);
// Save the entry into the list of entry point items
entry_points_items.push_back(entry);
}
// Create a constant array to initialize the entry_points
llvm::Constant* entry_points_initializer = llvm::ConstantArray::get(
entry_points_type,entry_points_items);
// Now get the GlobalVariable
llvm::GlobalVariable* entry_points = new llvm::GlobalVariable(
/*Type=*/entry_points_type,
/*isConstant=*/true,
/*Linkage=*/llvm::GlobalValue::AppendingLinkage,
/*Initializer=*/entry_points_initializer,
/*Name=*/"hlvm_programs",
/*Parent=*/em->getModule()
);
}
void
LLVMGeneratorPass::handleInitialize(AST* tree)
{
// Nothing to do
}
void
LLVMGeneratorPass::handle(Node* n,Pass::TraversalKinds mode)
{
if (mode == Pass::PreOrderTraversal) {
// We process container nodes here (preorder) to ensure that we create the
// container that is being asked for.
switch (n->getID())
{
case BundleID:
{
em->StartModule(llvm::cast<Bundle>(n)->getName());
lvars.clear();
gvars.clear();
funcs.clear();
break;
}
case ConstantBooleanID:
getConstant(llvm::cast<ConstantBoolean>(n));
break;
case ConstantCharacterID:
getConstant(llvm::cast<ConstantCharacter>(n));
break;
case ConstantEnumeratorID:
getConstant(llvm::cast<ConstantEnumerator>(n));
break;
case ConstantIntegerID:
getConstant(llvm::cast<hlvm::ConstantInteger>(n));
break;
case ConstantRealID:
getConstant(llvm::cast<hlvm::ConstantReal>(n));
break;
case ConstantStringID:
getConstant(llvm::cast<hlvm::ConstantString>(n));
break;
case ConstantAnyID:
getConstant(llvm::cast<hlvm::ConstantAny>(n));
break;
case ConstantStructureID:
getConstant(llvm::cast<hlvm::ConstantStructure>(n));
break;
case ConstantArrayID:
getConstant(llvm::cast<hlvm::ConstantArray>(n));
break;
case ConstantVectorID:
getConstant(llvm::cast<hlvm::ConstantVector>(n));
break;
case ConstantContinuationID:
getConstant(llvm::cast<hlvm::ConstantContinuation>(n));
break;
case ConstantPointerID:
getConstant(llvm::cast<hlvm::ConstantPointer>(n));
break;
case VariableID:
getVariable(llvm::cast<Variable>(n));
break;
case FunctionID:
{
// Get/Create the function
function = llvm::cast<hlvm::Function>(n);
startNewFunction(getFunction(function));
break;
}
case ProgramID:
{
// Create a new function for the program based on the signature
function = llvm::cast<hlvm::Program>(n);
llvm::Function* F = em->NewFunction(
/*Type=*/ em->getProgramType(),
/*Linkage=*/llvm::GlobalValue::InternalLinkage,
/*Name=*/ getLinkageName(function)
);
startNewFunction(F);
// Save the program so it can be generated into the list of program
// entry points.
progs.push_back(F);
break;
}
case BlockID:
{
Block* B = llvm::cast<Block>(n);
std::string name = B->getLabel().empty() ? "block" : B->getLabel();
enters[B] = em->pushBlock(name);
if (B->getResult()) {
const llvm::Type* Ty = getType(B->getType());
llvm::AllocaInst* result = em->NewAutoVar(Ty, name+"_var");
// Initialize the autovar to null
em->emitAssign(result,em->getNullValue(Ty));
pushOperand(result,B);
}
break;
}
default:
break;
}
} else {
// We process non-container nodes and operators. Operators are done
// post-order because we want their operands to be constructed first.
switch (n->getID())
{
case AnyTypeID:
case ArrayTypeID:
case BooleanTypeID:
case BufferTypeID:
case CharacterTypeID:
case EnumerationTypeID:
case IntegerTypeID:
case OpaqueTypeID:
case PointerTypeID:
case RangeTypeID:
case RationalTypeID:
case RealTypeID:
case StreamTypeID:
case StringTypeID:
case StructureTypeID:
case SignatureTypeID:
case VectorTypeID:
{
hlvm::Type* t = llvm::cast<hlvm::Type>(n);
em->AddType(getType(t), t->getName());
break;
}
case NegateOpID: gen(llvm::cast<NegateOp>(n)); break;
case ComplementOpID: gen(llvm::cast<ComplementOp>(n)); break;
case PreIncrOpID: gen(llvm::cast<PreIncrOp>(n)); break;
case PreDecrOpID: gen(llvm::cast<PreDecrOp>(n)); break;
case PostIncrOpID: gen(llvm::cast<PostIncrOp>(n)); break;
case PostDecrOpID: gen(llvm::cast<PostDecrOp>(n)); break;
case SizeOfOpID: gen(llvm::cast<SizeOfOp>(n)); break;
case ConvertOpID: gen(llvm::cast<ConvertOp>(n)); break;
case AddOpID: gen(llvm::cast<AddOp>(n)); break;
case SubtractOpID: gen(llvm::cast<SubtractOp>(n)); break;
case MultiplyOpID: gen(llvm::cast<MultiplyOp>(n)); break;
case DivideOpID: gen(llvm::cast<DivideOp>(n)); break;
case ModuloOpID: gen(llvm::cast<ModuloOp>(n)); break;
case BAndOpID: gen(llvm::cast<BAndOp>(n)); break;
case BOrOpID: gen(llvm::cast<BOrOp>(n)); break;
case BXorOpID: gen(llvm::cast<BXorOp>(n)); break;
case BNorOpID: gen(llvm::cast<BNorOp>(n)); break;
case NotOpID: gen(llvm::cast<NotOp>(n)); break;
case AndOpID: gen(llvm::cast<AndOp>(n)); break;
case OrOpID: gen(llvm::cast<OrOp>(n)); break;
case NorOpID: gen(llvm::cast<NorOp>(n)); break;
case XorOpID: gen(llvm::cast<XorOp>(n)); break;
case EqualityOpID: gen(llvm::cast<EqualityOp>(n)); break;
case InequalityOpID: gen(llvm::cast<InequalityOp>(n)); break;
case LessThanOpID: gen(llvm::cast<LessThanOp>(n)); break;
case GreaterThanOpID: gen(llvm::cast<GreaterThanOp>(n)); break;
case GreaterEqualOpID: gen(llvm::cast<GreaterEqualOp>(n)); break;
case LessEqualOpID: gen(llvm::cast<LessEqualOp>(n)); break;
case IsPInfOpID: gen(llvm::cast<IsPInfOp>(n)); break;
case IsNInfOpID: gen(llvm::cast<IsNInfOp>(n)); break;
case IsNanOpID: gen(llvm::cast<IsNanOp>(n)); break;
case TruncOpID: gen(llvm::cast<TruncOp>(n)); break;
case RoundOpID: gen(llvm::cast<RoundOp>(n)); break;
case FloorOpID: gen(llvm::cast<FloorOp>(n)); break;
case CeilingOpID: gen(llvm::cast<CeilingOp>(n)); break;
case LogEOpID: gen(llvm::cast<LogEOp>(n)); break;
case Log2OpID: gen(llvm::cast<Log2Op>(n)); break;
case Log10OpID: gen(llvm::cast<Log10Op>(n)); break;
case SquareRootOpID: gen(llvm::cast<SquareRootOp>(n)); break;
case CubeRootOpID: gen(llvm::cast<CubeRootOp>(n)); break;
case FactorialOpID: gen(llvm::cast<FactorialOp>(n)); break;
case PowerOpID: gen(llvm::cast<PowerOp>(n)); break;
case RootOpID: gen(llvm::cast<RootOp>(n)); break;
case GCDOpID: gen(llvm::cast<GCDOp>(n)); break;
case LCMOpID: gen(llvm::cast<LCMOp>(n)); break;
case SelectOpID: gen(llvm::cast<SelectOp>(n)); break;
case SwitchOpID: gen(llvm::cast<SwitchOp>(n)); break;
case WhileOpID: gen(llvm::cast<WhileOp>(n)); break;
case UnlessOpID: gen(llvm::cast<UnlessOp>(n)); break;
case UntilOpID: gen(llvm::cast<UntilOp>(n)); break;
case LoopOpID: gen(llvm::cast<LoopOp>(n)); break;
case BreakOpID: gen(llvm::cast<BreakOp>(n)); break;
case ContinueOpID: gen(llvm::cast<ContinueOp>(n)); break;
case ReturnOpID: gen(llvm::cast<ReturnOp>(n)); break;
case ResultOpID: gen(llvm::cast<ResultOp>(n)); break;
case CallOpID: gen(llvm::cast<CallOp>(n)); break;
case LoadOpID: gen(llvm::cast<LoadOp>(n)); break;
case StoreOpID: gen(llvm::cast<StoreOp>(n)); break;
case GetOpID: gen(llvm::cast<GetOp>(n)); break;
case AutoVarOpID: gen(llvm::cast<AutoVarOp>(n)); break;
case OpenOpID: gen(llvm::cast<OpenOp>(n)); break;
case CloseOpID: gen(llvm::cast<CloseOp>(n)); break;
case WriteOpID: gen(llvm::cast<WriteOp>(n)); break;
case ReadOpID: gen(llvm::cast<ReadOp>(n)); break;
case GetIndexOpID: gen(llvm::cast<GetIndexOp>(n)); break;
case GetFieldOpID: gen(llvm::cast<GetFieldOp>(n)); break;
case BundleID:
genProgramLinkage();
modules.push_back(em->FinishModule());
break;
case ConstantBooleanID:
case ConstantCharacterID:
case ConstantEnumeratorID:
case ConstantIntegerID:
case ConstantRealID:
case ConstantStringID:
case ConstantAnyID:
case ConstantStructureID:
case ConstantArrayID:
case ConstantVectorID:
case ConstantContinuationID:
case ConstantPointerID:
/* FALL THROUGH */
case VariableID:
break;
case ProgramID:
/* FALL THROUGH */
case FunctionID:
em->FinishFunction();
// The entry block was created to hold the automatic variables. We now
// need to terminate the block by branching it to the first active block
// in the function.
function = 0;
break;
case BlockID:
{
Block* B = llvm::cast<Block>(n);
exits[B] = em->getBlock();
getBlockResult(B);
em->popBlock();
break;
}
// everything else is an error
default:
hlvmNotImplemented("Node of unimplemented type");
break;
}
}
}
void
LLVMGeneratorPass::handleTerminate()
{
// Nothing to do.
}
llvm::Module*
LLVMGeneratorPass::linkModules()
{
llvm::Linker linker("HLVM",ast->getPublicID(),0);
for (ModuleList::iterator I = modules.begin(), E = modules.end(); I!=E; ++I) {
linker.LinkInModule(*I);
}
modules.empty(); // LinkInModules destroyed/merged them all
return linker.releaseModule();
}
llvm::cl::opt<bool> NoVerify("no-verify",
llvm::cl::init(false),
llvm::cl::desc("Don't verify generated LLVM module"));
llvm::cl::opt<bool> NoInline("no-inlining",
llvm::cl::init(false),
llvm::cl::desc("Do not run the LLVM inliner pass"));
llvm::cl::opt<bool> NoOptimizations("no-optimization",
llvm::cl::init(false),
llvm::cl::desc("Do not run any LLVM optimization passes"));
static void
getCleanupPasses(llvm::PassManager& PM)
{
PM.add(llvm::createLowerSetJmpPass()); // Lower llvm.setjmp/.longjmp
if (NoOptimizations)
return;
PM.add(llvm::createRaiseAllocationsPass()); // call %malloc -> malloc inst
PM.add(llvm::createCFGSimplificationPass()); // Clean up disgusting code
PM.add(llvm::createPromoteMemoryToRegisterPass());// Kill useless allocas
PM.add(llvm::createGlobalOptimizerPass()); // Optimize out global vars
PM.add(llvm::createGlobalDCEPass()); // Remove unused fns and globs
PM.add(llvm::createIPConstantPropagationPass());// IP Constant Propagation
PM.add(llvm::createDeadArgEliminationPass()); // Dead argument elimination
PM.add(llvm::createInstructionCombiningPass()); // Clean up after IPCP & DAE
PM.add(llvm::createCFGSimplificationPass()); // Clean up after IPCP & DAE
PM.add(llvm::createPruneEHPass()); // Remove dead EH info
if (!NoInline)
PM.add(llvm::createFunctionInliningPass()); // Inline small functions
PM.add(llvm::createSimplifyLibCallsPass()); // Library Call Optimizations
PM.add(llvm::createArgumentPromotionPass()); // Scalarize uninlined fn args
PM.add(llvm::createTailDuplicationPass()); // Simplify cfg by copying
PM.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
PM.add(llvm::createScalarReplAggregatesPass()); // Break up aggregate allocas
PM.add(llvm::createInstructionCombiningPass()); // Combine silly seq's
PM.add(llvm::createCondPropagationPass()); // Propagate conditionals
PM.add(llvm::createTailCallEliminationPass()); // Eliminate tail calls
PM.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
PM.add(llvm::createReassociatePass()); // Reassociate expressions
PM.add(llvm::createLICMPass()); // Hoist loop invariants
PM.add(llvm::createLoopUnswitchPass()); // Unswitch loops.
PM.add(llvm::createInstructionCombiningPass()); // Clean up after LICM/reassoc
PM.add(llvm::createIndVarSimplifyPass()); // Canonicalize indvars
PM.add(llvm::createLoopUnrollPass()); // Unroll small loops
PM.add(llvm::createInstructionCombiningPass()); // Clean up after the unroller
PM.add(llvm::createLoadValueNumberingPass()); // GVN for load instructions
PM.add(llvm::createGCSEPass()); // Remove common subexprs
PM.add(llvm::createSCCPPass()); // Constant prop with SCCP
// Run instcombine after redundancy elimination to exploit opportunities
// opened up by them.
PM.add(llvm::createInstructionCombiningPass());
PM.add(llvm::createCondPropagationPass()); // Propagate conditionals
PM.add(llvm::createDeadStoreEliminationPass()); // Delete dead stores
PM.add(llvm::createAggressiveDCEPass()); // SSA based 'Aggressive DCE'
PM.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs
PM.add(llvm::createDeadTypeEliminationPass()); // Eliminate dead types
PM.add(llvm::createConstantMergePass()); // Merge dup global constants
}
static bool
optimizeModule(llvm::Module* mod, std::string& ErrMsg)
{
llvm::PassManager Passes;
Passes.add(new llvm::TargetData(mod));
if (!NoVerify)
if (llvm::verifyModule(*mod,llvm::ReturnStatusAction,&ErrMsg))
return false;
getCleanupPasses(Passes);
Passes.run(*mod);
if (!NoVerify)
if (llvm::verifyModule(*mod,llvm::ReturnStatusAction,&ErrMsg))
return false;
return true;
}
}
bool
hlvm::generateBytecode(AST* tree, std::ostream& output, std::string& ErrMsg)
{
hlvm::PassManager* PM = hlvm::PassManager::create();
LLVMGeneratorPass genPass(tree);
PM->addPass(&genPass);
PM->runOn(tree);
delete PM;
llvm::Module* mod = genPass.linkModules();
bool result = optimizeModule(mod,ErrMsg);
if (result) {
llvm::WriteBitcodeToFile(mod, output);
}
delete mod;
return result;
}
bool
hlvm::generateAssembly(AST* tree, std::ostream& output, std::string& ErrMsg)
{
hlvm::PassManager* PM = hlvm::PassManager::create();
LLVMGeneratorPass genPass(tree);
PM->addPass(&genPass);
PM->runOn(tree);
delete PM;
llvm::Module* mod = genPass.linkModules();
bool result = optimizeModule(mod,ErrMsg);
if (result) {
llvm::PassManager Passes;
llvm::OStream strm(output);
Passes.add(new llvm::PrintModulePass(&strm));
Passes.run(*mod);
}
delete mod;
return result;
}
llvm::Module*
hlvm::generateModule(AST* tree, std::string& ErrMsg)
{
hlvm::PassManager* PM = hlvm::PassManager::create();
LLVMGeneratorPass genPass(tree);
PM->addPass(&genPass);
PM->runOn(tree);
delete PM;
llvm::Module* mod = genPass.linkModules();
if (!optimizeModule(mod,ErrMsg)) {
delete mod;
return 0;
}
return mod;
}