#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
using namespace empathy;
using namespace empathy::ir;
using namespace empathy::llr;
using namespace empathy::parse;
namespace empathy::builtins
{
void SetupLogicOps( Env& e )
{
CreatePrefixOp( e, "!"_sid, "operator_logical_not"_sid, precedence::UnaryOps,
ForType< bool >( []( auto&& operand ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
Xor( operand, ToValue( true ) ) );
} )
);
CreatePrefixOp( e, "~"_sid, "operator_bitwise_not"_sid, precedence::UnaryOps,
ForType< CustomPattern< RTInteger, RTInteger::Pattern > >( []( auto&& operand ) -> Value
{
auto opTypeVal = *ValueFromIRExpr( operand.type() );
auto opType = *FromValue< RTInteger >( opTypeVal );
return BuildComputedValue( operand.type(),
Xor( operand,
BuildComputedValue( operand.type(),
LoadConstInt( static_cast< llvm::IntegerType* >( GetLLVMType( opTypeVal ) ),
APSInt::getMaxValue( opType.m_numBits, true) )
)
) );
} )
);
CreateLeftAssInfixOp( e, "^"_sid, "operator_xor"_sid, precedence::OrOp,
// Logical xor
ForType< bool >( []( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
Xor( lhs, rhs ) );
} ),
// ct_int xor
ForType< BigInt >( []( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< BigInt >(),
Xor( lhs, rhs ) );
} ),
// runtime integer xor, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< RTInteger, RTInteger::Pattern > >(
[]( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Xor( lhs, rhs ) );
} )
);
CreateLeftAssInfixOp( e, "|"_sid, "operator_or"_sid, precedence::OrOp,
// ct_int or
ForType< BigInt >( []( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< BigInt >(),
Or( lhs, rhs ) );
} ),
// runtime integer or, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< RTInteger, RTInteger::Pattern > >(
[]( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Or( lhs, rhs ) );
} ),
// bool or
ForType< bool >( []( auto&& lhs, auto&& rhs ) -> Value
{
// Build a CFG that implements the control flow for
// shortcut evaluation.
auto cfg = make_shared< CFG >();
auto pLhsBB = cfg->entryBB();
auto pRhsBB = cfg->createBB();
auto pEndBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
pLhsBB->setTerminator( CondBranch( lhs, pEndBB, pRhsBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( cfg->uniqueId(), rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pEndBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromIRExpr( GetValueType< bool >() ),
2, cfg->uniqueId(), resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( pLhsBB, ToValue( true ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( cfg->uniqueId(), rhsIndex ) ) );
pEndBB->emplace_back( move( phi ) );
// Build the result val which pulls the temporary created by the
// cfg above.
auto resultVal = BuildComputedValue( GetValueType< bool >(),
GetTemporary( cfg->uniqueId(), resultIndex ) );
// Return it
pEndBB->setTerminator( Ret( move( resultVal ) ) );
// Pachage our cfg in a value with an inline CFG instruction.
return BuildComputedValue( GetValueType< bool >(), move( cfg ) );
} )
);
CreateLeftAssInfixOp( e, "&"_sid, "operator_and"_sid, precedence::AndOp,
// ct_int and
ForType< BigInt >( []( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< BigInt >(),
And( lhs, rhs ) );
} ),
// runtime integer and, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< RTInteger, RTInteger::Pattern > >(
[]( auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
And( lhs, rhs ) );
} ),
// bool or
ForType< bool >( []( auto&& lhs, auto&& rhs ) -> Value
{
// Build a CFG that implements the control flow for
// shortcut evaluation.
auto cfg = make_shared< CFG >();
auto pLhsBB = cfg->entryBB();
auto pRhsBB = cfg->createBB();
auto pEndBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
pLhsBB->setTerminator( CondBranch( lhs, pRhsBB, pEndBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( cfg->uniqueId(), rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pEndBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromIRExpr( GetValueType< bool >() ),
2, cfg->uniqueId(), resultIndex );
// If coming directly from the lhs BB, we know the result is false.
phi.setIncoming( pLhsBB, ToValue( false ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( cfg->uniqueId(), rhsIndex ) ) );
pEndBB->emplace_back( move( phi ) );
// Build the result val which pulls the temporary created by the
// cfg above.
auto resultVal = BuildComputedValue( GetValueType< bool >(),
GetTemporary( cfg->uniqueId(), resultIndex ) );
// Return it
pEndBB->setTerminator( Ret( move( resultVal ) ) );
// Pachage our cfg in a value with an inline CFG instruction.
return BuildComputedValue( GetValueType< bool >(), move( cfg ) );
} )
);
}
}