User-defined operators: Code generation

This commit is contained in:
wechman 2022-07-06 09:17:59 +02:00 committed by Kamil Śliwak
parent 5b03c13f90
commit 1a83fa7ebc
2 changed files with 117 additions and 1 deletions

View File

@ -410,6 +410,38 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
{
CompilerContext::LocationSetter locationSetter(m_context, _unaryOperation);
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
if (function)
{
solAssert(function->isFree());
FunctionType const* functionType = _unaryOperation.userDefinedFunctionType();
solAssert(functionType);
solAssert(functionType->parameterTypes().size() == 1);
solAssert(functionType->returnParameterTypes().size() == 1);
solAssert(functionType->kind() == FunctionType::Kind::Internal);
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
acceptAndConvert(
_unaryOperation.subExpression(),
*functionType->parameterTypes()[0],
false // _cleanupNeeded
);
m_context << m_context.functionEntryLabel(*function).pushTag();
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
m_context << returnLabel;
unsigned parameterSize = CompilerUtils::sizeOnStack(functionType->parameterTypes());
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
// callee adds return parameters, but removes arguments and return label
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
return false;
}
Type const& type = *_unaryOperation.annotation().type;
if (type.category() == Type::Category::RationalNumber)
{
@ -502,7 +534,42 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
CompilerContext::LocationSetter locationSetter(m_context, _binaryOperation);
Expression const& leftExpression = _binaryOperation.leftExpression();
Expression const& rightExpression = _binaryOperation.rightExpression();
solAssert(!!_binaryOperation.annotation().commonType, "");
FunctionDefinition const* function = *_binaryOperation.annotation().userDefinedFunction;
if (function)
{
solAssert(function->isFree());
FunctionType const* functionType = _binaryOperation.userDefinedFunctionType();
solAssert(functionType);
solAssert(functionType->parameterTypes().size() == 2);
solAssert(functionType->returnParameterTypes().size() == 1);
solAssert(functionType->kind() == FunctionType::Kind::Internal);
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
acceptAndConvert(
leftExpression,
*functionType->parameterTypes()[0],
false // _cleanupNeeded
);
acceptAndConvert(
rightExpression,
*functionType->parameterTypes()[1],
false // _cleanupNeeded
);
m_context << m_context.functionEntryLabel(*function).pushTag();
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
m_context << returnLabel;
unsigned parameterSize = CompilerUtils::sizeOnStack(functionType->parameterTypes());
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
// callee adds return parameters, but removes arguments and return label
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
return false;
}
solAssert(!!_binaryOperation.annotation().commonType);
Type const* commonType = _binaryOperation.annotation().commonType;
Token const c_op = _binaryOperation.getOperator();

View File

@ -672,6 +672,30 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
{
setLocation(_unaryOperation);
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
if (function)
{
_unaryOperation.subExpression().accept(*this);
setLocation(_unaryOperation);
solAssert(function->isImplemented());
solAssert(function->isFree());
solAssert(function->parameters().size() == 1);
solAssert(function->returnParameters().size() == 1);
solAssert(*function->returnParameters()[0]->type() == *_unaryOperation.annotation().type);
string argument = expressionAsType(_unaryOperation.subExpression(), *function->parameters()[0]->type());
solAssert(!argument.empty());
solAssert(_unaryOperation.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
define(_unaryOperation) <<
m_context.enqueueFunctionForCodeGeneration(*function) <<
("(" + argument + ")\n");
return false;
}
Type const& resultType = type(_unaryOperation);
Token const op = _unaryOperation.getOperator();
@ -775,6 +799,31 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{
setLocation(_binOp);
FunctionDefinition const* function = *_binOp.annotation().userDefinedFunction;
if (function)
{
_binOp.leftExpression().accept(*this);
_binOp.rightExpression().accept(*this);
setLocation(_binOp);
solAssert(function->isImplemented());
solAssert(function->isFree());
solAssert(function->parameters().size() == 2);
solAssert(function->returnParameters().size() == 1);
solAssert(*function->returnParameters()[0]->type() == *_binOp.annotation().type);
string left = expressionAsType(_binOp.leftExpression(), *function->parameters()[0]->type());
string right = expressionAsType(_binOp.rightExpression(), *function->parameters()[1]->type());
solAssert(!left.empty() && !right.empty());
solAssert(_binOp.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
define(_binOp) <<
m_context.enqueueFunctionForCodeGeneration(*function) <<
("(" + left + ", " + right + ")\n");
return false;
}
solAssert(!!_binOp.annotation().commonType);
Type const* commonType = _binOp.annotation().commonType;
langutil::Token op = _binOp.getOperator();