diff options
-rw-r--r-- | Compiler.cpp | 15 | ||||
-rw-r--r-- | Compiler.h | 6 | ||||
-rw-r--r-- | CompilerStack.cpp | 4 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 26 | ||||
-rw-r--r-- | ExpressionCompiler.h | 7 | ||||
-rw-r--r-- | Token.h | 2 |
6 files changed, 42 insertions, 18 deletions
diff --git a/Compiler.cpp b/Compiler.cpp index b094af19..d41bcffa 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -246,7 +246,7 @@ bool Compiler::visit(FunctionDefinition const& _function) bool Compiler::visit(IfStatement const& _ifStatement) { - ExpressionCompiler::compileExpression(m_context, _ifStatement.getCondition()); + compileExpression(_ifStatement.getCondition()); eth::AssemblyItem trueTag = m_context.appendConditionalJump(); if (_ifStatement.getFalseStatement()) _ifStatement.getFalseStatement()->accept(*this); @@ -265,7 +265,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement) m_breakTags.push_back(loopEnd); m_context << loopStart; - ExpressionCompiler::compileExpression(m_context, _whileStatement.getCondition()); + compileExpression(_whileStatement.getCondition()); m_context << eth::Instruction::ISZERO; m_context.appendConditionalJumpTo(loopEnd); @@ -298,7 +298,7 @@ bool Compiler::visit(Return const& _return) //@todo modifications are needed to make this work with functions returning multiple values if (Expression const* expression = _return.getExpression()) { - ExpressionCompiler::compileExpression(m_context, *expression); + compileExpression(*expression); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); @@ -312,7 +312,7 @@ bool Compiler::visit(VariableDefinition const& _variableDefinition) { if (Expression const* expression = _variableDefinition.getExpression()) { - ExpressionCompiler::compileExpression(m_context, *expression); + compileExpression(*expression); ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *_variableDefinition.getDeclaration().getType()); @@ -324,10 +324,15 @@ bool Compiler::visit(VariableDefinition const& _variableDefinition) bool Compiler::visit(ExpressionStatement const& _expressionStatement) { Expression const& expression = _expressionStatement.getExpression(); - ExpressionCompiler::compileExpression(m_context, expression); + compileExpression(expression); CompilerUtils(m_context).popStackElement(*expression.getType()); return false; } +void Compiler::compileExpression(Expression const& _expression) +{ + ExpressionCompiler::compileExpression(m_context, _expression, m_optimize); +} + } } @@ -30,10 +30,10 @@ namespace solidity { class Compiler: private ASTConstVisitor { public: - Compiler(): m_returnTag(m_context.newTag()) {} + explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_returnTag(m_context.newTag()) {} void compileContract(ContractDefinition const& _contract, std::vector<MagicVariableDeclaration const*> const& _magicGlobals); - bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); } + bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } private: @@ -57,7 +57,9 @@ private: virtual bool visit(VariableDefinition const& _variableDefinition) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; + void compileExpression(Expression const& _expression); + bool const m_optimize; CompilerContext m_context; std::vector<eth::AssemblyItem> m_breakTags; ///< tag to jump to for a "break" statement std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement diff --git a/CompilerStack.cpp b/CompilerStack.cpp index d4675485..7aaa79b1 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -101,10 +101,10 @@ void CompilerStack::compile(bool _optimize) if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) { m_globalContext->setCurrentContract(*contract); - shared_ptr<Compiler> compiler = make_shared<Compiler>(); + shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize); compiler->compileContract(*contract, m_globalContext->getMagicVariables()); Contract& compiledContract = m_contracts[contract->getName()]; - compiledContract.bytecode = compiler->getAssembledBytecode(_optimize); + compiledContract.bytecode = compiler->getAssembledBytecode(); compiledContract.compiler = move(compiler); } } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index a0b0a54a..a19c9cfd 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -33,9 +33,9 @@ using namespace std; namespace dev { namespace solidity { -void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression const& _expression) +void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize) { - ExpressionCompiler compiler(_context); + ExpressionCompiler compiler(_context, _optimize); _expression.accept(compiler); } @@ -145,10 +145,24 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) cleanupNeeded = true; - rightExpression.accept(*this); - appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); - leftExpression.accept(*this); - appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); + // for commutative operators, push the literal as late as possible to allow improved optimization + //@todo this has to be extended for literal expressions + bool swap = (m_optimize && Token::isCommutativeOp(op) && dynamic_cast<Literal const*>(&rightExpression) + && !dynamic_cast<Literal const*>(&leftExpression)); + if (swap) + { + leftExpression.accept(*this); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); + rightExpression.accept(*this); + appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); + } + else + { + rightExpression.accept(*this); + appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); + leftExpression.accept(*this); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); + } if (Token::isCompareOp(op)) appendCompareOperatorCode(op, commonType); else diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 41cb6676..fb4577c8 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -45,14 +45,14 @@ class ExpressionCompiler: private ASTConstVisitor { public: /// Compile the given @a _expression into the @a _context. - static void compileExpression(CompilerContext& _context, Expression const& _expression); + static void compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize = false); /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); private: - ExpressionCompiler(CompilerContext& _compilerContext): - m_context(_compilerContext), m_currentLValue(m_context) {} + explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): + m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} virtual bool visit(Assignment const& _assignment) override; virtual void endVisit(UnaryOperation const& _unaryOperation) override; @@ -132,6 +132,7 @@ private: unsigned m_stackSize; }; + bool m_optimize; CompilerContext& m_context; LValue m_currentLValue; }; @@ -317,6 +317,8 @@ public: static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; } static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } + static bool isCommutativeOp(Value op) { return op == BIT_OR || op == BIT_XOR || op == BIT_AND || + op == ADD || op == MUL || op == EQ || op == NE; } static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; } static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } |