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