Add support for OR concatenated IF conditions

This commit is contained in:
Volker Berlin 2019-07-29 19:15:47 +02:00
parent a019647094
commit be77f59ac0
2 changed files with 120 additions and 27 deletions

View File

@ -298,12 +298,15 @@ class BranchManger {
parent.add( new BranchNode( startPos, startPos, WasmBlockOperator.BR_IF, null, 0 ) );
return;
}
int elsePos = searchElsePosition( startBlock, parsedOperations );
BranchNode branch = null;
for( ; i < parsedOperations.size(); i++ ) {
ParsedBlock parsedBlock = parsedOperations.get( i );
if( parsedBlock.nextPosition == endPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition ) {
if( parsedBlock.nextPosition > elsePos ) {
break;
}
if( parsedBlock.nextPosition == elsePos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition ) {
parsedOperations.remove( i );
int elsePos = startBlock.endPosition;
// end position can not be outside of the parent
endPos = Math.min( parsedBlock.endPosition, parent.endPos );
@ -322,28 +325,6 @@ class BranchManger {
}
}
while( i > 0 ) {
// check if there is a second condition in the IF expression that is concatenated with "&&" operator
parsedBlock = parsedOperations.get( 0 );
if( parsedBlock.op == JavaBlockOperator.IF && parsedBlock.endPosition == elsePos ) {
parent.add( new BranchNode( startPos, parsedBlock.nextPosition - 1, WasmBlockOperator.IF, null ) );
parent.add( new BranchNode( parsedBlock.nextPosition - 1, parsedBlock.nextPosition, WasmBlockOperator.ELSE, WasmBlockOperator.END ) );
startPos = parsedBlock.nextPosition;
parsedOperations.remove( 0 );
i--;
((IfParsedBlock)parsedBlock).negateCompare();
for( int k = 0; k < instructions.size(); k++ ) {
WasmInstruction instr = instructions.get( k );
if( instr.getCodePosition() >= startPos ) {
instructions.add( k, new WasmConstInstruction( 0, startPos - 1, parsedBlock.lineNumber ) );
break;
}
}
continue;
}
break;
}
branch = new BranchNode( startPos, elsePos, WasmBlockOperator.IF, null );
parent.add( branch );
if( i > 0 ) {
@ -363,9 +344,30 @@ class BranchManger {
}
break;
}
if( parsedBlock.nextPosition > endPos ) {
break;
if( i== 0 && parsedBlock.op == JavaBlockOperator.IF ) {
// AND concatenation (&& operator)
if( endPos == elsePos && parsedBlock.endPosition == elsePos ) {
parent.add( new BranchNode( startPos, parsedBlock.nextPosition - 1, WasmBlockOperator.IF, null ) );
parent.add( new BranchNode( parsedBlock.nextPosition - 1, parsedBlock.nextPosition, WasmBlockOperator.ELSE, WasmBlockOperator.END ) );
startPos = parsedBlock.nextPosition;
parsedOperations.remove( 0 );
i--;
((IfParsedBlock)parsedBlock).negateCompare();
insertConstBeforePosition( 0, startPos, parsedBlock.lineNumber ); // 0 --> FALSE for the next if expression
continue;
}
// OR concatenation (|| operator)
if( startBlock.endPosition == parsedBlock.endPosition || startBlock.endPosition == parsedBlock.nextPosition ) {
int pos = startBlock.startPosition + 1; // startBlock.startPosition is the position of the compare operation which need before this if construct
parent.add( new BranchNode( pos, startPos, WasmBlockOperator.IF, null ) );
parent.add( new BranchNode( startPos, endPos, WasmBlockOperator.ELSE, WasmBlockOperator.END ) );
insertConstBeforePosition( 1, pos+1, startBlock.lineNumber ); // 1 --> TRUE for the next if expression
return;
}
}
}
if( branch == null ) {
@ -388,6 +390,58 @@ class BranchManger {
}
}
/**
* Search the start position of an ELSE branch.
*
* @param startBlock
* the start block of the if control structure
* @param parsedOperations
* the not consumed operations in the parent branch
* @return the position
*/
private int searchElsePosition( IfParsedBlock startBlock, List<ParsedBlock> parsedOperations ) {
int elsePos = startBlock.endPosition;
for( int i = 0; i < parsedOperations.size(); i++ ) {
ParsedBlock parsedBlock = parsedOperations.get( i );
if( parsedBlock.op == JavaBlockOperator.GOTO && elsePos == parsedBlock.nextPosition ) {
return elsePos;
}
if( parsedBlock.nextPosition > elsePos ) {
break;
}
}
for( int i = 0; i < parsedOperations.size(); i++ ) {
ParsedBlock parsedBlock = parsedOperations.get( i );
if( parsedBlock.nextPosition > elsePos ) {
break;
}
if( parsedBlock.op == JavaBlockOperator.IF && elsePos < parsedBlock.endPosition ) {
elsePos = parsedBlock.endPosition;
}
}
return elsePos;
}
/**
* Insert a constant i32 operation before the given code position
*
* @param constant
* the i32 value
* @param pos
* the code position
* @param lineNumber
* the line number for possible error messages
*/
private void insertConstBeforePosition( int constant, int pos, int lineNumber ) {
for( int k = 0; k < instructions.size(); k++ ) {
WasmInstruction instr = instructions.get( k );
if( instr.getCodePosition() >= pos ) {
instructions.add( k, new WasmConstInstruction( constant, pos - 1, lineNumber ) );
break;
}
}
}
/**
* Calculate the deep of a break.
*
@ -592,7 +646,6 @@ class BranchManger {
}
}
throw new WasmException( "GOTO code without target loop/block", null, null, gotoBlock.lineNumber );
}
/**

View File

@ -61,6 +61,11 @@ public class ControlFlowOperators extends AbstractBaseTest {
addParam( list, script, "ifAnd_6" );
addParam( list, script, "if4And_6" );
addParam( list, script, "if4And_7" );
addParam( list, script, "ifOr0" );
addParam( list, script, "ifOr1" );
addParam( list, script, "ifOr3" );
addParam( list, script, "ifOr5" );
addParam( list, script, "ifOr7" );
}
rule.setTestParameters( list );
return list;
@ -370,5 +375,40 @@ public class ControlFlowOperators extends AbstractBaseTest {
}
return result;
}
@Export
static int ifOr0() {
return ifOr( 0 );
}
@Export
static int ifOr1() {
return ifOr( 1 );
}
@Export
static int ifOr3() {
return ifOr( 3 );
}
@Export
static int ifOr5() {
return ifOr( 5 );
}
@Export
static int ifOr7() {
return ifOr( 7 );
}
private static int ifOr( int condition ) {
int result;
if( condition == 1 || condition == 3 || condition == 5 || condition == 7 ) {
result = 42;
} else {
result = 76;
}
return result;
}
}
}