/** * Returns the Greatest Lower Bound of the given types. The GLB is the smallest type of (t1, t2). * When t1 and t2 have different types (e.g. one is a int and the other is a uint), an int is * returned. * * @param t1 a type * @param t2 another type * @return the Greatest Lower Bound of the given types */ public static Type getGlb(Type t1, Type t2) { if (t1.isBool() && t2.isBool()) { return IrFactory.eINSTANCE.createTypeBool(); } else if (t1.isInt() && t2.isInt()) { return IrFactory.eINSTANCE.createTypeInt( Math.min(((TypeInt) t1).getSize(), ((TypeInt) t2).getSize())); } else if (t1.isUint() && t2.isUint()) { return IrFactory.eINSTANCE.createTypeUint( Math.min(((TypeUint) t1).getSize(), ((TypeUint) t2).getSize())); } else if (t1.isInt() && t2.isUint()) { int si = ((TypeInt) t1).getSize(); int su = ((TypeUint) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(su + 1); } else { return IrFactory.eINSTANCE.createTypeInt(si); } } else if (t1.isUint() && t2.isInt()) { int su = ((TypeUint) t1).getSize(); int si = ((TypeInt) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(su + 1); } else { return IrFactory.eINSTANCE.createTypeInt(si); } } return null; }
@Override public int getSize(Type t1, Type t2) { int shift = t2.getSizeInBits(); if (shift >= 6) { // limits type size to 64 shift = 6; } return t1.getSizeInBits() + (1 << shift) - 1; }
/** * Creates a new type based on the unification of t1 and t2, and clips its size to {@link * #maxSize}. * * @param t1 a type * @param t2 a type * @param unification how to unify t1 and t2 */ public static Type createType(Type t1, Type t2, Unification unification) { Type type = unification.getType(t1, t2); int size = unification.getSize(t1, t2); // only set the size if it is different than 0 if (size != 0) { if (type.isInt()) { ((TypeInt) type).setSize(size); } else if (type.isUint()) { ((TypeUint) type).setSize(size); } } return type; }
@SuppressWarnings("unchecked") @Override public Loop caseBlockWhile(BlockWhile blockWhile) { // Initialize members Map<Var, Port> inputs = new HashMap<Var, Port>(); Map<Var, Bus> outputs = new HashMap<Var, Bus>(); Map<Bus, Var> feedbackBusVar = new HashMap<Bus, Var>(); Map<Bus, Var> completeBusVar = new HashMap<Bus, Var>(); // -- Decision // Construct decision from the block while condition Block decisionBlock = null; Component valueComponent = new ExprToComponent().doSwitch(blockWhile.getCondition()); Map<Var, Port> dBlockDataPorts = null; if (!(valueComponent instanceof Block)) { dBlockDataPorts = new HashMap<Var, Port>(); Map<Var, Port> valueDataPorts = (Map<Var, Port>) blockWhile.getCondition().getAttribute("inputs").getObjectValue(); decisionBlock = new Block(Arrays.asList(valueComponent)); // Propagate DataPorts ComponentUtil.propagateDataPorts(decisionBlock, dBlockDataPorts, valueDataPorts); // Propagate DataBuses for (Bus dataBus : valueComponent.getExit(Exit.DONE).getDataBuses()) { Bus blockDataBus = decisionBlock.getExit(Exit.DONE).makeDataBus(); Port blockDataBuspeer = blockDataBus.getPeer(); ComponentUtil.connectDataDependency(dataBus, blockDataBuspeer, 0); } } else { decisionBlock = (Block) valueComponent; dBlockDataPorts = (Map<Var, Port>) blockWhile.getCondition().getAttribute("inputs").getObjectValue(); } Component decisionComponent = ComponentUtil.decisionFindConditionComponent(decisionBlock); // Create decision Decision decision = new Decision(decisionBlock, decisionComponent); Debug.depGraphTo(decision, "deicions", "/tmp/decision1.dot", 1); // Propagate decisionBlockInputs to the decision one Map<Var, Port> dDataPorts = new HashMap<Var, Port>(); ComponentUtil.propagateDataPorts(decision, dDataPorts, dBlockDataPorts); // -- Loop Body // Construct Loop Body Block from the block while blocks Map<Var, Port> blockDataPorts = new HashMap<Var, Port>(); Map<Var, Bus> blockDataBuses = new HashMap<Var, Bus>(); Module body = (Module) new BlocksToBlock(blockDataPorts, blockDataBuses, false) .doSwitch(blockWhile.getBlocks()); // Loop body (While Body) inputs and outputs Map<Var, Port> lbDataPorts = new HashMap<Var, Port>(); LoopBody loopBody = new WhileBody(decision, body); Debug.depGraphTo(loopBody, "loopBody", "/tmp/loopBody.dot", 1); // Propagate decision and body inputs to the loopBody // -- Propagate Decision data ports ComponentUtil.propagateDataPorts(loopBody, lbDataPorts, dDataPorts); // -- Propagate Body Blocks data ports ComponentUtil.propagateDataPorts(loopBody, lbDataPorts, blockDataPorts); // -- Complete Exit for (Var var : blockDataBuses.keySet()) { Type type = var.getType(); Bus bus = blockDataBuses.get(var); // -- Make an complete exit data bus Bus cBus = loopBody .getLoopCompleteExit() .makeDataBus(var.getName() + "_fb", type.getSizeInBits(), type.isInt()); // -- Connect Port cBusPeer = cBus.getPeer(); ComponentUtil.connectDataDependency(bus, cBusPeer); // -- Save it to the feedbackBusVar completeBusVar.put(cBus, var); } // -- FeedBack Exit for (Var var : blockDataBuses.keySet()) { Type type = var.getType(); // -- If the input does not exist create one because this is a // feedback if (!lbDataPorts.containsKey(var)) { Port lbPort = loopBody.makeDataPort(var.getName() + "_fb", type.getSizeInBits(), type.isInt()); lbDataPorts.put(var, lbPort); } Bus bus = blockDataBuses.get(var); // -- Make an feedback exit data bus Bus fbBus = loopBody .getFeedbackExit() .makeDataBus(var.getName() + "_fb", type.getSizeInBits(), type.isInt()); // -- Connect Port fbBusPeer = fbBus.getPeer(); ComponentUtil.connectDataDependency(bus, fbBusPeer); // -- Save it to the feedbackBusVar feedbackBusVar.put(fbBus, var); } // -- From input to Complete Exit dependency for (Bus bus : completeBusVar.keySet()) { Var var = completeBusVar.get(bus); Port port = lbDataPorts.get(var); // -- Connect it Port busPeer = bus.getPeer(); Bus portpeer = port.getPeer(); ComponentUtil.connectDataDependency(portpeer, busPeer); } // Create Loop Loop loop = new Loop(loopBody); // -- Loop inputs comes from decision and body Set<Var> inVars = new HashSet<Var>(); inVars.addAll(dDataPorts.keySet()); inVars.addAll(lbDataPorts.keySet()); for (Var var : inVars) { Type type = var.getType(); Port dataPort = loop.makeDataPort(var.getName(), type.getSizeInBits(), type.isInt()); inputs.put(var, dataPort); } // -- Init Dependencies Entry initEntry = loop.getBodyInitEntry(); for (Var var : inputs.keySet()) { if (feedbackBusVar.containsValue(var)) { Port lPort = inputs.get(var); Port lbPort = lbDataPorts.get(var); Bus lPortPeer = lPort.getPeer(); Dependency dep = (lbPort == lbPort.getOwner().getGoPort()) ? new ControlDependency(lPortPeer) : new DataDependency(lPortPeer); initEntry.addDependency(lbPort, dep); } } // -- Feedback Dependencies Entry fbEntry = loop.getBodyFeedbackEntry(); for (Bus bus : feedbackBusVar.keySet()) { Var var = feedbackBusVar.get(bus); Exit lfbExit = loop.getBody().getFeedbackExit(); Port lbPort = lbDataPorts.get(var); // -- Create a feedback register Reg fbReg = loop.createDataRegister(); fbReg.setIDLogical("fbReg_" + var.getName()); // fbReg.getDataPort().setIDLogical(var.getName()); // fbReg.getResultBus().setIDLogical(var.getName()); // -- Dependencies Entry entry = fbReg.makeEntry(lfbExit); entry.addDependency(fbReg.getDataPort(), new DataDependency(bus)); fbEntry.addDependency(lbPort, new DataDependency(fbReg.getResultBus())); } // -- Latch Dependencies Collection<Dependency> goInitDeps = initEntry.getDependencies(loop.getBody().getGoPort()); Bus initDoneBus = goInitDeps.iterator().next().getLogicalBus(); for (Var var : inVars) { if (!feedbackBusVar.containsValue(var)) { Port lPort = inputs.get(var); Bus lPortPeer = lPort.getPeer(); // -- Create a latch Latch latch = loop.createDataLatch(); latch.setIDLogical("latched_" + var.getName()); // -- Dependencies Entry latchEntry = latch.makeEntry(initDoneBus.getOwner()); latch.getDataPort().setIDLogical(var.getName()); // -- Control dependency latchEntry.addDependency(latch.getEnablePort(), new ControlDependency(initDoneBus)); // -- Data dependency in latch latchEntry.addDependency(latch.getDataPort(), new DataDependency(lPortPeer)); // -- Data dependency out latch Bus latchResultBus = latch.getResultBus(); latchResultBus.setIDLogical(var.getName() + "_result"); Port lbPort = lbDataPorts.get(var); fbEntry.addDependency(lbPort, new DataDependency(latchResultBus)); } } // -- Done Dependencies Entry outbufEntry = loop.getExit(Exit.DONE).getPeer().getEntries().get(0); for (Bus bus : loopBody.getLoopCompleteExit().getDataBuses()) { Var var = completeBusVar.get(bus); Type type = var.getType(); Bus dataBus = loop.getExit(Exit.DONE).makeDataBus(var.getName(), type.getSizeInBits(), type.isInt()); Port dataBusPeer = dataBus.getPeer(); Dependency dep = new DataDependency(bus); outbufEntry.addDependency(dataBusPeer, dep); outputs.put(var, dataBus); } // -- Set control dependency Port lbDonePort = loopBody.getLoopCompleteExit().getDoneBus().getPeer(); Bus lDoneBus = loop.getExit(Exit.DONE).getDoneBus(); Dependency dep = new ControlDependency(lDoneBus); outbufEntry.addDependency(lbDonePort, dep); // -- IDSourceInfo Procedure procedure = EcoreHelper.getContainerOfType(blockWhile, Procedure.class); IDSourceInfo sinfo = new IDSourceInfo(procedure.getName(), blockWhile.getLineNumber()); loop.setIDSourceInfo(sinfo); Debug.depGraphTo(loop, "loopBody", "/tmp/loop_new.dot", 1); // -- Set attributes blockWhile.setAttribute("inputs", inputs); blockWhile.setAttribute("outputs", outputs); return loop; }
@Override public int getSize(Type t1, Type t2) { return t1.getSizeInBits() + t2.getSizeInBits(); }
/** * Returns <code>true</code> if type src can be converted to type dst. * * @param src a type * @param dst the type src should be converted to * @return <code>true</code> if type src can be converted to type dst */ public static boolean isConvertibleTo(Type src, Type dst) { if (src == null || dst == null) { return false; } if (src.isFloat() && dst.isFloat()) { return dst.getSizeInBits() >= src.getSizeInBits(); } if (src.isBool() && dst.isBool() || src.isString() && dst.isString() || (src.isInt() || src.isUint()) && (dst.isInt() || dst.isUint()) || (src.isInt() || src.isUint()) && dst.isFloat()) { return true; } if (src.isList() && dst.isList()) { TypeList typeSrc = (TypeList) src; TypeList typeDst = (TypeList) dst; // Recursively check type convertibility if (isConvertibleTo(typeSrc.getType(), typeDst.getType())) { if (typeSrc.getSizeExpr() != null && typeDst.getSizeExpr() != null) { return typeSrc.getSize() <= typeDst.getSize(); } return true; } } return false; }
/** * Returns the type of a binary expression whose left operand has type t1 and right operand has * type t2, and whose operator is given. * * <p>TODO replace automatic int/uint to float casting with explicit casts * * @param op operator * @param t1 type of the first operand * @param t2 type of the second operand * @param source source object * @param feature feature * @return the type of the binary expression, or <code>null</code> */ public static Type getTypeBinary(OpBinary op, Type t1, Type t2) { if (t1 == null || t2 == null) { return null; } switch (op) { case BITAND: return createType(t1, t2, Glb.instance); case BITOR: case BITXOR: return createType(t1, t2, Lub.instance); case TIMES: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, LubSum.instance); case MINUS: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, SignedLub.instance); case PLUS: if (t1.isString() && !t2.isList() || t2.isString() && !t1.isList()) { return IrFactory.eINSTANCE.createTypeString(); } if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } return createType(t1, t2, LubPlus1.instance); case DIV: case DIV_INT: if ((t1.isInt() || t1.isUint()) && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t2.getSizeInBits()); } else if ((t2.isInt() || t2.isUint()) && t1.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat(t1.getSizeInBits()); } else if (t1.isFloat() && t2.isFloat()) { return createType(t1, t2, Lub.instance); } case SHIFT_RIGHT: return EcoreUtil.copy(t1); case MOD: return EcoreUtil.copy(t2); case SHIFT_LEFT: return createType(t1, t2, LubSumPow.instance); case EQ: case GE: case GT: case LE: case LT: case NE: return IrFactory.eINSTANCE.createTypeBool(); case EXP: return null; case LOGIC_AND: case LOGIC_OR: return IrFactory.eINSTANCE.createTypeBool(); default: return null; } }
/** * Returns the Least Upper Bound of the given types, which is the smallest type that can contain * both types. If no such type exists (e.g. when types are not compatible with each other), <code> * null</code> is returned. * * @param t1 a type * @param t2 another type * @return the Least Upper Bound of the given types */ public static Type getLub(Type t1, Type t2) { if (t1 == null || t2 == null) { return null; } if (t1.isBool() && t2.isBool()) { return IrFactory.eINSTANCE.createTypeBool(); } else if (t1.isFloat() && t2.isFloat()) { return IrFactory.eINSTANCE.createTypeFloat( Math.max(((TypeFloat) t1).getSize(), ((TypeFloat) t2).getSize())); } else if (t1.isString() && t2.isString()) { return IrFactory.eINSTANCE.createTypeString(); } else if (t1.isInt() && t2.isInt()) { return IrFactory.eINSTANCE.createTypeInt( Math.max(((TypeInt) t1).getSize(), ((TypeInt) t2).getSize())); } else if (t1.isList() && t2.isList()) { TypeList listType1 = (TypeList) t1; TypeList listType2 = (TypeList) t2; Type type = getLub(listType1.getType(), listType2.getType()); if (type != null) { // only return a list when the underlying type is valid int size = Math.max(listType1.getSize(), listType2.getSize()); return IrFactory.eINSTANCE.createTypeList(size, type); } } else if (t1.isUint() && t2.isUint()) { return IrFactory.eINSTANCE.createTypeUint( Math.max(((TypeUint) t1).getSize(), ((TypeUint) t2).getSize())); } else if (t1.isInt() && t2.isUint()) { int si = ((TypeInt) t1).getSize(); int su = ((TypeUint) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(si); } else { return IrFactory.eINSTANCE.createTypeInt(su + 1); } } else if (t1.isUint() && t2.isInt()) { int su = ((TypeUint) t1).getSize(); int si = ((TypeInt) t2).getSize(); if (si > su) { return IrFactory.eINSTANCE.createTypeInt(si); } else { return IrFactory.eINSTANCE.createTypeInt(su + 1); } } return null; }