From rspencer at reidspencer.com Mon Jun 26 14:53:27 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Mon, 26 Jun 2006 14:53:27 -0500 Subject: [hlvm-commits] r334 - hlvm/AST hlvm/CodeGen hlvm/Pass hlvm/Reader hlvm/Writer test/return0 test/xml2xml Message-ID: <200606261953.k5QJrRd6003926@server1.hlvm.org> Author: reid Date: 2006-06-26 14:45:41 -0500 (Mon, 26 Jun 2006) New Revision: 334 Log: Create a "result" operator to dissociate the operation of specifying a result value for a block from the operation of returning from a function. This allows results to be specified at any point during a block, not just at the end of the block, which allows post-result computations. Modified: hlvm/AST/AST.cpp hlvm/AST/Block.cpp hlvm/AST/ControlFlow.h hlvm/AST/Node.h hlvm/AST/Operator.cpp hlvm/AST/Operator.h hlvm/CodeGen/LLVMGenerator.cpp hlvm/Pass/Validate.cpp hlvm/Reader/HLVM.rng hlvm/Reader/XMLReader.cpp hlvm/Writer/XMLWriter.cpp test/return0/arithmetic.hlx test/return0/bitwise.hlx test/return0/boolean.hlx test/return0/call.hlx test/return0/complement.hlx test/return0/helloworld.hlx test/return0/return0.hlx test/return0/select.hlx test/xml2xml/block.hlx test/xml2xml/helloworld.hlx test/xml2xml/loop.hlx test/xml2xml/return.hlx test/xml2xml/select.hlx test/xml2xml/switch.hlx Modified: hlvm/AST/AST.cpp =================================================================== --- hlvm/AST/AST.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/AST.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -1041,10 +1041,15 @@ AST::new_NilaryOp(const Locator*loc); template ReturnOp* -AST::new_UnaryOp(const Type*Ty, Operator*op1,const Locator*loc); +AST::new_NilaryOp(const Type*Ty, const Locator*loc); template ReturnOp* -AST::new_UnaryOp(Operator*op1,const Locator*loc); +AST::new_NilaryOp(const Locator*loc); +template ResultOp* +AST::new_UnaryOp(const Type*Ty, Operator*op1,const Locator*loc); +template ResultOp* +AST::new_UnaryOp(Operator*op1,const Locator*loc); + template CallOp* AST::new_MultiOp(const Type*Ty, const std::vector& ops, const Locator*loc); template CallOp* Modified: hlvm/AST/Block.cpp =================================================================== --- hlvm/AST/Block.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/Block.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -47,7 +47,7 @@ if (llvm::isa(child)) { AutoVarOp* av = llvm::cast(child); autovars[av->getName()] = av; - } + } else if (llvm::isa(child)) type = getResultType(); // update type to match type of thing just added } @@ -83,4 +83,5 @@ return 0; } +ResultOp::~ResultOp() {} } Modified: hlvm/AST/ControlFlow.h =================================================================== --- hlvm/AST/ControlFlow.h 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/ControlFlow.h 2006-06-26 19:45:41 UTC (rev 334) @@ -153,28 +153,22 @@ /// The ReturnOp takes one operand which is the value to return to the caller /// of the Function. /// @brief AST Return Operator Node -class ReturnOp : public UnaryOperator +class ReturnOp : public NilaryOperator { /// @name Constructors /// @{ protected: - ReturnOp() : UnaryOperator(ReturnOpID) {} + ReturnOp() : NilaryOperator(ReturnOpID) {} virtual ~ReturnOp(); /// @} /// @name Accessors /// @{ public: - Value* getResult() { return UnaryOperator::op1; } static inline bool classof(const ReturnOp*) { return true; } static inline bool classof(const Node* N) { return N->is(ReturnOpID); } /// @} - /// @name Accessors - /// @{ - public: - void setResult(Value* op) { op->setParent(this); } - /// @} friend class AST; }; Modified: hlvm/AST/Node.h =================================================================== --- hlvm/AST/Node.h 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/Node.h 2006-06-26 19:45:41 UTC (rev 334) @@ -155,9 +155,10 @@ FirstOperatorID = BlockID, // Nilary Operators (those taking no operands) - BreakOpID, ///< Break out of the enclosing loop + BreakOpID, ///< Break out of the enclosing block FirstNilaryOperatorID = BreakOpID, - ContinueOpID, ///< Continue from start of enclosing block + ContinueOpID, ///< Continue from start of enclosing loop + ReturnOpID, ///< Return to the function's caller PInfOpID, ///< Constant Positive Infinity Real Value NInfOpID, ///< Constant Negative Infinity Real Value NaNOpID, ///< Constant Not-A-Number Real Value @@ -167,8 +168,7 @@ // Control Flow Unary Operators NullOpID, ///< The "do nothing" NullOp (no-op) Operator FirstUnaryOperatorID = NullOpID, - ReturnOpID, ///< Return a value to the function's caller - ResultOpID, ///< Specify the result of a block + ResultOpID, ///< Specify the result of a block or function ThrowOpID, ///< Throw an exception out of the function // Integer Arithmetic Unary Operators Modified: hlvm/AST/Operator.cpp =================================================================== --- hlvm/AST/Operator.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/Operator.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -48,6 +48,14 @@ return cast(p); } +Block* +Operator::getContainingBlock() +{ + Node* p = getParent(); + while (p && !isa(p)) p = p->getParent(); + return cast(p); +} + NilaryOperator::~NilaryOperator() { } Modified: hlvm/AST/Operator.h =================================================================== --- hlvm/AST/Operator.h 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/AST/Operator.h 2006-06-26 19:45:41 UTC (rev 334) @@ -37,6 +37,7 @@ class Type; class Function; +class Block; /// This class is the abstract base class in the Abstract Syntax Tree for all /// operators. An Operator is an instruction to the virtual machine to take @@ -70,6 +71,9 @@ /// Return the function containing this operator Function* getContainingFunction(); + /// Return the block containing this operator + Block* getContainingBlock(); + /// Determine if this is a classof some other type. static inline bool classof(const Operator*) { return true; } static inline bool classof(const Node* N) { return N->isOperator(); } Modified: hlvm/CodeGen/LLVMGenerator.cpp =================================================================== --- hlvm/CodeGen/LLVMGenerator.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/CodeGen/LLVMGenerator.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -77,6 +77,7 @@ typedef std::vector ModuleList; typedef std::vector OperandList; typedef std::vector BlockStack; + typedef std::vector ResultStack; typedef std::map VariableDictionary; typedef std::map AutoVarDictionary; typedef std::map @@ -88,12 +89,12 @@ llvm::BasicBlock* lblk; ///< The current LLVM block we're generating OperandList lops; ///< The current list of instruction operands BlockStack blocks; ///< The stack of blocks we're constructing + ResultStack results; ///< The stack of block results VariableDictionary gvars; ///< Dictionary of HLVM -> LLVM gvars AutoVarDictionary lvars; ///< Dictionary of HLVM -> LLVM auto vars llvm::TypeSymbolTable ltypes; ///< The cached LLVM types we've generated ConstantDictionary consts; ///< The cached LLVM constants we've generated FunctionDictionary funcs; ///< The cached LLVM constants we've generated - ///< The current LLVM instructions we're generating 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 @@ -120,8 +121,8 @@ public: LLVMGeneratorPass(const AST* tree) : Pass(0,Pass::PreAndPostOrderTraversal), - modules(), lmod(0), lfunc(0), lblk(0), lops(), blocks(), - gvars(), lvars(), ltypes(), consts(), + modules(), lmod(0), lfunc(0), lblk(0), lops(), blocks(), results(), + gvars(), lvars(), ltypes(), consts(), funcs(), ast(tree), bundle(0), function(0), block(0), hlvm_text(0), hlvm_text_create(0), hlvm_text_delete(0), hlvm_text_to_buffer(0), @@ -1142,7 +1143,7 @@ template<> void LLVMGeneratorPass::gen(LoopOp* op) { - hlvmAssert(lops.size() >= 3 && "Too few operands for SelectOp"); + hlvmAssert(lops.size() >= 3 && "Too few operands for LoopOp"); llvm::Value* op3 = lops.back(); lops.pop_back(); llvm::Value* op2 = lops.back(); lops.pop_back(); llvm::Value* op1 = lops.back(); lops.pop_back(); @@ -1159,18 +1160,32 @@ } template<> void +LLVMGeneratorPass::gen(ResultOp* r) +{ + hlvmAssert(lops.size() >= 1 && "Too few operands for ResultOp"); + llvm::Value* result = lops.back(); lops.pop_back(); + const llvm::Type* resultTy = result->getType(); + if (resultTy != lfunc->getReturnType()) { + result = new llvm::CastInst(result,lfunc->getReturnType(),"result",lblk); + } + // Save the result value for use in other blocks or as the result of the + // function + results.push_back(result); +} + +template<> void LLVMGeneratorPass::gen(ReturnOp* r) { - hlvmAssert(lops.size() >= 1 && "Too few operands for ReturnInst"); - llvm::Value* retVal = lops.back(); lops.pop_back(); - const llvm::Type* retTy = retVal->getType(); - if (retTy != lfunc->getReturnType()) { - retVal = new llvm::CastInst(retVal,lfunc->getReturnType(),"",lblk); + // If this function returns a result then we need a return value + llvm::Value* result = 0; + if (lfunc->getReturnType() != llvm::Type::VoidTy) { + hlvmAssert(!results.empty() && "No result for function"); + result = results.back(); results.pop_back(); } // RetInst is never the operand of another instruction because it is // a terminator and cannot return a value. Consequently, we don't push it // on the lops stack. - new llvm::ReturnInst(retVal,lblk); + new llvm::ReturnInst(result,lblk); } template<> void @@ -1439,6 +1454,7 @@ lvars.clear(); blocks.clear(); lops.clear(); + results.clear(); break; } case ProgramID: @@ -1461,7 +1477,9 @@ } case BlockID: { - lblk = new llvm::BasicBlock(llvm::cast(n)->getLabel(),lfunc,0); + Block* B = llvm::cast(n); + + lblk = new llvm::BasicBlock(B->getLabel(),lfunc,0); blocks.push_back(lblk); break; } @@ -1533,6 +1551,7 @@ case BreakOpID: gen(llvm::cast(n)); break; case ContinueOpID: gen(llvm::cast(n)); break; case ReturnOpID: gen(llvm::cast(n)); break; + case ResultOpID: gen(llvm::cast(n)); break; case CallOpID: gen(llvm::cast(n)); break; case LoadOpID: gen(llvm::cast(n)); break; case StoreOpID: gen(llvm::cast(n)); break; Modified: hlvm/Pass/Validate.cpp =================================================================== --- hlvm/Pass/Validate.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/Pass/Validate.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -515,20 +515,30 @@ checkOperator(n,NullOpID,0); } + template<> inline void -ValidateImpl::validate(ReturnOp* n) +ValidateImpl::validate(ResultOp* n) { - if (checkOperator(n,ReturnOpID,1)) - if (checkTerminator(n)) { + if (checkOperator(n,ResultOpID,1)) { + const Function* F = n->getContainingFunction(); + const Block* B = n->getContainingBlock(); + if (F->getBlock() == B) { + const SignatureType* SigTy = F->getSignature(); Operator* res = n->getOperand(0); - const Function* F = n->getContainingFunction(); - const SignatureType* SigTy = F->getSignature(); if (res->getType() != SigTy->getResultType()) - error(n,"ReturnOp operand does not agree in type with Function result"); + error(n,"ResultOp operand does not agree in type with Function result"); } + } } template<> inline void +ValidateImpl::validate(ReturnOp* n) +{ + if (checkOperator(n,ReturnOpID,0)) + checkTerminator(n); +} + +template<> inline void ValidateImpl::validate(BreakOp* n) { if (checkOperator(n,BreakOpID,0)) @@ -1264,6 +1274,7 @@ case ThrowOpID: /*validate(cast(n));*/ break; case NullOpID: validate(cast(n)); break; case ReturnOpID: validate(cast(n)); break; + case ResultOpID: validate(cast(n)); break; case ContinueOpID: validate(cast(n)); break; case BreakOpID: validate(cast(n)); break; case SelectOpID: validate(cast(n)); break; Modified: hlvm/Reader/HLVM.rng =================================================================== --- hlvm/Reader/HLVM.rng 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/Reader/HLVM.rng 2006-06-26 19:45:41 UTC (rev 334) @@ -1053,6 +1053,7 @@ + @@ -1102,6 +1103,12 @@ + + + + + + Modified: hlvm/Reader/XMLReader.cpp =================================================================== --- hlvm/Reader/XMLReader.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/Reader/XMLReader.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -1102,7 +1102,8 @@ case TKN_loop: op = parseTernaryOp(cur); break; case TKN_break: op = parseNilaryOp(cur); break; case TKN_continue: op = parseNilaryOp(cur); break; - case TKN_ret: op = parseUnaryOp(cur); break; + case TKN_ret: op = parseNilaryOp(cur); break; + case TKN_result: op = parseUnaryOp(cur); break; case TKN_call: op = parseMultiOp(cur); break; case TKN_store: op = parseBinaryOp(cur); break; case TKN_load: op = parseUnaryOp(cur); break; Modified: hlvm/Writer/XMLWriter.cpp =================================================================== --- hlvm/Writer/XMLWriter.cpp 2006-06-25 04:57:27 UTC (rev 333) +++ hlvm/Writer/XMLWriter.cpp 2006-06-26 19:45:41 UTC (rev 334) @@ -721,6 +721,13 @@ } template<> void +XMLWriterImpl::WriterPass::put(ResultOp* r) +{ + startElement("result"); + putDoc(r); +} + +template<> void XMLWriterImpl::WriterPass::put(CallOp* r) { startElement("call"); @@ -852,6 +859,7 @@ case BreakOpID: put(cast(n)); break; case ContinueOpID: put(cast(n)); break; case ReturnOpID: put(cast(n)); break; + case ResultOpID: put(cast(n)); break; case CallOpID: put(cast(n)); break; case StoreOpID: put(cast(n)); break; case LoadOpID: put(cast(n)); break; Modified: test/return0/arithmetic.hlx =================================================================== --- test/return0/arithmetic.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/arithmetic.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -8,7 +8,7 @@ 8 - + @@ -22,7 +22,8 @@ - + + Modified: test/return0/bitwise.hlx =================================================================== --- test/return0/bitwise.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/bitwise.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -7,7 +7,7 @@ 00000000 - + @@ -21,7 +21,8 @@ - + + Modified: test/return0/boolean.hlx =================================================================== --- test/return0/boolean.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/boolean.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -7,7 +7,7 @@ 0 - + - + + Modified: test/return0/call.hlx =================================================================== --- test/return0/call.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/call.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -5,19 +5,21 @@ - + - + + - + - + + Modified: test/return0/complement.hlx =================================================================== --- test/return0/complement.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/complement.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -4,7 +4,7 @@ - + @@ -12,7 +12,8 @@ - + + Modified: test/return0/helloworld.hlx =================================================================== --- test/return0/helloworld.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/helloworld.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -25,9 +25,10 @@ - + - + + Modified: test/return0/return0.hlx =================================================================== --- test/return0/return0.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/return0.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -4,9 +4,10 @@ 0 - + - + + Modified: test/return0/select.hlx =================================================================== --- test/return0/select.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/return0/select.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -12,7 +12,7 @@ - + - + + Modified: test/xml2xml/block.hlx =================================================================== --- test/xml2xml/block.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/block.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -12,7 +12,7 @@ - + - + + Modified: test/xml2xml/helloworld.hlx =================================================================== --- test/xml2xml/helloworld.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/helloworld.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -30,9 +30,10 @@ - + - + + Modified: test/xml2xml/loop.hlx =================================================================== --- test/xml2xml/loop.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/loop.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -9,7 +9,7 @@ - + @@ -18,7 +18,8 @@ - + + Modified: test/xml2xml/return.hlx =================================================================== --- test/xml2xml/return.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/return.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -6,9 +6,10 @@ - + - + + Modified: test/xml2xml/select.hlx =================================================================== --- test/xml2xml/select.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/select.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -12,7 +12,7 @@ - + - + + Modified: test/xml2xml/switch.hlx =================================================================== --- test/xml2xml/switch.hlx 2006-06-25 04:57:27 UTC (rev 333) +++ test/xml2xml/switch.hlx 2006-06-26 19:45:41 UTC (rev 334) @@ -27,7 +27,7 @@ - + @@ -44,7 +44,8 @@ - + + From rspencer at reidspencer.com Tue Jun 27 15:36:56 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Tue, 27 Jun 2006 15:36:56 -0500 Subject: [hlvm-commits] r335 - hlvm/AST hlvm/CodeGen hlvm/Pass hlvm/Reader test/return0 test/xml2xml tools/hlvm-compiler Message-ID: <200606272036.k5RKauUe006926@server1.hlvm.org> Author: reid Date: 2006-06-27 15:01:30 -0500 (Tue, 27 Jun 2006) New Revision: 335 Log: Get the SelectOp working. HLVM can now make decisions. Adjust test cases for the new ResultOp operator. Start work on LoopOp by validating its operands. Modified: hlvm/AST/Block.cpp hlvm/AST/Block.h hlvm/AST/ControlFlow.h hlvm/AST/Linkables.h hlvm/AST/Node.h hlvm/AST/Operator.cpp hlvm/AST/Operator.h hlvm/CodeGen/LLVMGenerator.cpp hlvm/Pass/Validate.cpp hlvm/Reader/HLVM.rng test/return0/select.hlx test/xml2xml/argscall.hlx test/xml2xml/arithmetic.hlx test/xml2xml/autovar.hlx test/xml2xml/block.hlx test/xml2xml/booleanops.hlx test/xml2xml/break.hlx test/xml2xml/call.hlx test/xml2xml/continue.hlx test/xml2xml/loop.hlx tools/hlvm-compiler/hlvm-compiler.cpp Modified: hlvm/AST/Block.cpp =================================================================== --- hlvm/AST/Block.cpp 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Block.cpp 2006-06-27 20:01:30 UTC (rev 335) @@ -47,8 +47,10 @@ if (llvm::isa(child)) { AutoVarOp* av = llvm::cast(child); autovars[av->getName()] = av; - } else if (llvm::isa(child)) - type = getResultType(); // update type to match type of thing just added + } else if (llvm::isa(child)) { + result = llvm::cast(child); + type = result->getType(); + } } void Modified: hlvm/AST/Block.h =================================================================== --- hlvm/AST/Block.h 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Block.h 2006-06-27 20:01:30 UTC (rev 335) @@ -51,7 +51,7 @@ /// @name Constructors /// @{ protected: - Block() : MultiOperator(BlockID){} + Block() : MultiOperator(BlockID), label(), result(0), autovars() {} virtual ~Block(); /// @} @@ -60,9 +60,14 @@ public: virtual const Type* getType() const { return this->back()->getType(); } const std::string& getLabel() const { return label; } - AutoVarOp* getAutoVar(const std::string& name) const; - const Type* getResultType() { return this->back()->getType(); } + AutoVarOp* getAutoVar(const std::string& name) const; + const Type* getResultType() const { return result->getType(); } + const Operator* getResult() const { return result; } Block* getParentBlock() const; + bool isTerminated() const { + if (empty()) return false; + return back()->isTerminator(); + } static inline bool classof(const Block*) { return true; } static inline bool classof(const Node* N) { return N->is(BlockID); } @@ -71,6 +76,7 @@ /// @{ public: void setLabel(const std::string& l) { label = l; } + protected: virtual void insertChild(Node* child); virtual void removeChild(Node* child); @@ -80,6 +86,7 @@ private: typedef std::map AutoVarMap; std::string label; + Operator* result; AutoVarMap autovars; /// @} friend class AST; Modified: hlvm/AST/ControlFlow.h =================================================================== --- hlvm/AST/ControlFlow.h 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/ControlFlow.h 2006-06-27 20:01:30 UTC (rev 335) @@ -62,8 +62,14 @@ /// operand as a boolean. If the result is true, the second operand is evaluated /// and its result is the result of the select operator. If the result of the /// first operand is false, the third operand is evaluated and its result is the -/// result of the select operator. This is similar to an "if" statement in other -/// languages except it is unrestricted. The three operands can be of any type. +/// result of the select operator. This is similar to the ternary operator in +/// other languages, such as ?: in C. It also fulfills the purpose of an "if" +/// statement except it is more generalized because the operator has a result +/// value whereas most "if" statements do not. The second and third operands +/// can be any type but they must both be the same type. If the second and +/// third operands are blocks, and neither contains a result operator, the +/// result of those blocks has type "void" and consequently so does the result +/// of the select operator. /// @brief AST Select Operator Node class SelectOp : public TernaryOperator { Modified: hlvm/AST/Linkables.h =================================================================== --- hlvm/AST/Linkables.h 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Linkables.h 2006-06-27 20:01:30 UTC (rev 335) @@ -167,6 +167,7 @@ bool hasBlock() const { return block != 0; } Block* getBlock() const { return block; } const SignatureType* getSignature() const; + const Type* getResultType() const { return getSignature()->getResultType();} static inline bool classof(const Function*) { return true; } static inline bool classof(const Node* N) { return N->isFunction(); } Modified: hlvm/AST/Node.h =================================================================== --- hlvm/AST/Node.h 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Node.h 2006-06-27 20:01:30 UTC (rev 335) @@ -380,8 +380,7 @@ return id >= FirstOperatorID && id <= LastOperatorID; } inline bool isTerminator() const { - return (id >= BreakOpID && id <= ContinueOpID) || - (id >= ReturnOpID && id <= ThrowOpID); } + return (id >= BreakOpID && id <= ReturnOpID) || (id == ThrowOpID); } inline bool isNilaryOperator() const { return id >= FirstNilaryOperatorID && id <= LastNilaryOperatorID; } Modified: hlvm/AST/Operator.cpp =================================================================== --- hlvm/AST/Operator.cpp 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Operator.cpp 2006-06-27 20:01:30 UTC (rev 335) @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -45,6 +46,8 @@ { Node* p = getParent(); while (p && !isa(p)) p = p->getParent(); + if (!p) + return 0; return cast(p); } @@ -53,9 +56,21 @@ { Node* p = getParent(); while (p && !isa(p)) p = p->getParent(); + if (!p) + return 0; return cast(p); } +LoopOp* +Operator::getContainingLoop() +{ + Node* p = getParent(); + while (p && !isa(p)) p = p->getParent(); + if (!p) + return 0; + return cast(p); +} + NilaryOperator::~NilaryOperator() { } Modified: hlvm/AST/Operator.h =================================================================== --- hlvm/AST/Operator.h 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/AST/Operator.h 2006-06-27 20:01:30 UTC (rev 335) @@ -38,6 +38,7 @@ class Type; class Function; class Block; +class LoopOp; /// This class is the abstract base class in the Abstract Syntax Tree for all /// operators. An Operator is an instruction to the virtual machine to take @@ -74,6 +75,9 @@ /// Return the block containing this operator Block* getContainingBlock(); + /// Return the loop operator containing this operator + LoopOp* getContainingLoop(); + /// Determine if this is a classof some other type. static inline bool classof(const Operator*) { return true; } static inline bool classof(const Node* N) { return N->isOperator(); } Modified: hlvm/CodeGen/LLVMGenerator.cpp =================================================================== --- hlvm/CodeGen/LLVMGenerator.cpp 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/CodeGen/LLVMGenerator.cpp 2006-06-27 20:01:30 UTC (rev 335) @@ -77,7 +77,7 @@ typedef std::vector ModuleList; typedef std::vector OperandList; typedef std::vector BlockStack; - typedef std::vector ResultStack; + typedef std::map ResultDictionary; typedef std::map VariableDictionary; typedef std::map AutoVarDictionary; typedef std::map @@ -89,7 +89,7 @@ llvm::BasicBlock* lblk; ///< The current LLVM block we're generating OperandList lops; ///< The current list of instruction operands BlockStack blocks; ///< The stack of blocks we're constructing - ResultStack results; ///< The stack of block results + ResultDictionary results; ///< Dictionary of LLVM blocks to result values VariableDictionary gvars; ///< Dictionary of HLVM -> LLVM gvars AutoVarDictionary lvars; ///< Dictionary of HLVM -> LLVM auto vars llvm::TypeSymbolTable ltypes; ///< The cached LLVM types we've generated @@ -1112,23 +1112,74 @@ llvm::Value* op3 = lops.back(); lops.pop_back(); llvm::Value* op2 = lops.back(); lops.pop_back(); llvm::Value* op1 = lops.back(); lops.pop_back(); - hlvmAssert(op1->getType() == llvm::Type::BoolTy); hlvmAssert(op2->getType() == op2->getType()); hlvmAssert(llvm::isa(op2) == llvm::isa(op3)); + + /// If the first operand is a basic block then it is an expression block, by + /// definition. We can therefore discard the LLVM basic block and incorporate + /// its contents into the current block. We also replace "op1" with the + /// BasicBlock's result which was cached. + if (llvm::BasicBlock* BB1 = llvm::dyn_cast(op1)) { + hlvmAssert(!BB1->getTerminator() && "expression block with terminator?"); + // Move the contents of the basic block into the current one + llvm::BasicBlock::InstListType& IL = lblk->getInstList(); + for (llvm::BasicBlock::iterator I = BB1->begin(), E = BB1->end(); + I != E; ) { + // be careful with iterator invalidation + llvm::Instruction* one2move = &(*I); + ++I; + // move the instruction from one block to the other + one2move->removeFromParent(); + IL.push_back(one2move); + } + op1 = results[BB1]; + results.erase(BB1); + BB1->eraseFromParent(); + } + if (llvm::isa(op2)) { - // both are blocks, emit a BranchInstr - lops.push_back(new llvm::BranchInst( - llvm::cast(op2), - llvm::cast(op3),op1,lblk)); - return; - } - - // A this point, we can only be left with a first class type since all HLVM - // operators translate to a first class type. Since the select operator - // requires first class types, its okay to just use it here. - hlvmAssert(op2->getType()->isFirstClassType()); - lops.push_back(new llvm::SelectInst(op1,op2,op3,"select",lblk)); + // Both op2 and op3 are blocks, so we must emit a branch instruction for + // the select. That will terminate the current block so we need to set up + // another block to receive the result of the selection. We also need to + // make sure that the two operand blocks are properly terminated. + llvm::BasicBlock* BB2 = llvm::cast(op2); + llvm::BasicBlock* BB3 = llvm::cast(op3); + // Neither block should have a terminator, they are expression blocks + hlvmAssert(!BB2->getTerminator() && !BB3->getTerminator()); + // Create an auto variable to hold the result of the select. + llvm::AllocaInst* select_result = new llvm::AllocaInst( + /*Ty=*/ results[BB2]->getType(), + /*ArraySize=*/ llvm::ConstantUInt::get(llvm::Type::UIntTy,1), + /*Name=*/ "select_result", + /*InsertAtEnd=*/ lblk + ); + // Set up the branch to terminate the current block + new llvm::BranchInst(BB2,BB3,op1,lblk); + // Create the exit block + llvm::BasicBlock* exit = new llvm::BasicBlock("select_exit",lfunc); + // Make the exit block the current block + lblk = exit; + // Store the result of the "true" case into the autovar + new llvm::StoreInst(results[BB2],select_result,BB2); + // Branch to the exit block + BB2->setName("select_true"); + new llvm::BranchInst(exit,BB2); + // Store the result of the "false" case into the autovar + new llvm::StoreInst(results[BB3],select_result,BB3); + // Branch to the exit block + BB3->setName("select_false"); + new llvm::BranchInst(exit,BB3); + // Load the result and put it on the operand stack + lops.push_back(new llvm::LoadInst(select_result,"select",exit)); + } else { + // A this point, we can only be left with a first class type since all HLVM + // operators translate to a first class type. Since the select operator + // requires first class types, its okay to just use it here. + hlvmAssert(op2->getType()->isFirstClassType()); + hlvmAssert(op3->getType()->isFirstClassType()); + lops.push_back(new llvm::SelectInst(op1,op2,op3,"select",lblk)); + } } template<> void @@ -1147,6 +1198,7 @@ llvm::Value* op3 = lops.back(); lops.pop_back(); llvm::Value* op2 = lops.back(); lops.pop_back(); llvm::Value* op1 = lops.back(); lops.pop_back(); + } template<> void @@ -1164,13 +1216,9 @@ { hlvmAssert(lops.size() >= 1 && "Too few operands for ResultOp"); llvm::Value* result = lops.back(); lops.pop_back(); - const llvm::Type* resultTy = result->getType(); - if (resultTy != lfunc->getReturnType()) { - result = new llvm::CastInst(result,lfunc->getReturnType(),"result",lblk); - } // Save the result value for use in other blocks or as the result of the // function - results.push_back(result); + results[lblk] = result; } template<> void @@ -1180,8 +1228,14 @@ llvm::Value* result = 0; if (lfunc->getReturnType() != llvm::Type::VoidTy) { hlvmAssert(!results.empty() && "No result for function"); - result = results.back(); results.pop_back(); + result = results[lblk]; + const llvm::Type* resultTy = result->getType(); + if (resultTy != lfunc->getReturnType()) { + result = new llvm::CastInst(result,lfunc->getReturnType(),"result",lblk); + } + hlvmAssert(result && "No result for function"); } + // RetInst is never the operand of another instruction because it is // a terminator and cannot return a value. Consequently, we don't push it // on the lops stack. @@ -1478,7 +1532,6 @@ case BlockID: { Block* B = llvm::cast(n); - lblk = new llvm::BasicBlock(B->getLabel(),lfunc,0); blocks.push_back(lblk); break; @@ -1577,6 +1630,7 @@ lfunc = 0; break; case BlockID: + lops.push_back(lblk); blocks.pop_back(); if (blocks.empty()) lblk = 0; Modified: hlvm/Pass/Validate.cpp =================================================================== --- hlvm/Pass/Validate.cpp 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/Pass/Validate.cpp 2006-06-27 20:01:30 UTC (rev 335) @@ -55,8 +55,8 @@ ValidateImpl() : Pass(0,Pass::PostOrderTraversal), ast(0) {} virtual void handleInitialize(AST* tree) { ast = tree; } virtual void handle(Node* b,Pass::TraversalKinds k); - inline void error(Node*n, const std::string& msg); - inline void warning(Node*n, const std::string& msg); + inline void error(const Node*n, const std::string& msg); + inline void warning(const Node*n, const std::string& msg); inline bool checkNode(Node*); inline bool checkType(Type*,NodeIDs id); inline bool checkValue(Value*,NodeIDs id); @@ -67,13 +67,14 @@ inline bool checkUniformContainer(UniformContainerType* T, NodeIDs id); inline bool checkDisparateContainer(DisparateContainerType* T, NodeIDs id); inline bool checkLinkable(Linkable* LI, NodeIDs id); + inline bool checkExpressionBlock(const Block* B); template inline void validate(NodeClass* C); }; void -ValidateImpl::warning(Node* n, const std::string& msg) +ValidateImpl::warning(const Node* n, const std::string& msg) { if (n) { const Locator* loc = n->getLocator(); @@ -88,7 +89,7 @@ } void -ValidateImpl::error(Node* n, const std::string& msg) +ValidateImpl::error(const Node* n, const std::string& msg) { if (n) { const Locator* loc = n->getLocator(); @@ -249,6 +250,21 @@ return result; } +bool +ValidateImpl::checkExpressionBlock(const Block* B) +{ + bool result = true; + if (!B->getResult()) { + error(B,"Expression block without result"); + result = false; + } + if (B->isTerminated()) { + error(B,"Expression blocks cannot have terminators"); + result = false; + } + return true; +} + template<> inline void ValidateImpl::validate(VoidType* n) { @@ -503,10 +519,39 @@ if (checkValue(n,BlockID)) if (n->getNumOperands() == 0) error(n,"Block with no operands"); - else - for (MultiOperator::iterator I = n->begin(), E = n->end(); I != E; ++I) - if (!llvm::isa(*I)) + else { + Operator* terminator = 0; + Operator* result = 0; + for (MultiOperator::iterator I = n->begin(), E = n->end(); I != E; ++I) { + if (llvm::isa(*I)) + result = *I; + else if ((*I)->isTerminator()) { + if (terminator) + error(n,"Block contains multiple terminators"); + else + terminator = *I; + } else if (terminator) + error(n,"Block has operators after terminator"); + else if (!llvm::isa(*I)) error(n,"Block contains non-operator"); + } + if (terminator) { + if (llvm::isa(terminator)) { + if (!result) { + Function* F= n->getContainingFunction(); + if (F->getResultType() != ast->getPrimitiveType(VoidTypeID)) + error(terminator,"Missing result in return from function"); + } + } else if (result) { + warning(result,"Result will not be used in terminated block"); + } + } else if (result) { + if (n == n->getContainingFunction()->getBlock()) + error(result,"Function's main block has result but no return"); + } else { + error(n,"Block does not contain a result or terminator"); + } + } } template<> inline void @@ -521,12 +566,18 @@ { if (checkOperator(n,ResultOpID,1)) { const Function* F = n->getContainingFunction(); - const Block* B = n->getContainingBlock(); - if (F->getBlock() == B) { - const SignatureType* SigTy = F->getSignature(); - Operator* res = n->getOperand(0); - if (res->getType() != SigTy->getResultType()) - error(n,"ResultOp operand does not agree in type with Function result"); + if (!F) + error(n,"ResultOp not in Function!"); + else { + const Block* B = n->getContainingBlock(); + if (!B) + error(n,"ResultOp not in a Block"); + else if (F->getBlock() == B) { + const SignatureType* SigTy = F->getSignature(); + Operator* res = n->getOperand(0); + if (res->getType() != SigTy->getResultType()) + error(n,"Operand does not agree in type with Function result"); + } } } } @@ -542,14 +593,18 @@ ValidateImpl::validate(BreakOp* n) { if (checkOperator(n,BreakOpID,0)) - checkTerminator(n); + if (checkTerminator(n)) + if (!n->getContainingLoop()) + error(n,"Break not within a loop scope"); } template<> inline void ValidateImpl::validate(ContinueOp* n) { if (checkOperator(n,ContinueOpID,0)) - checkTerminator(n); + if (checkTerminator(n)) + if (!n->getContainingLoop()) + error(n,"Continue not within a loop scope"); } template<> inline void @@ -564,11 +619,17 @@ const Type* Ty3 = Op3->getType(); if (!isa(Ty1)) error(n,"SelectOp expects first operand to be type boolean"); - else if ( Ty2 != Ty3 ) - error(n,"Second and third operands for SelectOp must agree in type"); - else if (isa(Op2) != isa(Op3)) + if (isa(Op1)) + checkExpressionBlock(cast(Op1)); + if (Ty2 != Ty3) + error(n,"Second and third operands for SelectOp must have same type"); + if (isa(Op2) != isa(Op3)) error(n,"SelectOp requires operands 2 and 3 to both be blocks or " "neither be blocks"); + if (isa(Op2)) + checkExpressionBlock(cast(Op2)); + if (isa(Op3)) + checkExpressionBlock(cast(Op3)); } } @@ -576,12 +637,19 @@ ValidateImpl::validate(LoopOp* n) { if (checkOperator(n,LoopOpID,3)) { - const Type* Ty = n->getOperand(0)->getType(); - if (!isa(Ty) && !isa(Ty)) + const Operator* Op1 = n->getOperand(0); + const Operator* Op2 = n->getOperand(1); + const Operator* Op3 = n->getOperand(2); + const Type* Ty1 = Op1->getType(); + const Type* Ty3 = Op3->getType(); + if (!isa(Ty1) && !isa(Ty1)) error(n,"LoopOp expects first operand to be type boolean or void"); - Ty = n->getOperand(2)->getType(); - if (!isa(Ty) && !isa(Ty)) + if (!isa(Ty3) && !isa(Ty3)) error(n,"LoopOp expects third operand to be type boolean or void"); + if (isa(Op1)) + checkExpressionBlock(cast(Op1)); + if (isa(Op3)) + checkExpressionBlock(cast(Op3)); } } Modified: hlvm/Reader/HLVM.rng =================================================================== --- hlvm/Reader/HLVM.rng 2006-06-26 19:45:41 UTC (rev 334) +++ hlvm/Reader/HLVM.rng 2006-06-27 20:01:30 UTC (rev 335) @@ -1090,12 +1090,22 @@ + + + + + + + + + + Modified: test/return0/select.hlx =================================================================== --- test/return0/select.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/return0/select.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -1,27 +1,29 @@ - - 0 - - - 21 - - - 42 - + 0 + 21 + 42 + + + + + + + - + - + Modified: test/xml2xml/argscall.hlx =================================================================== --- test/xml2xml/argscall.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/argscall.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -16,6 +16,9 @@ 42 + + 0 + @@ -40,6 +43,10 @@ + + + + Modified: test/xml2xml/arithmetic.hlx =================================================================== --- test/xml2xml/arithmetic.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/arithmetic.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -4,6 +4,9 @@ 1 + + 0 + @@ -98,6 +101,10 @@ + + + + Modified: test/xml2xml/autovar.hlx =================================================================== --- test/xml2xml/autovar.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/autovar.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -3,7 +3,13 @@ - + + + + + + + Modified: test/xml2xml/block.hlx =================================================================== --- test/xml2xml/block.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/block.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -15,16 +15,22 @@ Modified: test/xml2xml/booleanops.hlx =================================================================== --- test/xml2xml/booleanops.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/booleanops.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -7,6 +7,9 @@ + + 0 + @@ -96,6 +99,10 @@ + + + + Modified: test/xml2xml/break.hlx =================================================================== --- test/xml2xml/break.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/break.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -1,9 +1,22 @@ + + 0 + - + + + + + + + + + + + Modified: test/xml2xml/call.hlx =================================================================== --- test/xml2xml/call.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/call.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -3,11 +3,18 @@ + + 0 + + + + + Modified: test/xml2xml/continue.hlx =================================================================== --- test/xml2xml/continue.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/continue.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -1,9 +1,22 @@ + + 0 + - + + + + + + + + + + + Modified: test/xml2xml/loop.hlx =================================================================== --- test/xml2xml/loop.hlx 2006-06-26 19:45:41 UTC (rev 334) +++ test/xml2xml/loop.hlx 2006-06-27 20:01:30 UTC (rev 335) @@ -1,13 +1,13 @@ - - + + 0 1 - + Modified: tools/hlvm-compiler/hlvm-compiler.cpp =================================================================== --- tools/hlvm-compiler/hlvm-compiler.cpp 2006-06-26 19:45:41 UTC (rev 334) +++ tools/hlvm-compiler/hlvm-compiler.cpp 2006-06-27 20:01:30 UTC (rev 335) @@ -47,8 +47,8 @@ OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); -static cl::opt Validate("validate", cl::init(true), - cl::desc("Validate input before generating code")); +static cl::opt NoValidate("no-validate", cl::init(false), + cl::desc("Don't validate input before generating code")); enum GenerationOptions { GenLLVMBytecode, @@ -117,7 +117,7 @@ XMLReader* rdr = XMLReader::create(InputFilename); rdr->read(); AST* node = rdr->get(); - if (node && Validate) { + if (node && !NoValidate) { if (!validate(node)) return 3; } From rspencer at reidspencer.com Tue Jun 27 15:53:06 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Tue, 27 Jun 2006 15:53:06 -0500 Subject: [hlvm-commits] r336 - in test: . invalid lib Message-ID: <200606272053.k5RKr67O007005@server1.hlvm.org> Author: reid Date: 2006-06-27 15:53:06 -0500 (Tue, 27 Jun 2006) New Revision: 336 Log: Rename "error" to "invalid" so as to more precisely label its function, that of testing invalid input to the compiler. Added: test/invalid/ test/lib/invalid.exp Removed: test/error/ test/lib/error.exp Modified: test/SConscript test/invalid/dg.exp Modified: test/SConscript =================================================================== --- test/SConscript 2006-06-27 20:01:30 UTC (rev 335) +++ test/SConscript 2006-06-27 20:53:06 UTC (rev 336) @@ -24,4 +24,4 @@ Import('env') if 'check' in COMMAND_LINE_TARGETS: from build import check - check.Check(env,['xml2xml','error','return0']) + check.Check(env,['xml2xml','invalid','return0']) Copied: test/invalid (from rev 334, test/error) Modified: test/invalid/dg.exp =================================================================== --- test/error/dg.exp 2006-06-26 19:45:41 UTC (rev 334) +++ test/invalid/dg.exp 2006-06-27 20:53:06 UTC (rev 336) @@ -1,3 +1,3 @@ -load_lib error.exp +load_lib invalid.exp -hlvm-error-tests hlvm-xml2xml "*.hlx" +hlvm-invalid-tests hlvm-xml2xml "*.hlx" Deleted: test/lib/error.exp =================================================================== --- test/lib/error.exp 2006-06-27 20:01:30 UTC (rev 335) +++ test/lib/error.exp 2006-06-27 20:53:06 UTC (rev 336) @@ -1,55 +0,0 @@ -#===-test/lib/error.exp - Script for error check tests ---------------------===# -# -# 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 -# -#===------------------------------------------------------------------------===# -proc hlvm-error-tests { prog pat } { - global srcdir subdir objdir tmpdir objrootdir - set outdir [file join $objdir $subdir] - set tool [file join $objrootdir tools $prog $prog ] - set source [file join $srcdir $subdir ] - set files [lsort [ - glob -nocomplain -tails -types {f r} -directory $source $pat]] - set dirs [lsort [ - glob -nocomplain -tails -types {d r} -directory $source *]] - - if { [file isdirectory $outdir] } { - cd $outdir - } else { - if { [file exists $outdir] } { - fail "identity: $outdir exists and is not a directory. Remove it" - exit(2) - } else { - file mkdir $outdir - } - } - - foreach test $files { - set output [file join $outdir ${test}.out] - set testsrc [file join $source $test] - set execout "" - set retval [ catch { exec -keepnewline $tool $testsrc -o $output } msg ] - if { $retval != 0 } { - pass "$test" - } else { - fail "$test: $tool return $retval\n$msg" - } - } -} Copied: test/lib/invalid.exp (from rev 334, test/lib/error.exp) =================================================================== --- test/lib/invalid.exp (rev 0) +++ test/lib/invalid.exp 2006-06-27 20:53:06 UTC (rev 336) @@ -0,0 +1,55 @@ +#===-test/lib/invalid.exp - Script for invalid input tests -----------------===# +# +# 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 +# +#===------------------------------------------------------------------------===# +proc hlvm-invalid-tests { prog pat } { + global srcdir subdir objdir tmpdir objrootdir + set outdir [file join $objdir $subdir] + set tool [file join $objrootdir tools $prog $prog ] + set source [file join $srcdir $subdir ] + set files [lsort [ + glob -nocomplain -tails -types {f r} -directory $source $pat]] + set dirs [lsort [ + glob -nocomplain -tails -types {d r} -directory $source *]] + + if { [file isdirectory $outdir] } { + cd $outdir + } else { + if { [file exists $outdir] } { + fail "identity: $outdir exists and is not a directory. Remove it" + exit(2) + } else { + file mkdir $outdir + } + } + + foreach test $files { + set output [file join $outdir ${test}.out] + set testsrc [file join $source $test] + set execout "" + set retval [ catch { exec -keepnewline $tool $testsrc -o $output } msg ] + if { $retval != 0 } { + pass "$test" + } else { + fail "$test: $tool return $retval\n$msg" + } + } +} From rspencer at reidspencer.com Tue Jun 27 16:15:30 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Tue, 27 Jun 2006 16:15:30 -0500 Subject: [hlvm-commits] r337 - test/invalid Message-ID: <200606272115.k5RLFUrZ007192@server1.hlvm.org> Author: reid Date: 2006-06-27 16:15:30 -0500 (Tue, 27 Jun 2006) New Revision: 337 Log: Add a test to ensure that blocks without results generate an error when the containing scope requires a result. Added: test/invalid/blockresult.hlx Added: test/invalid/blockresult.hlx =================================================================== --- test/invalid/blockresult.hlx (rev 0) +++ test/invalid/blockresult.hlx 2006-06-27 21:15:30 UTC (rev 337) @@ -0,0 +1,26 @@ + + + + + 0 + + + 1 + + + + + + + + + + + From rspencer at reidspencer.com Wed Jun 28 03:40:04 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Wed, 28 Jun 2006 03:40:04 -0500 Subject: [hlvm-commits] r338 - hlvm/AST hlvm/CodeGen hlvm/Pass hlvm/Reader hlvm/Writer test/invalid test/return0 test/xml2xml Message-ID: <200606280840.k5S8e4ZY009349@server1.hlvm.org> Author: reid Date: 2006-06-28 03:40:04 -0500 (Wed, 28 Jun 2006) New Revision: 338 Log: This patch gets 4 kinds of loop operators working. It also resolves numerous issues about blocks, their results, getting correct LLVM operands, etc. A number of new test cases were added to ensure its all working correctly. Added: test/invalid/funcresult.hlx test/return0/loop.hlx test/return0/noresult.hlx test/return0/resultoverride.hlx test/return0/unless.hlx test/return0/until.hlx test/return0/unused.hlx test/return0/while.hlx test/xml2xml/unless.hlx test/xml2xml/until.hlx test/xml2xml/while.hlx Modified: hlvm/AST/AST.cpp hlvm/AST/Block.h hlvm/AST/ControlFlow.cpp hlvm/AST/ControlFlow.h hlvm/AST/Node.h hlvm/CodeGen/LLVMGenerator.cpp hlvm/Pass/Validate.cpp hlvm/Reader/HLVM.rng hlvm/Reader/XMLReader.cpp hlvm/Writer/XMLWriter.cpp test/return0/arithmetic.hlx test/return0/bitwise.hlx test/return0/boolean.hlx test/return0/call.hlx test/return0/complement.hlx test/return0/return0.hlx test/return0/select.hlx test/xml2xml/break.hlx test/xml2xml/continue.hlx test/xml2xml/loop.hlx Modified: hlvm/AST/AST.cpp =================================================================== --- hlvm/AST/AST.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/AST/AST.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -1005,6 +1005,21 @@ return new_TernaryOp(op2->getType(),op1,op2,op3,loc); } +template WhileOp* +AST::new_BinaryOp(const Type* Ty, Operator* op1, Operator* op2, const Locator* loc); +template WhileOp* +AST::new_BinaryOp(Operator* op1, Operator* op2,const Locator* loc); + +template UnlessOp* +AST::new_BinaryOp(const Type* Ty, Operator* op1, Operator* op2, const Locator* loc); +template UnlessOp* +AST::new_BinaryOp(Operator* op1, Operator* op2,const Locator* loc); + +template UntilOp* +AST::new_BinaryOp(const Type* Ty, Operator* op1, Operator* op2, const Locator* loc); +template UntilOp* +AST::new_BinaryOp(Operator* op1, Operator* op2,const Locator* loc); + template LoopOp* AST::new_TernaryOp(const Type* Ty, Operator*op1,Operator*op2,Operator*op3,const Locator* loc); Modified: hlvm/AST/Block.h =================================================================== --- hlvm/AST/Block.h 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/AST/Block.h 2006-06-28 08:40:04 UTC (rev 338) @@ -61,7 +61,7 @@ virtual const Type* getType() const { return this->back()->getType(); } const std::string& getLabel() const { return label; } AutoVarOp* getAutoVar(const std::string& name) const; - const Type* getResultType() const { return result->getType(); } + const Type* getResultType() const { return (result?result->getType():0); } const Operator* getResult() const { return result; } Block* getParentBlock() const; bool isTerminated() const { Modified: hlvm/AST/ControlFlow.cpp =================================================================== --- hlvm/AST/ControlFlow.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/AST/ControlFlow.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -40,7 +40,67 @@ NullOp::~NullOp() {} SelectOp::~SelectOp() {} SwitchOp::~SwitchOp() {} +WhileOp::~WhileOp() {} +const Type* +WhileOp::getType() const +{ + hlvmAssert(getNumOperands() == 2); + Operator* op2 = getOperand(1); + if (Block* B = llvm::dyn_cast(op2)) { + if (const Type* Ty = B->getResultType()) + return Ty; + return 0; + } else { + return op2->getType(); + } +} + +UnlessOp::~UnlessOp() {} +const Type* +UnlessOp::getType() const +{ + hlvmAssert(getNumOperands() == 2); + Operator* op2 = getOperand(1); + if (Block* B = llvm::dyn_cast(op2)) { + if (const Type* Ty = B->getResultType()) + return Ty; + return 0; + } else { + return op2->getType(); + } +} + +UntilOp::~UntilOp() {} +const Type* +UntilOp::getType() const +{ + hlvmAssert(getNumOperands() == 2); + Operator* op1 = getOperand(0); + if (Block* B = llvm::dyn_cast(op1)) { + if (const Type* Ty = B->getResultType()) + return Ty; + return 0; + } else { + return op1->getType(); + } +} + LoopOp::~LoopOp() {} + +const Type* +LoopOp::getType() const +{ + hlvmAssert(getNumOperands() == 3); + Operator* op2 = getOperand(1); + if (Block* B = llvm::dyn_cast(op2)) { + if (const Type* Ty = B->getResultType()) + return Ty; + return 0; + } else { + return op2->getType(); + } +} + ReturnOp::~ReturnOp() { } BreakOp::~BreakOp() {} ContinueOp::~ContinueOp() {} Modified: hlvm/AST/ControlFlow.h =================================================================== --- hlvm/AST/ControlFlow.h 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/AST/ControlFlow.h 2006-06-28 08:40:04 UTC (rev 338) @@ -122,6 +122,94 @@ friend class AST; }; +/// This class prvoides an Abstract Syntax Tree node that represents a loop +/// construct with two operands. The first operand is a boolean expression +/// that is tested before each iteration. If the expression evaluates to false, +/// the loop terminates. The second operand is the expression or block to be +/// executed on each iteration. This is similar to a "while" loop in other +/// languages, hence the name. If the second operand declares a result, then +/// the value of that result on the final iteration is the value of the loop. +/// Otherwise the WhileOp may not be used as a value (has type void). +/// @brief AST While Loop Operator Node +class WhileOp : public BinaryOperator +{ + /// @name Constructors + /// @{ + protected: + WhileOp() : BinaryOperator(WhileOpID) {} + virtual ~WhileOp(); + + /// @} + /// @name Accessors + /// @{ + public: + virtual const Type* getType() const; + static inline bool classof(const WhileOp*) { return true; } + static inline bool classof(const Node* N) { return N->is(WhileOpID); } + + /// @} + friend class AST; +}; + +/// This class prvoides an Abstract Syntax Tree node that represents a loop +/// construct with two operands. The first operand is a boolean expression +/// that is tested before each iteration. If the expression evaluates to true, +/// the loop terminates. The second operand is the expression or block to be +/// executed on each iteration. This is similar to a "while" loop in other +/// languages, except the logic of the control expression is inverted. If the +/// second operand declares a result, then the value of that result on the +/// final iteration is the value of the loop. Otherwise the UnlessOp may +/// not be used as a value (has type void). +/// @brief AST Unless Loop Operator Node +class UnlessOp : public BinaryOperator +{ + /// @name Constructors + /// @{ + protected: + UnlessOp() : BinaryOperator(UnlessOpID) {} + virtual ~UnlessOp(); + + /// @} + /// @name Accessors + /// @{ + public: + virtual const Type* getType() const; + static inline bool classof(const UnlessOp*) { return true; } + static inline bool classof(const Node* N) { return N->is(UnlessOpID); } + + /// @} + friend class AST; +}; + +/// This class prvoides an Abstract Syntax Tree node that represents a loop +/// construct with two operands. The second operand is a boolean expression +/// that is tested after each iteration. If the expression evaluates to true, +/// the loop terminates. The first operand is the expression or block to be +/// executed on each iteration. This is similar to a "do" loop in other +/// languages. If the first operand declares a result, then the value of that +/// result on the final iteration is the value of the loop. Otherwise the +/// UntilOp may not be used as a value (has type void). +/// @brief AST Unless Loop Operator Node +class UntilOp : public BinaryOperator +{ + /// @name Constructors + /// @{ + protected: + UntilOp() : BinaryOperator(UntilOpID) {} + virtual ~UntilOp(); + + /// @} + /// @name Accessors + /// @{ + public: + virtual const Type* getType() const; + static inline bool classof(const UntilOp*) { return true; } + static inline bool classof(const Node* N) { return N->is(UntilOpID); } + + /// @} + friend class AST; +}; + /// This class provides an Abstract Syntax Tree node that represents a /// generalized loop construct for HLVM. The LoopOp takes three operands, as /// follows: @@ -131,9 +219,7 @@ /// loop. This is the main body of the loop /// -# a boolean expression to be evaluated after each iteration ends that /// controls loop termination -/// Either or both of the control expressions can be a NoOp operator in which -/// case the test is not performed. If both control expressions are NoOp, the -/// loop is infinite. +/// This construct is similar to combining a WhileOp with an UntilOp. /// @brief AST Loop Operator Node class LoopOp : public TernaryOperator { @@ -147,6 +233,7 @@ /// @name Accessors /// @{ public: + virtual const Type* getType() const; static inline bool classof(const LoopOp*) { return true; } static inline bool classof(const Node* N) { return N->is(LoopOpID); } Modified: hlvm/AST/Node.h =================================================================== --- hlvm/AST/Node.h 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/AST/Node.h 2006-06-28 08:40:04 UTC (rev 338) @@ -244,6 +244,11 @@ ReallocateOpID, ///< The Reallocate Memory Operator StoreOpID, ///< The Store Operator (store a value to a location) + // Binary Control Flow Operators + WhileOpID, ///< While expression is true loop + UnlessOpID, ///< Unless expression is true loop + UntilOpID, ///< Do block until expression is true loop + // Other Binary Operators OpenOpID, ///< Open a stream from a URL ReadOpID, ///< Read from a stream Modified: hlvm/CodeGen/LLVMGenerator.cpp =================================================================== --- hlvm/CodeGen/LLVMGenerator.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/CodeGen/LLVMGenerator.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -77,7 +77,7 @@ typedef std::vector ModuleList; typedef std::vector OperandList; typedef std::vector BlockStack; - typedef std::map ResultDictionary; + typedef std::map ResultsDictionary; typedef std::map VariableDictionary; typedef std::map AutoVarDictionary; typedef std::map @@ -89,7 +89,7 @@ llvm::BasicBlock* lblk; ///< The current LLVM block we're generating OperandList lops; ///< The current list of instruction operands BlockStack blocks; ///< The stack of blocks we're constructing - ResultDictionary results; ///< Dictionary of LLVM blocks to result values + ResultsDictionary results; ///< Dictionary of LLVM blocks to result values VariableDictionary gvars; ///< Dictionary of HLVM -> LLVM gvars AutoVarDictionary lvars; ///< Dictionary of HLVM -> LLVM auto vars llvm::TypeSymbolTable ltypes; ///< The cached LLVM types we've generated @@ -147,6 +147,12 @@ inline llvm::Value* toBoolean(llvm::Value* op); inline llvm::Value* ptr2Value(llvm::Value* op); inline llvm::Value* coerce(llvm::Value* op); + inline void saveOperand(llvm::Value* v, const Operator* op); + inline bool hasResult(llvm::BasicBlock* B) const; + llvm::AllocaInst* getBlockResult(llvm::BasicBlock* B, const char* name); + llvm::BasicBlock* getBodyBlock(llvm::Value* V, const std::string& name); + llvm::BasicBlock* getExpressionBlock( + llvm::Value* V, llvm::Value*& cond, const std::string& name); /// Accessors for HLVM Runtime Library things inline llvm::Type* get_hlvm_size(); @@ -706,6 +712,90 @@ return Load; } +void +LLVMGeneratorPass::saveOperand(llvm::Value* v, const Operator* op) +{ + if (op) + if (!llvm::isa(op->getParent())) + lops.push_back(v); +} + +bool +LLVMGeneratorPass::hasResult(llvm::BasicBlock* B) const +{ + if (B) { + ResultsDictionary::const_iterator I = results.find(B); + return I != results.end(); + } + return false; +} + +llvm::AllocaInst* +LLVMGeneratorPass::getBlockResult(llvm::BasicBlock* B, const char* name) +{ + if (hasResult(B)) { + const llvm::Type* Ty = results[B]->getType(); + llvm::AllocaInst* result = new llvm::AllocaInst( + /*Ty=*/ Ty, + /*ArraySize=*/ llvm::ConstantUInt::get(llvm::Type::UIntTy,1), + /*Name=*/ name, + /*InsertAtEnd=*/ lblk + ); + // Initialize the autovar to null + new llvm::StoreInst(llvm::Constant::getNullValue(Ty),result,lblk); + // Store the value on each iteration + new llvm::StoreInst(results[B],result,B); + return result; + } + return 0; +} + +llvm::BasicBlock* +LLVMGeneratorPass::getBodyBlock(llvm::Value* V, const std::string& name) +{ + llvm::BasicBlock* B = llvm::dyn_cast(V); + if (B) + return B; + B = new llvm::BasicBlock(name,lfunc); + if (llvm::Instruction* ins = llvm::dyn_cast(V)) { + ins->removeFromParent(); + B->getInstList().push_back(ins); + results[B] = ins; + } else { + // Its just a value or a constant or something, just cast it to itself + // so we can get its value + results[B] = new llvm::CastInst(V,V->getType(),name+"_result",B); + } + return B; +} + +llvm::BasicBlock* +LLVMGeneratorPass::getExpressionBlock( + llvm::Value* V, llvm::Value*& cond, const std::string& name) +{ + // Extract the condition value and make sure the condition expression is + // a block. + cond = 0; + llvm::BasicBlock* B = llvm::dyn_cast(V); + if (B) { + hlvmAssert(hasResult(B) && "No result in expression block?"); + cond = results[B]; + return B; + } + B = new llvm::BasicBlock(name,lfunc); + if (llvm::Instruction* ins = llvm::dyn_cast(V)) { + ins->removeFromParent(); + B->getInstList().push_back(ins); + cond = results[B] = V; + } else { + // Its just a value or a constant or something, just cast it to itself + // so we can get its value + cond = results[B] = new llvm::CastInst(V,V->getType(),name+"_result",B); + } + hlvmAssert(cond->getType() == llvm::Type::BoolTy); + return B; +} + template<> void LLVMGeneratorPass::gen(AutoVarOp* av) { @@ -752,7 +842,7 @@ } llvm::Value* store = new llvm::StoreInst(C,alloca,"",lblk); } - lops.push_back(alloca); + saveOperand(alloca,av); lvars[av] = alloca; } @@ -767,7 +857,7 @@ "Can't negate non-numeric"); llvm::BinaryOperator* neg = llvm::BinaryOperator::createNeg(operand,"neg",lblk); - lops.push_back(neg); + saveOperand(neg,op); } template<> void @@ -782,7 +872,7 @@ llvm::ConstantIntegral::getAllOnesValue(lType); llvm::BinaryOperator* cmpl = llvm::BinaryOperator::create( llvm::Instruction::Xor,operand,allOnes,"cmpl",lblk); - lops.push_back(cmpl); + saveOperand(cmpl,op); } template<> void @@ -791,16 +881,22 @@ hlvmAssert(lops.size() >= 1 && "Too few operands for PreIncrOp"); llvm::Value* operand = lops.back(); lops.pop_back(); const llvm::Type* lType = operand->getType(); + hlvmAssert(llvm::isa(lType)); + const llvm::PointerType* PT = llvm::cast(lType); + lType = PT->getElementType(); + llvm::LoadInst* load = new llvm::LoadInst(operand,"preincr",lblk); if (lType->isFloatingPoint()) { llvm::ConstantFP* one = llvm::ConstantFP::get(lType,1.0); llvm::BinaryOperator* add = llvm::BinaryOperator::create( - llvm::Instruction::Add, operand, one, "preincr", lblk); - lops.push_back(add); + llvm::Instruction::Add, load, one, "preincr", lblk); + new llvm::StoreInst(add,operand,"preincr",lblk); + saveOperand(add,op); } else if (lType->isInteger()) { llvm::ConstantInt* one = llvm::ConstantInt::get(lType,1); llvm::BinaryOperator* add = llvm::BinaryOperator::create( - llvm::Instruction::Add, operand, one, "preincr", lblk); - lops.push_back(add); + llvm::Instruction::Add, load, one, "preincr", lblk); + new llvm::StoreInst(add,operand,"preincr",lblk); + saveOperand(add,op); } else { hlvmAssert(!"PreIncrOp on non-numeric"); } @@ -812,16 +908,22 @@ hlvmAssert(lops.size() >= 1 && "Too few operands for PreDecrOp"); llvm::Value* operand = lops.back(); lops.pop_back(); const llvm::Type* lType = operand->getType(); + hlvmAssert(llvm::isa(lType)); + const llvm::PointerType* PT = llvm::cast(lType); + lType = PT->getElementType(); + llvm::LoadInst* load = new llvm::LoadInst(operand,"predecr",lblk); if (lType->isFloatingPoint()) { llvm::ConstantFP* one = llvm::ConstantFP::get(lType,1.0); llvm::BinaryOperator* sub = llvm::BinaryOperator::create( - llvm::Instruction::Sub, operand, one, "predecr", lblk); - lops.push_back(sub); + llvm::Instruction::Sub, load, one, "predecr", lblk); + new llvm::StoreInst(sub,operand,"predecr",lblk); + saveOperand(sub,op); } else if (lType->isInteger()) { llvm::ConstantInt* one = llvm::ConstantInt::get(lType,1); llvm::BinaryOperator* sub = llvm::BinaryOperator::create( - llvm::Instruction::Sub, operand, one, "predecr", lblk); - lops.push_back(sub); + llvm::Instruction::Sub, load, one, "predecr", lblk); + new llvm::StoreInst(sub,operand,"predecr",lblk); + saveOperand(sub,op); } else { hlvmAssert(!"PreIncrOp on non-numeric"); } @@ -831,12 +933,54 @@ LLVMGeneratorPass::gen(PostIncrOp* op) { hlvmAssert(lops.size() >= 1 && "Too few operands for PostIncrOp"); + llvm::Value* operand = lops.back(); lops.pop_back(); + const llvm::Type* lType = operand->getType(); + hlvmAssert(llvm::isa(lType)); + const llvm::PointerType* PT = llvm::cast(lType); + lType = PT->getElementType(); + llvm::LoadInst* load = new llvm::LoadInst(operand,"postincr",lblk); + if (lType->isFloatingPoint()) { + llvm::ConstantFP* one = llvm::ConstantFP::get(lType,1.0); + llvm::BinaryOperator* add = llvm::BinaryOperator::create( + llvm::Instruction::Add, load, one, "postincr", lblk); + new llvm::StoreInst(add,operand,"postincr",lblk); + saveOperand(load,op); + } else if (lType->isInteger()) { + llvm::ConstantInt* one = llvm::ConstantInt::get(lType,1); + llvm::BinaryOperator* add = llvm::BinaryOperator::create( + llvm::Instruction::Add, load, one, "postincr", lblk); + new llvm::StoreInst(add,operand,"postincr",lblk); + saveOperand(load,op); + } else { + hlvmAssert(!"PostDecrOp on non-numeric"); + } } template<> void LLVMGeneratorPass::gen(PostDecrOp* op) { hlvmAssert(lops.size() >= 1 && "Too few operands for PostDecrOp"); + llvm::Value* operand = lops.back(); lops.pop_back(); + const llvm::Type* lType = operand->getType(); + hlvmAssert(llvm::isa(lType)); + const llvm::PointerType* PT = llvm::cast(lType); + lType = PT->getElementType(); + llvm::LoadInst* load = new llvm::LoadInst(operand,"postincr",lblk); + if (lType->isFloatingPoint()) { + llvm::ConstantFP* one = llvm::ConstantFP::get(lType,1.0); + llvm::BinaryOperator* sub = llvm::BinaryOperator::create( + llvm::Instruction::Sub, load, one, "postdecr", lblk); + new llvm::StoreInst(sub,operand,"postdecr",lblk); + saveOperand(load,op); + } else if (lType->isInteger()) { + llvm::ConstantInt* one = llvm::ConstantInt::get(lType,1); + llvm::BinaryOperator* sub = llvm::BinaryOperator::create( + llvm::Instruction::Sub, load, one, "postdecr", lblk); + new llvm::StoreInst(sub,operand,"postdecr",lblk); + saveOperand(load,op); + } else { + hlvmAssert(!"PostDecrOp on non-numeric"); + } } template<> void @@ -849,7 +993,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* add = llvm::BinaryOperator::create( llvm::Instruction::Add, op1, op2, "add", lblk); - lops.push_back(add); + saveOperand(add,op); } template<> void @@ -862,7 +1006,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* sub = llvm::BinaryOperator::create( llvm::Instruction::Sub, op1, op2, "add", lblk); - lops.push_back(sub); + saveOperand(sub,op); } template<> void @@ -875,7 +1019,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* mul = llvm::BinaryOperator::create( llvm::Instruction::Mul, op1, op2, "mul", lblk); - lops.push_back(mul); + saveOperand(mul,op); } template<> void @@ -888,7 +1032,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* div = llvm::BinaryOperator::create( llvm::Instruction::Div, op1, op2, "div", lblk); - lops.push_back(div); + saveOperand(div,op); } template<> void @@ -901,7 +1045,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* rem = llvm::BinaryOperator::create( llvm::Instruction::Rem, op1, op2, "mod", lblk); - lops.push_back(rem); + saveOperand(rem,op); } template<> void @@ -914,7 +1058,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* band = llvm::BinaryOperator::create( llvm::Instruction::And, op1, op2, "band", lblk); - lops.push_back(band); + saveOperand(band,op); } template<> void @@ -927,7 +1071,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* bor = llvm::BinaryOperator::create( llvm::Instruction::Or, op1, op2, "bor", lblk); - lops.push_back(bor); + saveOperand(bor,op); } template<> void @@ -940,7 +1084,7 @@ op2 = ptr2Value(op2); llvm::BinaryOperator* Xor = llvm::BinaryOperator::create( llvm::Instruction::Xor, op1, op2, "bxor", lblk); - lops.push_back(Xor); + saveOperand(Xor,op); } template<> void @@ -954,7 +1098,7 @@ llvm::BinaryOperator* bor = llvm::BinaryOperator::create( llvm::Instruction::Or, op1, op2, "bnor", lblk); llvm::BinaryOperator* nor = llvm::BinaryOperator::createNot(bor,"bnor",lblk); - lops.push_back(nor); + saveOperand(nor,op); } template<> void @@ -971,7 +1115,7 @@ op1 = ptr2Value(op1); llvm::Value* b1 = toBoolean(op1); llvm::BinaryOperator* Not = llvm::BinaryOperator::createNot(b1,"not",lblk); - lops.push_back(Not); + saveOperand(Not,op); } template<> void @@ -986,7 +1130,7 @@ llvm::Value* b2 = toBoolean(op2); llvm::BinaryOperator* And = llvm::BinaryOperator::create( llvm::Instruction::And, b1, b2, "and", lblk); - lops.push_back(And); + saveOperand(And,op); } template<> void @@ -1001,7 +1145,7 @@ llvm::Value* b2 = toBoolean(op2); llvm::BinaryOperator* Or = llvm::BinaryOperator::create( llvm::Instruction::Or, b1, b2, "or", lblk); - lops.push_back(Or); + saveOperand(Or,op); } template<> void @@ -1017,7 +1161,7 @@ llvm::BinaryOperator* Or = llvm::BinaryOperator::create( llvm::Instruction::Or, b1, b2, "nor", lblk); llvm::BinaryOperator* Nor = llvm::BinaryOperator::createNot(Or,"nor",lblk); - lops.push_back(Nor); + saveOperand(Nor,op); } template<> void @@ -1032,7 +1176,7 @@ llvm::Value* b2 = toBoolean(op2); llvm::BinaryOperator* Xor = llvm::BinaryOperator::create( llvm::Instruction::Xor, b1, b2, "xor", lblk); - lops.push_back(Xor); + saveOperand(Xor,op); } template<> void @@ -1045,7 +1189,7 @@ op2 = ptr2Value(op2); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetEQ, op1,op2,"eq",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1058,7 +1202,7 @@ op2 = ptr2Value(op2); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetNE, op1,op2,"ne",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1069,7 +1213,7 @@ llvm::Value* op1 = lops.back(); lops.pop_back(); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetLT, op1,op2,"lt",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1080,7 +1224,7 @@ llvm::Value* op1 = lops.back(); lops.pop_back(); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetGT, op1,op2,"gt",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1091,7 +1235,7 @@ llvm::Value* op1 = lops.back(); lops.pop_back(); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetGE, op1,op2,"ge",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1102,7 +1246,7 @@ llvm::Value* op1 = lops.back(); lops.pop_back(); llvm::SetCondInst* SCI = new llvm::SetCondInst(llvm::Instruction::SetLE, op1,op2,"le",lblk); - lops.push_back(SCI); + saveOperand(SCI,op); } template<> void @@ -1112,7 +1256,6 @@ llvm::Value* op3 = lops.back(); lops.pop_back(); llvm::Value* op2 = lops.back(); lops.pop_back(); llvm::Value* op1 = lops.back(); lops.pop_back(); - hlvmAssert(op2->getType() == op2->getType()); hlvmAssert(llvm::isa(op2) == llvm::isa(op3)); @@ -1145,40 +1288,42 @@ // make sure that the two operand blocks are properly terminated. llvm::BasicBlock* BB2 = llvm::cast(op2); llvm::BasicBlock* BB3 = llvm::cast(op3); + // Neither block should have a terminator, they are expression blocks hlvmAssert(!BB2->getTerminator() && !BB3->getTerminator()); - // Create an auto variable to hold the result of the select. - llvm::AllocaInst* select_result = new llvm::AllocaInst( - /*Ty=*/ results[BB2]->getType(), - /*ArraySize=*/ llvm::ConstantUInt::get(llvm::Type::UIntTy,1), - /*Name=*/ "select_result", - /*InsertAtEnd=*/ lblk - ); + llvm::AllocaInst* select_result = getBlockResult(BB2,"select_result"); + // Set up the branch to terminate the current block new llvm::BranchInst(BB2,BB3,op1,lblk); + // Create the exit block llvm::BasicBlock* exit = new llvm::BasicBlock("select_exit",lfunc); + // Make the exit block the current block lblk = exit; - // Store the result of the "true" case into the autovar - new llvm::StoreInst(results[BB2],select_result,BB2); + // Branch to the exit block BB2->setName("select_true"); new llvm::BranchInst(exit,BB2); - // Store the result of the "false" case into the autovar - new llvm::StoreInst(results[BB3],select_result,BB3); + + // Store the result of the "false" case into the autovar, if we should + if (select_result) + new llvm::StoreInst(results[BB3],select_result,BB3); + // Branch to the exit block BB3->setName("select_false"); new llvm::BranchInst(exit,BB3); + // Load the result and put it on the operand stack - lops.push_back(new llvm::LoadInst(select_result,"select",exit)); + if (select_result) + saveOperand(new llvm::LoadInst(select_result,"select",exit),op); } else { // A this point, we can only be left with a first class type since all HLVM // operators translate to a first class type. Since the select operator // requires first class types, its okay to just use it here. hlvmAssert(op2->getType()->isFirstClassType()); hlvmAssert(op3->getType()->isFirstClassType()); - lops.push_back(new llvm::SelectInst(op1,op2,op3,"select",lblk)); + saveOperand(new llvm::SelectInst(op1,op2,op3,"select",lblk),op); } } @@ -1192,6 +1337,111 @@ } template<> void +LLVMGeneratorPass::gen(WhileOp* op) +{ + hlvmAssert(lops.size() >= 2 && "Too few operands for WhileOp"); + llvm::Value* op2 = lops.back(); lops.pop_back(); + llvm::Value* op1 = lops.back(); lops.pop_back(); + + // Get the body of the while loop + llvm::BasicBlock* B2 = getBodyBlock(op2,"while_body"); + + // If there's a result in the while body, get it now + llvm::AllocaInst* while_result = getBlockResult(B2,"while_result"); + + // Extract the condition value and make sure its in a block + llvm::Value* cond = 0; + llvm::BasicBlock* B1 = getExpressionBlock(op1,cond,"while_cond"); + + // Terminate the current block with a branch to the condition block + new llvm::BranchInst(B1,lblk); + + // Terminate the body with a branch back to the condition block + new llvm::BranchInst(B1,B2); + + // Create a new block for the exit from the while loop + lblk = new llvm::BasicBlock("while_exit",lfunc); + + // Create a conditional branch to either exit or repeat the loop. + new llvm::BranchInst(B2,lblk,cond,B1); + + // Deal with the result of the while loop, if it has one + if (while_result) { + lops.push_back(new llvm::LoadInst(while_result,"while_result",lblk)); + } +} + +template<> void +LLVMGeneratorPass::gen(UnlessOp* op) +{ + hlvmAssert(lops.size() >= 2 && "Too few operands for UnlessOp"); + llvm::Value* op2 = lops.back(); lops.pop_back(); + llvm::Value* op1 = lops.back(); lops.pop_back(); + + // Get the body block from the 2nd operand + llvm::BasicBlock* B2 = getBodyBlock(op2,"unless_body"); + + // If there's a result in the unless body, get it now + llvm::AllocaInst* unless_result = getBlockResult(B2,"unless_result"); + + // Get the condition expression + llvm::Value* cond = 0; + llvm::BasicBlock* B1 = getExpressionBlock(op1,cond,"unless_cond"); + + // Terminate the current block with a branch to the condition block + new llvm::BranchInst(B1,lblk); + + // Terminate the unless body with a branch back to the condition block + new llvm::BranchInst(B1,B2); + + // Create a new block for the exit from the while loop + lblk = new llvm::BasicBlock("unless_exit",lfunc); + + // Create a conditional branch to either exit or repeat the loop. + new llvm::BranchInst(lblk,B2,cond,B1); + + // Deal with the result of the unless loop, if it has one + if (unless_result) { + lops.push_back(new llvm::LoadInst(unless_result,"unless_result",lblk)); + } +} + +template<> void +LLVMGeneratorPass::gen(UntilOp* op) +{ + hlvmAssert(lops.size() >= 2 && "Too few operands for UntilOp"); + llvm::Value* op2 = lops.back(); lops.pop_back(); + llvm::Value* op1 = lops.back(); lops.pop_back(); + + // Get the body of the block + llvm::BasicBlock* B1 = getBodyBlock(op1,"until_body"); + + // If there's a result in the until body, get it now + llvm::AllocaInst* until_result = getBlockResult(B1,"until_result"); + + // Get the condition expression + llvm::Value* cond = 0; + llvm::BasicBlock* B2 = getExpressionBlock(op2,cond,"until_cond"); + + // Branch the current block into the body of the loop + new llvm::BranchInst(B1,lblk); + + // Terminate the body with a branch forward to the condition block + new llvm::BranchInst(B2,B1); + + // Create a new block for the exit from the loop + lblk = new llvm::BasicBlock("until_exit",lfunc); + + // Create a conditional branch to either exit or repeat the loop. + new llvm::BranchInst(B1,lblk,cond,B2); + + // Deal with the result of the until loop, if it has one + if (until_result) { + lops.push_back(new llvm::LoadInst(until_result,"until_result",lblk)); + } +} + +template<> void LLVMGeneratorPass::gen(LoopOp* op) { hlvmAssert(lops.size() >= 3 && "Too few operands for LoopOp"); @@ -1199,6 +1449,39 @@ llvm::Value* op2 = lops.back(); lops.pop_back(); llvm::Value* op1 = lops.back(); lops.pop_back(); + // Get the body of the loop + llvm::BasicBlock* B2 = getBodyBlock(op2,"loop_body"); + + // If there's a result in the loop body, get it now + llvm::AllocaInst* loop_result = getBlockResult(B2,"loop_result"); + + // Extract the loop start condition expression + llvm::Value* start_cond = 0; + llvm::BasicBlock* B1 = getExpressionBlock(op1,start_cond,"loop_start_cond"); + + // Extract the loop end condition expression + llvm::Value* end_cond = 0; + llvm::BasicBlock* B3 = getExpressionBlock(op3,end_cond,"loop_end_cond"); + + // Terminate the current block with a branch to the start condition block + new llvm::BranchInst(B1,lblk); + + // Terminate the body with a branch to the end_condition block + new llvm::BranchInst(B3,B2); + + // Create a new block for the exit from the while loop + lblk = new llvm::BasicBlock("loop_exit",lfunc); + + // Terminate the start condition with a conditional branch + new llvm::BranchInst(B2,lblk,start_cond,B1); + + // Terminate the end condition with a conditional branch + new llvm::BranchInst(B1,lblk,end_cond,B3); + + // Deal with the result of the loop, if it has one + if (loop_result) { + lops.push_back(new llvm::LoadInst(loop_result,"loop_result",lblk)); + } } template<> void @@ -1260,7 +1543,7 @@ hlvmAssert(llvm::isa(arg)); llvm::Function* F = const_cast( llvm::cast(arg)); - lops.push_back(new llvm::CallInst(F,args,"call_" + hFunc->getName(),lblk)); + saveOperand(new llvm::CallInst(F,args,"call_" + hFunc->getName(),lblk),co); } template<> void @@ -1269,15 +1552,15 @@ hlvmAssert(lops.size() >= 2 && "Too few operands for StoreOp"); llvm::Value* value = lops.back(); lops.pop_back(); llvm::Value* location = lops.back(); lops.pop_back(); - lops.push_back(new llvm::StoreInst(value,location,lblk)); + saveOperand(new llvm::StoreInst(value,location,lblk),s); } template<> void -LLVMGeneratorPass::gen(LoadOp* s) +LLVMGeneratorPass::gen(LoadOp* l) { hlvmAssert(lops.size() >= 1 && "Too few operands for LoadOp"); llvm::Value* location = lops.back(); lops.pop_back(); - lops.push_back(new llvm::LoadInst(location,"",lblk)); + saveOperand(new llvm::LoadInst(location,"",lblk),l); } template<> void @@ -1313,7 +1596,7 @@ } else hlvmDeadCode("Referent not a linkable or autovar?"); - lops.push_back(v); + saveOperand(v,r); } template<> void @@ -1348,7 +1631,7 @@ hlvmAssert(!"OpenOp parameter is not a pointer"); llvm::CallInst* ci = new llvm::CallInst(get_hlvm_stream_open(), args, "", lblk); - lops.push_back(ci); + saveOperand(ci,o); } template<> void @@ -1363,14 +1646,14 @@ if (llvm::isa(arg2->getType())) if (llvm::cast(arg2->getType())->getElementType() == llvm::Type::SByteTy) - lops.push_back( - new llvm::CallInst(get_hlvm_stream_write_string(), args, "", lblk)); + saveOperand( + new llvm::CallInst(get_hlvm_stream_write_string(), args, "", lblk),o); if (arg2->getType() == get_hlvm_text()) - lops.push_back( - new llvm::CallInst(get_hlvm_stream_write_text(), args, "", lblk)); + saveOperand( + new llvm::CallInst(get_hlvm_stream_write_text(), args, "", lblk),o); else if (arg2->getType() == get_hlvm_buffer()) - lops.push_back( - new llvm::CallInst(get_hlvm_stream_write_buffer(), args, "",lblk)); + saveOperand( + new llvm::CallInst(get_hlvm_stream_write_buffer(), args, "",lblk),o); } template<> void @@ -1382,7 +1665,7 @@ lops.erase(lops.end()-3,lops.end()); llvm::CallInst* ci = new llvm::CallInst(get_hlvm_stream_read(), args, "", lblk); - lops.push_back(ci); + saveOperand(ci,o); } template<> void @@ -1393,7 +1676,7 @@ args.push_back(lops.back()); lops.pop_back(); llvm::CallInst* ci = new llvm::CallInst(get_hlvm_stream_close(), args, "", lblk); - lops.push_back(ci); + saveOperand(ci,o); } void @@ -1600,6 +1883,9 @@ case LessEqualOpID: gen(llvm::cast(n)); break; case SelectOpID: gen(llvm::cast(n)); break; case SwitchOpID: gen(llvm::cast(n)); break; + case WhileOpID: gen(llvm::cast(n)); break; + case UnlessOpID: gen(llvm::cast(n)); break; + case UntilOpID: gen(llvm::cast(n)); break; case LoopOpID: gen(llvm::cast(n)); break; case BreakOpID: gen(llvm::cast(n)); break; case ContinueOpID: gen(llvm::cast(n)); break; Modified: hlvm/Pass/Validate.cpp =================================================================== --- hlvm/Pass/Validate.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/Pass/Validate.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -67,7 +67,7 @@ inline bool checkUniformContainer(UniformContainerType* T, NodeIDs id); inline bool checkDisparateContainer(DisparateContainerType* T, NodeIDs id); inline bool checkLinkable(Linkable* LI, NodeIDs id); - inline bool checkExpressionBlock(const Block* B); + inline bool checkExpressionBlock(const Block* B,bool optional = false); template inline void validate(NodeClass* C); @@ -148,10 +148,6 @@ error(v,"Bad ID for a Value"); result = false; } - if (v->getType() == 0) { - error(v,"Value with no type"); - result = false; - } return result; } @@ -251,14 +247,21 @@ } bool -ValidateImpl::checkExpressionBlock(const Block* B) +ValidateImpl::checkExpressionBlock(const Block* B, bool optional) { bool result = true; if (!B->getResult()) { - error(B,"Expression block without result"); - result = false; + if (optional) { + if (!isa(B->getParent()->getParent())) { + error(B,"Block has no result, but its use expects a result"); + result = false; + } + } else { + error(B,"Expression block without result"); + result = false; + } } - if (B->isTerminated()) { + if (!optional && B->isTerminated()) { error(B,"Expression blocks cannot have terminators"); result = false; } @@ -548,8 +551,6 @@ } else if (result) { if (n == n->getContainingFunction()->getBlock()) error(result,"Function's main block has result but no return"); - } else { - error(n,"Block does not contain a result or terminator"); } } } @@ -565,6 +566,10 @@ ValidateImpl::validate(ResultOp* n) { if (checkOperator(n,ResultOpID,1)) { + if (!isa(n->getParent())) { + error(n, "ResultOp not in a Block"); + return; + } const Function* F = n->getContainingFunction(); if (!F) error(n,"ResultOp not in Function!"); @@ -573,10 +578,19 @@ if (!B) error(n,"ResultOp not in a Block"); else if (F->getBlock() == B) { - const SignatureType* SigTy = F->getSignature(); - Operator* res = n->getOperand(0); - if (res->getType() != SigTy->getResultType()) - error(n,"Operand does not agree in type with Function result"); + const SignatureType* SigTy = F->getSignature(); + Operator* res = n->getOperand(0); + if (res) { + if (res->getType()) { + if (res->getType() != SigTy->getResultType()) + error(n,"Result does not agree in type with Function result"); + } else if (SigTy->getResultType() != + ast->getPrimitiveType(VoidTypeID)) { + error(n,"Void function result for non-void function"); + } + } else { + error(n,"Result operator with no operand"); + } } } } @@ -627,13 +641,58 @@ error(n,"SelectOp requires operands 2 and 3 to both be blocks or " "neither be blocks"); if (isa(Op2)) - checkExpressionBlock(cast(Op2)); + checkExpressionBlock(cast(Op2),true); if (isa(Op3)) - checkExpressionBlock(cast(Op3)); + checkExpressionBlock(cast(Op3),true); } } template<> inline void +ValidateImpl::validate(WhileOp* n) +{ + if (checkOperator(n,WhileOpID,2)) { + const Operator* Op1 = n->getOperand(0); + const Operator* Op2 = n->getOperand(1); + if (!isa(Op1->getType())) + error(n,"WhileOp expects first operand to be type boolean"); + if (const Block* B1 = dyn_cast(Op1)) + checkExpressionBlock(B1); + if (const Block* B2 = dyn_cast(Op2)) + checkExpressionBlock(B2,true); + } +} + +template<> inline void +ValidateImpl::validate(UnlessOp* n) +{ + if (checkOperator(n,UnlessOpID,2)) { + const Operator* Op1 = n->getOperand(0); + const Operator* Op2 = n->getOperand(1); + if (!isa(Op1->getType())) + error(n,"WhileOp expects first operand to be type boolean"); + if (const Block* B1 = dyn_cast(Op1)) + checkExpressionBlock(B1); + if (const Block* B2 = dyn_cast(Op2)) + checkExpressionBlock(B2,true); + } +} + +template<> inline void +ValidateImpl::validate(UntilOp* n) +{ + if (checkOperator(n,UntilOpID,2)) { + const Operator* Op1 = n->getOperand(0); + const Operator* Op2 = n->getOperand(1); + if (!isa(Op2->getType())) + error(n,"WhileOp expects second operand to be type boolean"); + if (const Block* B1 = dyn_cast(Op1)) + checkExpressionBlock(B1,true); + if (const Block* B2 = dyn_cast(Op2)) + checkExpressionBlock(B2); + } +} + +template<> inline void ValidateImpl::validate(LoopOp* n) { if (checkOperator(n,LoopOpID,3)) { @@ -642,14 +701,17 @@ const Operator* Op3 = n->getOperand(2); const Type* Ty1 = Op1->getType(); const Type* Ty3 = Op3->getType(); - if (!isa(Ty1) && !isa(Ty1)) - error(n,"LoopOp expects first operand to be type boolean or void"); - if (!isa(Ty3) && !isa(Ty3)) - error(n,"LoopOp expects third operand to be type boolean or void"); + if (!isa(Ty1)) + error(n,"LoopOp expects first operand to be type boolean"); + if (!isa(Ty3)) + error(n,"LoopOp expects third operand to be type boolean"); if (isa(Op1)) checkExpressionBlock(cast(Op1)); if (isa(Op3)) checkExpressionBlock(cast(Op3)); + if (const Block* B = dyn_cast(Op2)) + checkExpressionBlock(B,true); + } } @@ -1346,6 +1408,9 @@ case ContinueOpID: validate(cast(n)); break; case BreakOpID: validate(cast(n)); break; case SelectOpID: validate(cast(n)); break; + case WhileOpID: validate(cast(n)); break; + case UnlessOpID: validate(cast(n)); break; + case UntilOpID: validate(cast(n)); break; case LoopOpID: validate(cast(n)); break; case SwitchOpID: validate(cast(n)); break; case LoadOpID: validate(cast(n)); break; Modified: hlvm/Reader/HLVM.rng =================================================================== --- hlvm/Reader/HLVM.rng 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/Reader/HLVM.rng 2006-06-28 08:40:04 UTC (rev 338) @@ -1049,6 +1049,9 @@ + + + @@ -1079,6 +1082,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + Modified: hlvm/Reader/XMLReader.cpp =================================================================== --- hlvm/Reader/XMLReader.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/Reader/XMLReader.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -1099,6 +1099,9 @@ case TKN_le: op = parseBinaryOp(cur); break; case TKN_select: op = parseTernaryOp(cur); break; case TKN_switch: op = parseMultiOp(cur); break; + case TKN_while: op = parseBinaryOp(cur); break; + case TKN_unless: op = parseBinaryOp(cur); break; + case TKN_until: op = parseBinaryOp(cur); break; case TKN_loop: op = parseTernaryOp(cur); break; case TKN_break: op = parseNilaryOp(cur); break; case TKN_continue: op = parseNilaryOp(cur); break; Modified: hlvm/Writer/XMLWriter.cpp =================================================================== --- hlvm/Writer/XMLWriter.cpp 2006-06-27 21:15:30 UTC (rev 337) +++ hlvm/Writer/XMLWriter.cpp 2006-06-28 08:40:04 UTC (rev 338) @@ -693,6 +693,27 @@ } template<> void +XMLWriterImpl::WriterPass::put(WhileOp* op) +{ + startElement("while"); + putDoc(op); +} + +template<> void +XMLWriterImpl::WriterPass::put(UnlessOp* op) +{ + startElement("unless"); + putDoc(op); +} + +template<> void +XMLWriterImpl::WriterPass::put(UntilOp* op) +{ + startElement("until"); + putDoc(op); +} + +template<> void XMLWriterImpl::WriterPass::put(LoopOp* op) { startElement("loop"); @@ -855,6 +876,9 @@ case NullOpID: put(cast(n)); break; case SelectOpID: put(cast(n)); break; case SwitchOpID: put(cast(n)); break; + case WhileOpID: put(cast(n)); break; + case UnlessOpID: put(cast(n)); break; + case UntilOpID: put(cast(n)); break; case LoopOpID: put(cast(n)); break; case BreakOpID: put(cast(n)); break; case ContinueOpID: put(cast(n)); break; Added: test/invalid/funcresult.hlx =================================================================== --- test/invalid/funcresult.hlx (rev 0) +++ test/invalid/funcresult.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,16 @@ + + + + + 1 + + + + + + + + + + + Modified: test/return0/arithmetic.hlx =================================================================== --- test/return0/arithmetic.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/arithmetic.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + 42 7 Modified: test/return0/bitwise.hlx =================================================================== --- test/return0/bitwise.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/bitwise.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + 0f0f0f0f 08080808 Modified: test/return0/boolean.hlx =================================================================== --- test/return0/boolean.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/boolean.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + Modified: test/return0/call.hlx =================================================================== --- test/return0/call.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/call.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + 0 Modified: test/return0/complement.hlx =================================================================== --- test/return0/complement.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/complement.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + Added: test/return0/loop.hlx =================================================================== --- test/return0/loop.hlx (rev 0) +++ test/return0/loop.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,29 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + + + + + Added: test/return0/noresult.hlx =================================================================== --- test/return0/noresult.hlx (rev 0) +++ test/return0/noresult.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,27 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + Added: test/return0/resultoverride.hlx =================================================================== --- test/return0/resultoverride.hlx (rev 0) +++ test/return0/resultoverride.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,18 @@ + + + + 0 + 1 + + + + + + + + + + + + + Modified: test/return0/return0.hlx =================================================================== --- test/return0/return0.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/return0.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + 0 Modified: test/return0/select.hlx =================================================================== --- test/return0/select.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/return0/select.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,5 +1,5 @@ - + 0 21 Added: test/return0/unless.hlx =================================================================== --- test/return0/unless.hlx (rev 0) +++ test/return0/unless.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,25 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + Added: test/return0/until.hlx =================================================================== --- test/return0/until.hlx (rev 0) +++ test/return0/until.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,25 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + Added: test/return0/unused.hlx =================================================================== --- test/return0/unused.hlx (rev 0) +++ test/return0/unused.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,27 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + Added: test/return0/while.hlx =================================================================== --- test/return0/while.hlx (rev 0) +++ test/return0/while.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,25 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + Modified: test/xml2xml/break.hlx =================================================================== --- test/xml2xml/break.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/xml2xml/break.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,17 +1,20 @@ + + + 0 - + - + Modified: test/xml2xml/continue.hlx =================================================================== --- test/xml2xml/continue.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/xml2xml/continue.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,17 +1,20 @@ + + + 0 - + - + Modified: test/xml2xml/loop.hlx =================================================================== --- test/xml2xml/loop.hlx 2006-06-27 21:15:30 UTC (rev 337) +++ test/xml2xml/loop.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -1,6 +1,9 @@ + + + 0 @@ -16,7 +19,7 @@ - + Added: test/xml2xml/unless.hlx =================================================================== --- test/xml2xml/unless.hlx (rev 0) +++ test/xml2xml/unless.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,26 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + + Added: test/xml2xml/until.hlx =================================================================== --- test/xml2xml/until.hlx (rev 0) +++ test/xml2xml/until.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,26 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + + Added: test/xml2xml/while.hlx =================================================================== --- test/xml2xml/while.hlx (rev 0) +++ test/xml2xml/while.hlx 2006-06-28 08:40:04 UTC (rev 338) @@ -0,0 +1,26 @@ + + + + + 0 + + + 1 + + + + + + + + + + + + + + + + + + From rspencer at reidspencer.com Wed Jun 28 14:12:35 2006 From: rspencer at reidspencer.com (rspencer at reidspencer.com) Date: Wed, 28 Jun 2006 14:12:35 -0500 Subject: [hlvm-commits] r339 - hlvm/Pass Message-ID: <200606281912.k5SJCZOY015550@server1.hlvm.org> Author: reid Date: 2006-06-28 14:12:34 -0500 (Wed, 28 Jun 2006) New Revision: 339 Log: Refactor the block checking code to make it easier to understand and reduce code size. No functionality changes. Modified: hlvm/Pass/Validate.cpp Modified: hlvm/Pass/Validate.cpp =================================================================== --- hlvm/Pass/Validate.cpp 2006-06-28 08:40:04 UTC (rev 338) +++ hlvm/Pass/Validate.cpp 2006-06-28 19:12:34 UTC (rev 339) @@ -67,7 +67,10 @@ inline bool checkUniformContainer(UniformContainerType* T, NodeIDs id); inline bool checkDisparateContainer(DisparateContainerType* T, NodeIDs id); inline bool checkLinkable(Linkable* LI, NodeIDs id); - inline bool checkExpressionBlock(const Block* B,bool optional = false); + inline bool checkExpression(const Operator* op); + inline bool checkBooleanExpression(const Operator* op); + inline bool checkIntegralExpression(const Operator* op); + inline bool checkResult(const Operator* op); template inline void validate(NodeClass* C); @@ -246,25 +249,69 @@ return result; } -bool -ValidateImpl::checkExpressionBlock(const Block* B, bool optional) +bool +ValidateImpl::checkExpression(const Operator* op) { bool result = true; - if (!B->getResult()) { - if (optional) { - if (!isa(B->getParent()->getParent())) { - error(B,"Block has no result, but its use expects a result"); + if (const Block* B = dyn_cast(op)) { + if (const Operator* block_result = B->getResult()) { + if (!block_result->getType()) { + error(op,"Block with void result used where expression expected"); result = false; } } else { - error(B,"Expression block without result"); + error(op,"Block without result used where expression expected"); result = false; } - } - if (!optional && B->isTerminated()) { - error(B,"Expression blocks cannot have terminators"); + if (B->isTerminated()){ + error(op,"Terminator found in block used as an expression"); + result = false; + } + } else if (!op->getType()) { + error(op,"Operator with void result used where expression expected"); result = false; } + return result; +} + +bool +ValidateImpl::checkBooleanExpression(const Operator* op) +{ + if (checkExpression(op)) + if (!isa(op->getType())) { + error(op,std::string("Expecting boolean expression but type '") + + op->getType()->getName() + "' was found"); + return false; + } else + return true; + return false; +} + +bool +ValidateImpl::checkIntegralExpression(const Operator* op) +{ + if (checkExpression(op)) + if (!op->getType()->isIntegralType()) { + error(op,std::string("Expecting integral expression but type '") + + op->getType()->getName() + "' was found"); + return false; + } else + return true; + return false; +} + +bool +ValidateImpl::checkResult(const Operator* op) +{ + if (const Block* B = dyn_cast(op)) { + if (!B->getResult() && !isa(B->getParent()->getParent())) { + error(B,"Block with no result used where an expression is expected"); + return false; + } + } else if (!op->getType() && !isa(op->getParent()->getParent())) { + error(op,"Operator with void result used where an expression is expected"); + return false; + } return true; } @@ -628,22 +675,11 @@ Operator* Op1 = n->getOperand(0); Operator* Op2 = n->getOperand(1); Operator* Op3 = n->getOperand(2); - const Type* Ty1 = Op1->getType(); - const Type* Ty2 = Op2->getType(); - const Type* Ty3 = Op3->getType(); - if (!isa(Ty1)) - error(n,"SelectOp expects first operand to be type boolean"); - if (isa(Op1)) - checkExpressionBlock(cast(Op1)); - if (Ty2