001: /* CreateIfThenElseOperator Copyright (C) 1998-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: CreateIfThenElseOperator.java,v 4.17.2.1 2002/05/28 17:34:09 hoenicke Exp $
018: */
019:
020: package jode.flow;
021:
022: import jode.GlobalOptions;
023: import jode.type.Type;
024: import jode.expr.*;
025:
026: import java.util.Enumeration;
027: import java.util.Vector;
028:
029: public class CreateIfThenElseOperator {
030:
031: /**
032: * This handles the body of createFunny. There are three cases:
033: *
034: * <pre>
035: * --------
036: * IF (c2)
037: * GOTO trueDest -> PUSH c2
038: * PUSH false
039: * --------
040: * PUSH bool -> PUSH bool
041: * --------
042: * if (c2)
043: * (handled recursively) -> PUSH (c2 ? expr1 : expr2)
044: * else
045: * (handled recursively)
046: * --------
047: * </pre>
048: */
049: private static boolean createFunnyHelper(FlowBlock trueDest,
050: FlowBlock falseDest, StructuredBlock block) {
051:
052: if (block instanceof InstructionBlock
053: && !((InstructionBlock) block).getInstruction()
054: .isVoid())
055: return true;
056:
057: if (block instanceof IfThenElseBlock) {
058: IfThenElseBlock ifBlock = (IfThenElseBlock) block;
059: Expression expr1, expr2;
060: if (ifBlock.elseBlock == null)
061: return false;
062:
063: /* Next is a non-shortcut "or": simplify both blocks! */
064: if (!createFunnyHelper(trueDest, falseDest,
065: ifBlock.thenBlock)
066: | !createFunnyHelper(trueDest, falseDest,
067: ifBlock.elseBlock))
068: return false;
069:
070: if (GlobalOptions.verboseLevel > 0)
071: GlobalOptions.err.print('?');
072:
073: Expression iteo = new IfThenElseOperator(Type.tBoolean)
074: .addOperand(
075: ((InstructionBlock) ifBlock.elseBlock)
076: .getInstruction()).addOperand(
077: ((InstructionBlock) ifBlock.thenBlock)
078: .getInstruction()).addOperand(
079: ifBlock.cond);
080: ((InstructionBlock) ifBlock.thenBlock).setInstruction(iteo);
081:
082: ifBlock.thenBlock.moveDefinitions(ifBlock, null);
083: ifBlock.thenBlock.replace(ifBlock);
084: return true;
085: }
086:
087: if (block instanceof SequentialBlock
088: && block.getSubBlocks()[0] instanceof ConditionalBlock
089: && block.getSubBlocks()[1] instanceof InstructionBlock) {
090:
091: ConditionalBlock condBlock = (ConditionalBlock) block
092: .getSubBlocks()[0];
093: InstructionBlock pushBlock = (InstructionBlock) block
094: .getSubBlocks()[1];
095:
096: if (!(pushBlock.getInstruction() instanceof ConstOperator))
097: return false;
098:
099: ConstOperator constOp = (ConstOperator) pushBlock
100: .getInstruction();
101:
102: if (condBlock.trueBlock.jump.destination == trueDest
103: && constOp.getValue().equals(new Integer(0))) {
104:
105: Expression cond = condBlock.getInstruction();
106: condBlock.flowBlock
107: .removeSuccessor(condBlock.trueBlock.jump);
108: condBlock.trueBlock.removeJump();
109:
110: pushBlock.setInstruction(cond);
111: pushBlock.moveDefinitions(block, null);
112: pushBlock.replace(block);
113: return true;
114: }
115: }
116: return false;
117: }
118:
119: /**
120: * This handles the more complicated form of the ?-:-operator used
121: * in a conditional block. The simplest case is:
122: * <pre>
123: * if (cond)
124: * PUSH e1
125: * else {
126: * IF (c2)
127: * GOTO flow_2_
128: * PUSH false
129: * }
130: * ->IF (stack_0 == 0)
131: * GOTO flow_1_
132: * GOTO flow_2_
133: * </pre>
134: * is transformed to
135: * <pre>
136: * push cond ? e1 : c2
137: * ->IF (stack_0 == 0)
138: * GOTO flow_1_
139: * GOTO flow_2_
140: * </pre>
141: *
142: * The <code>-></code> points to the lastModified block. Note
143: * that both the if and the then part may contain this
144: * condition+push0-block. There may be even stack if-then-else-blocks
145: * for very complicated nested ?-:-Operators. <p>
146: *
147: * Also note that the produced code is suboptimal: The push-0 could
148: * sometimes be better replaced with a correct jump.
149: * @param flow The FlowBlock that is transformed
150: */
151: public static boolean createFunny(ConditionalBlock cb,
152: StructuredBlock last) {
153:
154: if (cb.jump == null
155: || !(cb.getInstruction() instanceof CompareUnaryOperator)
156: || !(last.outer instanceof SequentialBlock)
157: || !(last.outer.getSubBlocks()[0] instanceof IfThenElseBlock))
158: return false;
159:
160: CompareUnaryOperator compare = (CompareUnaryOperator) cb
161: .getInstruction();
162:
163: FlowBlock trueDestination;
164: FlowBlock falseDestination;
165: if (compare.getOperatorIndex() == compare.EQUALS_OP) {
166: trueDestination = cb.jump.destination;
167: falseDestination = cb.trueBlock.jump.destination;
168: } else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP) {
169: falseDestination = cb.jump.destination;
170: trueDestination = cb.trueBlock.jump.destination;
171: } else
172: return false;
173:
174: Expression[] e = new Expression[3];
175: IfThenElseBlock ifBlock;
176:
177: SequentialBlock sequBlock = (SequentialBlock) last.outer;
178: return createFunnyHelper(trueDestination, falseDestination,
179: sequBlock.subBlocks[0]);
180: }
181:
182: /**
183: * This handles the normal form of the ?-:-operator:
184: * <pre>
185: * if (cond)
186: * push e1
187: * GOTO flow_1_
188: * ->push e2
189: * GOTO flow_2
190: * </pre>
191: * is transformed to
192: * <pre>
193: * ->push cond ? e1 : e2
194: * </pre>
195: * The <code>-></code> points to the lastModified block.
196: * @param flow The FlowBlock that is transformed
197: */
198: public static boolean create(InstructionContainer ic,
199: StructuredBlock last) {
200: Expression cond, thenExpr, elseExpr;
201: InstructionBlock thenBlock;
202: if (ic.jump == null || !(last.outer instanceof SequentialBlock))
203: return false;
204: SequentialBlock sequBlock = (SequentialBlock) last.outer;
205: if (!(sequBlock.subBlocks[0] instanceof IfThenElseBlock))
206: return false;
207:
208: IfThenElseBlock ifBlock = (IfThenElseBlock) sequBlock.subBlocks[0];
209: if (!(ifBlock.thenBlock instanceof InstructionBlock)
210: || ifBlock.thenBlock.jump == null
211: || ifBlock.thenBlock.jump.destination != ic.jump.destination
212: || ifBlock.elseBlock != null)
213: return false;
214:
215: thenBlock = (InstructionBlock) ifBlock.thenBlock;
216:
217: thenExpr = thenBlock.getInstruction();
218: if (thenExpr.isVoid() || thenExpr.getFreeOperandCount() > 0)
219: return false;
220: elseExpr = ic.getInstruction();
221: if (elseExpr.isVoid() || elseExpr.getFreeOperandCount() > 0)
222: return false;
223: cond = ifBlock.cond;
224:
225: if (GlobalOptions.verboseLevel > 0)
226: GlobalOptions.err.print('?');
227:
228: thenBlock.flowBlock.removeSuccessor(thenBlock.jump);
229: thenBlock.removeJump();
230:
231: IfThenElseOperator iteo = new IfThenElseOperator(Type
232: .tSuperType(thenExpr.getType()).intersection(
233: Type.tSuperType(elseExpr.getType())));
234: iteo.addOperand(elseExpr);
235: iteo.addOperand(thenExpr);
236: iteo.addOperand(cond);
237: ic.setInstruction(iteo);
238: ic.moveDefinitions(last.outer, last);
239: last.replace(last.outer);
240: return true;
241: }
242: }
|