/* * Copyright (c) 2011, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.ir.util; import java.util.Collection; import java.util.List; import net.sf.orcc.ir.Block; import net.sf.orcc.ir.BlockBasic; import net.sf.orcc.ir.BlockWhile; import net.sf.orcc.ir.Def; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.Instruction; import net.sf.orcc.ir.IrFactory; import net.sf.orcc.ir.Use; import net.sf.orcc.ir.Var; import net.sf.orcc.util.util.EcoreHelper; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil.Copier; /** * This class contains several methods to help the manipulation of EMF models. * * @author Matthieu Wipliez * @author Herve Yviquel * */ public class IrUtil { private static void addBlockBeforeBlock(Block newBlock, Block block) { List<Block> blocks = EcoreHelper.getContainingList(block); blocks.add(blocks.indexOf(block), newBlock); } /** * Add the given block before the given expression. If the expression is * contained by an instruction in a basic block, this basic block is split * to insert the block in the right place. Else the block is put after the * previous block of the block containing the expression. Return * <code>true</code> if the given instruction has split the current basic * block. * * @param expression * an expression * @param block * the block to add before the given expression * @return <code>true</code> if the given block is added in the current * block */ public static boolean addBlockBeforeExpr(Expression expression, Block block) { Instruction containingInst = EcoreHelper.getContainerOfType(expression, Instruction.class); Block containingBlock = EcoreHelper.getContainerOfType(expression, Block.class); if (containingInst != null) { if (containingInst.isInstPhi() && isWhileJoinBlock(containingBlock)) { BlockWhile blockWhile = EcoreHelper.getContainerOfType( containingBlock, BlockWhile.class); addBlockBeforeBlock(block, blockWhile); return false; } else { List<Instruction> instructions = EcoreHelper .getContainingList(containingInst); BlockBasic blockBasic = IrFactory.eINSTANCE.createBlockBasic(); // Split the basic block blockBasic.getInstructions().addAll( instructions.subList(0, instructions.indexOf(containingInst))); addBlockBeforeBlock(blockBasic, containingBlock); addBlockBeforeBlock(block, containingBlock); return true; } } else { // The given expression is contained in the condition of If/While addBlockBeforeBlock(block, containingBlock); return false; } } /** * Add the given instruction before the given expression. If the expression * is contained by an instruction then the instruction to add is put * directly before, else the instruction is put to the previous block which * is created if needed. Return <code>true</code> if the given instruction * is added in the current block. * * @param expression * an expression * @param instruction * the instruction to add before the given expression * @return <code>true</code> if the given instruction is added in the * current block */ public static boolean addInstBeforeExpr(Expression expression, Instruction instruction) { Instruction containingInst = EcoreHelper.getContainerOfType(expression, Instruction.class); Block containingBlock = EcoreHelper.getContainerOfType(expression, Block.class); if (containingInst != null) { if (containingInst.isInstPhi() && isWhileJoinBlock(containingBlock)) { BlockWhile blockWhile = EcoreHelper.getContainerOfType( containingBlock, BlockWhile.class); addToPreviousBlockBasic(blockWhile, instruction); return false; } else { List<Instruction> instructions = EcoreHelper .getContainingList(containingInst); instructions.add(instructions.indexOf(containingInst), instruction); return true; } } else { // The given expression is contained in the condition of If/While if (containingBlock.isBlockWhile()) { BlockBasic joinBlock = ((BlockWhile) containingBlock) .getJoinBlock(); joinBlock.add(instruction); } else { addToPreviousBlockBasic(containingBlock, instruction); } return false; } } private static void addToPreviousBlockBasic(Block block, Instruction instruction) { List<Block> blocks = EcoreHelper.getContainingList(block); BlockBasic blockBasic = IrFactory.eINSTANCE.createBlockBasic(); blockBasic.add(instruction); blocks.add(blocks.indexOf(block), blockBasic); } /** * Returns a deep copy of the given objects, and updates def/use chains. * * @param eObjects * A Collection of objects * @return a deep copy of the given objects with def/use chains correctly * updated */ public static <T extends EObject> Collection<T> copy(Collection<T> eObjects) { return copy(new Copier(), eObjects, true); } /** * Returns a deep copy of the given objects, using the given Copier instance * and updates def/use chains. If <i>copyReferences</i> is set to true, * referenced objects will be duplicated in the same time their referrer * will be. * * @param copier * A Copier instance * @param eObjects * A Collection of objects * @param copyReferences * Flag to control if references must be copied * @return a deep copy of the given objects with def/use chains correctly * updated */ public static <T extends EObject> Collection<T> copy(Copier copier, Collection<T> eObjects, boolean copyReferences) { Collection<T> result = copier.copyAll(eObjects); if (copyReferences) { copier.copyReferences(); } TreeIterator<EObject> it = EcoreUtil.getAllContents(eObjects); while (it.hasNext()) { EObject object = it.next(); if (object instanceof Def) { Def def = (Def) object; Def copyDef = (Def) copier.get(def); if (copyDef.getVariable() == null) { copyDef.setVariable(def.getVariable()); } } else if (object instanceof Use) { Use use = (Use) object; Use copyUse = (Use) copier.get(use); if (copyUse.getVariable() == null) { copyUse.setVariable(use.getVariable()); } } } return result; } /** * Returns a deep copy of the given object, using the given Copier instance * and updates def/use chains. * * @param copier * A Copier instance * @param eObject * The EObject to copy * @return a deep copy of the given object with uses correctly updated */ public static <T extends EObject> T copy(Copier copier, T eObject) { return copy(copier, eObject, true); } /** * Returns a deep copy of the given object, using the given Copier instance * and updates def/use chains. If <i>copyReferences</i> is set to true, * referenced objects will be duplicated in the same time their referrer * will be. * * @param copier * A Copier instance * @param eObject * The EObject to copy * @param copyReferences * Flag to control if references must be copied * @return a deep copy of the given object with uses correctly updated */ public static <T extends EObject> T copy(Copier copier, T eObject, boolean copyReferences) { @SuppressWarnings("unchecked") T result = (T) copier.copy(eObject); if (copyReferences) { copier.copyReferences(); } TreeIterator<EObject> it = EcoreUtil.getAllContents(eObject, true); while (it.hasNext()) { EObject object = it.next(); if (object instanceof Def) { Def def = (Def) object; Def copyDef = (Def) copier.get(def); if (copyDef.getVariable() == null) { copyDef.setVariable(def.getVariable()); } } else if (object instanceof Use) { Use use = (Use) object; Use copyUse = (Use) copier.get(use); if (copyUse.getVariable() == null) { copyUse.setVariable(use.getVariable()); } } } return result; } /** * Returns a deep copy of the given object, and updates def/use chains. * * @param eObject * The EObject to copy * @return a deep copy of the given object with uses correctly updated */ public static <T extends EObject> T copy(T eObject) { return copy(new Copier(), eObject); } /** * Returns a deep copy of the given object, and updates def/use chains. If * <i>copyReferences</i> is set to true, referenced objects will be * duplicated in the same time their referrer will be. * * @param eObject * The EObject to copy * @param copyReferences * Flag to control if references must be copied * @return a deep copy of the given object with uses correctly updated */ public static <T extends EObject> T copy(T eObject, boolean copyReferences) { return copy(new Copier(), eObject, copyReferences); } /** * Removes the def/use chains of the given object, and then removes the * object itself from its container. * * @param eObject * an EObject */ public static void delete(EObject eObject) { removeUses(eObject); removeDefs(eObject); EcoreUtil.remove(eObject); } /** * Deletes the given objects, and updates the def/use chains. * * @param objects * a list of objects */ public static void delete(List<? extends EObject> eObjects) { while (!eObjects.isEmpty()) { delete(eObjects.get(0)); } } /** * Returns the first block in the given list of blocks. A new block is * created if there is no block in the given block list. * * @param blocks * a list of blocks * @return a block */ public static BlockBasic getFirst(List<Block> blocks) { BlockBasic block; if (blocks.isEmpty()) { block = IrFactory.eINSTANCE.createBlockBasic(); blocks.add(block); } else { Block firstBlock = blocks.get(0); if (firstBlock.isBlockBasic()) { block = (BlockBasic) firstBlock; } else { block = IrFactory.eINSTANCE.createBlockBasic(); blocks.add(0, block); } } return block; } /** * Returns the last block in the given list of blocks. A new block is * created if there is no block in the given block list. * * @param blocks * a list of blocks * @return a block */ public static BlockBasic getLast(List<Block> blocks) { BlockBasic block; if (blocks.isEmpty()) { block = IrFactory.eINSTANCE.createBlockBasic(); blocks.add(block); } else { Block lastBlock = blocks.get(blocks.size() - 1); if (lastBlock.isBlockBasic()) { block = (BlockBasic) lastBlock; } else { block = IrFactory.eINSTANCE.createBlockBasic(); blocks.add(block); } } return block; } /** * Returns the name of the given local variable when using SSA. * * @param local * local variable * @return the local name */ public static String getNameSSA(Var local) { if (local.getIndex() == 0) { return local.getName(); } else { return local.getName() + "_" + local.getIndex(); } } private static boolean isWhileJoinBlock(Block block) { if (block.isBlockBasic()) { BlockWhile blockWhile = EcoreHelper.getContainerOfType(block, BlockWhile.class); return (blockWhile != null && blockWhile.getJoinBlock() == block); } return false; } /** * Removes the defs present in the given object. * * @param eObject * an EObject */ public static void removeDefs(EObject eObject) { for (Def def : EcoreHelper.getObjects(eObject, Def.class)) { def.setVariable(null); } } /** * Removes all the instructions that use or define the given variable. The * method does not remove the variable itself. * * @param variable * a variable */ public static void removeInstrRelated(Var variable) { List<Def> definitions = variable.getDefs(); while (!definitions.isEmpty()) { Def def = definitions.get(0); Instruction instruction = EcoreHelper.getContainerOfType(def, Instruction.class); IrUtil.delete(instruction); } List<Use> uses = variable.getUses(); while (!uses.isEmpty()) { Use use = uses.get(0); Instruction instruction = EcoreHelper.getContainerOfType(use, Instruction.class); IrUtil.delete(instruction); } } /** * Removes the uses present in the given object. * * @param eObject * an EObject */ public static void removeUses(EObject eObject) { for (Use use : EcoreHelper.getObjects(eObject, Use.class)) { use.setVariable(null); } } }