/* CreateIfThenElseOperator Copyright (C) 1998-2002 Jochen Hoenicke. * * This program 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, or (at your option) * any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; see the file COPYING.LESSER. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ */ package net.sf.jode.flow; import net.sf.jode.GlobalOptions; import net.sf.jode.type.Type; import net.sf.jode.expr.*; public class CreateIfThenElseOperator { /** * This handles the body of createFunny. There are three cases: * *
* -------- * IF (c2) * GOTO trueDest -> PUSH c2 * PUSH false * -------- * PUSH bool -> PUSH bool * -------- * if (c2) * (handled recursively) -> PUSH (c2 ? expr1 : expr2) * else * (handled recursively) * -------- **/ private static boolean createFunnyHelper(FlowBlock trueDest, FlowBlock falseDest, StructuredBlock block) { if (block instanceof InstructionBlock && !((InstructionBlock)block).getInstruction().isVoid()) return true; if (block instanceof IfThenElseBlock) { IfThenElseBlock ifBlock = (IfThenElseBlock) block; if (ifBlock.elseBlock == null) return false; /* Next is a non-shortcut "or": simplify both blocks! */ if (!createFunnyHelper(trueDest, falseDest, ifBlock.thenBlock) | !createFunnyHelper(trueDest, falseDest, ifBlock.elseBlock)) return false; if (GlobalOptions.verboseLevel > 0) GlobalOptions.err.print('?'); Expression iteo = new IfThenElseOperator(Type.tBoolean) .addOperand(((InstructionBlock) ifBlock.elseBlock) .getInstruction()) .addOperand(((InstructionBlock) ifBlock.thenBlock) .getInstruction()) .addOperand(ifBlock.cond); ((InstructionBlock)ifBlock.thenBlock).setInstruction(iteo); ifBlock.thenBlock.moveDefinitions(ifBlock, null); ifBlock.thenBlock.replace(ifBlock); return true; } if (block instanceof SequentialBlock && block.getSubBlocks()[0] instanceof ConditionalBlock && block.getSubBlocks()[1] instanceof InstructionBlock) { ConditionalBlock condBlock = (ConditionalBlock) block.getSubBlocks()[0]; InstructionBlock pushBlock = (InstructionBlock) block.getSubBlocks()[1]; if (!(pushBlock.getInstruction() instanceof ConstOperator)) return false; ConstOperator constOp = (ConstOperator) pushBlock.getInstruction(); if (condBlock.trueBlock.jump.destination == trueDest && constOp.getValue().equals(new Integer(0))) { Expression cond = condBlock.getInstruction(); condBlock.flowBlock.removeSuccessor(condBlock.trueBlock.jump); condBlock.trueBlock.removeJump(); pushBlock.setInstruction(cond); pushBlock.moveDefinitions(block, null); pushBlock.replace(block); return true; } } return false; } /** * This handles the more complicated form of the ?-:-operator used * in a conditional block. The simplest case is: *
* if (cond) * PUSH e1 * else { * IF (c2) * GOTO flow_2_ * PUSH false * } * ->IF (stack_0 == 0) * GOTO flow_1_ * GOTO flow_2_ ** is transformed to *
* push cond ? e1 : c2 * ->IF (stack_0 == 0) * GOTO flow_1_ * GOTO flow_2_ ** * The
->
points to the lastModified block. Note
* that both the if and the then part may contain this
* condition+push0-block. There may be even stack if-then-else-blocks
* for very complicated nested ?-:-Operators. * * Also note that the produced code is suboptimal: The push-0 could * sometimes be better replaced with a correct jump. */ public static boolean createFunny(ConditionalBlock cb, StructuredBlock last) { if (cb.jump == null || !(cb.getInstruction() instanceof CompareUnaryOperator) || !(last.outer instanceof SequentialBlock) || !(last.outer.getSubBlocks()[0] instanceof IfThenElseBlock)) return false; CompareUnaryOperator compare = (CompareUnaryOperator) cb.getInstruction(); FlowBlock trueDestination; FlowBlock falseDestination; if (compare.getOperatorIndex() == Operator.EQUALS_OP) { trueDestination = cb.jump.destination; falseDestination = cb.trueBlock.jump.destination; } else if (compare.getOperatorIndex() == Operator.NOTEQUALS_OP) { falseDestination = cb.jump.destination; trueDestination = cb.trueBlock.jump.destination; } else return false; SequentialBlock sequBlock = (SequentialBlock) last.outer; return createFunnyHelper(trueDestination, falseDestination, sequBlock.subBlocks[0]); } /** * This handles the normal form of the ?-:-operator: *
* if (cond) * push e1 * GOTO flow_1_ * ->push e2 * GOTO flow_2 ** is transformed to *
* ->push cond ? e1 : e2 ** The
->
points to the lastModified block.
*/
public static boolean create(InstructionContainer ic,
StructuredBlock last) {
Expression cond, thenExpr, elseExpr;
InstructionBlock thenBlock;
if (ic.jump == null
|| !(last.outer instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock)last.outer;
if (!(sequBlock.subBlocks[0] instanceof IfThenElseBlock))
return false;
IfThenElseBlock ifBlock = (IfThenElseBlock)sequBlock.subBlocks[0];
if (!(ifBlock.thenBlock instanceof InstructionBlock)
|| ifBlock.thenBlock.jump == null
|| ifBlock.thenBlock.jump.destination != ic.jump.destination
|| ifBlock.elseBlock != null)
return false;
thenBlock = (InstructionBlock) ifBlock.thenBlock;
thenExpr = thenBlock.getInstruction();
if (thenExpr.isVoid() || thenExpr.getFreeOperandCount() > 0)
return false;
elseExpr = ic.getInstruction();
if (elseExpr.isVoid() || elseExpr.getFreeOperandCount() > 0)
return false;
cond = ifBlock.cond;
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.print('?');
thenBlock.flowBlock.removeSuccessor(thenBlock.jump);
thenBlock.removeJump();
IfThenElseOperator iteo = new IfThenElseOperator
(Type.tSuperType(thenExpr.getType())
.intersection(Type.tSuperType(elseExpr.getType())));
iteo.addOperand(elseExpr);
iteo.addOperand(thenExpr);
iteo.addOperand(cond);
ic.setInstruction(iteo);
ic.moveDefinitions(last.outer, last);
last.replace(last.outer);
return true;
}
}