@Override public void visitForStmt(ForStmt forStmt) { visitChildFromParent(forStmt.getInit(), forStmt); visitChildFromParent(forStmt.getCondition(), forStmt); visitChildFromParent(forStmt.getIncrement(), forStmt); visitChildFromParent(forStmt.getBody(), forStmt); }
@Override public ForStmt clone() { return new ForStmt(init.clone(), getCondition().clone(), increment.clone(), getBody().clone()); }
@Override public void applyReductionImpl() { firstLoop.setCondition(secondLoop.getCondition()); enclosingBlock.removeStmt(secondLoop); final String splitLoopCounter = ((DeclarationStmt) firstLoop.getInit()) .getVariablesDeclaration().getDeclInfo(0).getName(); int originalNameBeginIndex = Constants.SPLIT_LOOP_COUNTER_PREFIX.length(); assert Character.isDigit(splitLoopCounter.charAt(originalNameBeginIndex)); while (Character.isDigit(splitLoopCounter.charAt(originalNameBeginIndex))) { originalNameBeginIndex++; } final String mergedLoopCounter = splitLoopCounter.substring(originalNameBeginIndex); ReplaceLoopCounter.replaceLoopCounter(firstLoop, splitLoopCounter, mergedLoopCounter); }
@Override public void applyReductionImpl() { Stmt replacement; if (compoundStmt instanceof ForStmt) { final ForStmt forStmt = (ForStmt) compoundStmt; assert childStmt == forStmt.getBody(); List<Stmt> stmts = new ArrayList<>(); stmts.add(forStmt.getInit()); if (forStmt.getBody() instanceof BlockStmt) { stmts.addAll(((BlockStmt) forStmt.getBody()).getStmts()); } else { stmts.add(forStmt.getBody()); } replacement = new BlockStmt(stmts, true); } else { replacement = childStmt; } parent.replaceChild(compoundStmt, replacement); }
private boolean maybeLongRunning(ForStmt forStmt) { final Optional<ImmutablePair<String, Integer>> initValueAndLoopCounterName = getLoopCounterNameAndInitValue(forStmt.getInit()); if (!initValueAndLoopCounterName.isPresent()) { return false; } final String loopCounterName = initValueAndLoopCounterName.get().left; final int initValue = initValueAndLoopCounterName.get().right; final Optional<ImmutablePair<BinOp, Integer>> condTestTypeAndLimitValue = getCondTestTypeAndLimitValue(forStmt.getCondition(), loopCounterName); if (!condTestTypeAndLimitValue.isPresent()) { return false; } final BinOp condTestType = condTestTypeAndLimitValue.get().left; final int condLimitValue = condTestTypeAndLimitValue.get().right; if (condTestType.isSideEffecting()) { return false; } final Optional<Integer> incrementValue = getIncrementValue(forStmt.getIncrement(), loopCounterName); if (!incrementValue.isPresent()) { return false; } return (((condTestType == BinOp.LT || condTestType == BinOp.LE) && incrementValue.get() <= 0) || ((condTestType == BinOp.GT || condTestType == BinOp.GE) && incrementValue.get() >= 0) || ((condLimitValue - initValue) / incrementValue.get() >= limit)); }
private boolean canMergeLoops(Stmt first, Stmt second) { if (!(first instanceof ForStmt && second instanceof ForStmt)) { return false; } ForStmt firstLoop = (ForStmt) first; ForStmt secondLoop = (ForStmt) second; Optional<String> commonLoopCounter = checkForCommonLoopCounter(firstLoop, secondLoop); if (!commonLoopCounter.isPresent()) { return false; } if (!commonLoopCounter.get().startsWith(Constants.SPLIT_LOOP_COUNTER_PREFIX)) { return false; } if (!hasRegularLoopGuard(firstLoop, commonLoopCounter.get())) { return false; } if (!hasRegularLoopGuard(secondLoop, commonLoopCounter.get())) { return false; } final Integer firstLoopEnd = new Integer(((IntConstantExpr) ((BinaryExpr) firstLoop.getCondition()).getRhs()).getValue()); final BinOp firstLoopOp = ((BinaryExpr) firstLoop.getCondition()).getOp(); final Integer secondLoopStart = new Integer(((IntConstantExpr) ((ScalarInitializer) ((DeclarationStmt) secondLoop.getInit()).getVariablesDeclaration().getDeclInfo(0) .getInitializer()).getExpr()).getValue()); assert firstLoopOp == BinOp.LT || firstLoopOp == BinOp.GT : "Unexpected operator in split loops."; return firstLoopEnd.equals(secondLoopStart); }
public boolean modifiesLoopCounter() { visit(forStmt.getBody()); return foundModification; }
private Optional<String> extractLoopCounter(ForStmt loop) { if (!(loop.getInit() instanceof DeclarationStmt)) { return Optional.empty(); } final DeclarationStmt init = (DeclarationStmt) loop.getInit(); if (init.getVariablesDeclaration().getNumDecls() != 1) { return Optional.empty(); } return Optional.of(init.getVariablesDeclaration().getDeclInfo(0).getName()); }
@Override public boolean preconditionHolds() { if (!enclosingBlock.getStmts().contains(secondLoop)) { return false; } if (!(firstLoop.getIncrement() instanceof UnaryExpr)) { return false; } if (!(((UnaryExpr) firstLoop.getIncrement()).getExpr() instanceof VariableIdentifierExpr)) { return false; } return true; }
private boolean hasRegularLoopGuard(ForStmt loop, String counterName) { if (!(loop.getCondition() instanceof BinaryExpr)) { return false; } final BinaryExpr guard = (BinaryExpr) loop.getCondition(); if (!(guard.getOp() == BinOp.LT || guard.getOp() == BinOp.GT)) { return false; } if (!(guard.getLhs() instanceof VariableIdentifierExpr)) { return false; } if (!(guard.getRhs() instanceof IntConstantExpr)) { return false; } return ((VariableIdentifierExpr) guard.getLhs()).getName().equals(counterName); }
private ForStmt fuzzForStmt() { fuzzingContext.enterScope(); final Stmt init = generator.nextBoolean() ? fuzzDeclarationStmt() : fuzzExprStmt(); final Expr condition = fuzzExpr(BasicType.BOOL, false, false, 0); final Expr increment = fuzzExpr(fuzzType(), false, false, 0); final Stmt body = fuzzBlockStmt(false); fuzzingContext.leaveScope(); return new ForStmt(init, condition, increment, body); }
private void adjustBound(ForStmt loop, int numIterationsToSplitAfter, LoopSplitInfo loopSplitInfo, String newLoopCounter) { final Integer newBound = new Integer(loopSplitInfo.getStartValue() + (loopSplitInfo.getIncreasing() ? 1 : -1) * numIterationsToSplitAfter); final BinOp newOp = loopSplitInfo.getIncreasing() ? BinOp.LT : BinOp.GT; loop.setCondition( new BinaryExpr( new VariableIdentifierExpr(newLoopCounter), new IntConstantExpr(newBound.toString()), newOp)); }
private static ForStmt cloneWithReplacedLoopCounter(ForStmt original, String oldLoopCounter, String newLoopCounter) { return ReplaceLoopCounter.replaceLoopCounter(original.clone(), oldLoopCounter, newLoopCounter); }
@Override public void visitForStmt(ForStmt forStmt) { if (!(forStmt.getBody() instanceof BlockStmt)) { maybeAddInjectionPoint(new LoopInjectionPoint(forStmt, currentFunction, currentScope)); } loopNestingDepth++; super.visitForStmt(forStmt); loopNestingDepth--; }
private void adjustInitializer(ForStmt loop, int numIterationsToSplitAfter, LoopSplitInfo loopSplitInfo) { final Integer newStart = new Integer(loopSplitInfo.getStartValue() + (loopSplitInfo.getIncreasing() ? 1 : -1) * numIterationsToSplitAfter); VariablesDeclaration varDecl = ((DeclarationStmt) loop.getInit()).getVariablesDeclaration(); varDecl.getDeclInfo(0).setInitializer(new ScalarInitializer(new IntConstantExpr( newStart.toString()))); }
Set<String> getIteratorVariableNames(ForStmt forStmt) { visit(forStmt.getIncrement()); return names; }
private Stmt makeSingleIterationForStmt(Stmt stmt, OpaqueExpressionGenerator opaqueExpressionGenerator, Fuzzer fuzzer, IRandom generator, ShadingLanguageVersion shadingLanguageVersion) { boolean up = generator.nextBoolean(); String loopVariableName = "_injected_loop_counter_" + loopVariableCounter; loopVariableCounter++; boolean loopBoundsMustBeConst = shadingLanguageVersion.restrictedForLoops(); Expr start = up ? opaqueExpressionGenerator .makeOpaqueZero(BasicType.INT, loopBoundsMustBeConst, 0, fuzzer) : opaqueExpressionGenerator .makeOpaqueOne(BasicType.INT, loopBoundsMustBeConst, 0, fuzzer); DeclarationStmt init = new DeclarationStmt(new VariablesDeclaration(BasicType.INT, new VariableDeclInfo(loopVariableName, null, new ScalarInitializer(start)))); Expr end = up ? opaqueExpressionGenerator .makeOpaqueOne(BasicType.INT, loopBoundsMustBeConst, 0, fuzzer) : opaqueExpressionGenerator .makeOpaqueZero(BasicType.INT, loopBoundsMustBeConst, 0, fuzzer); BinOp testOp = generator.nextBoolean() ? (up ? BinOp.LT : BinOp.GT) : BinOp.NE; Expr test = new BinaryExpr(new VariableIdentifierExpr(loopVariableName), end, testOp); UnOp incOp = up ? UnOp.POST_INC : UnOp.POST_DEC; Expr inc = new UnaryExpr(new VariableIdentifierExpr(loopVariableName), incOp); return new ForStmt(init, makeWrappedLoopCondition(test), inc, stmt); }
public static ForStmt replaceLoopCounter(ForStmt loop, String oldLoopCounter, String newLoopCounter) { final Map<String, String> substitution = new HashMap<>(); substitution.put(oldLoopCounter, newLoopCounter); new ApplySubstitution(substitution, loop.getBody()); replaceLoopCounterInInitializer(loop.getInit(), newLoopCounter); replaceLoopCounterInCondition(loop.getCondition(), newLoopCounter); replaceLoopCounterInIncrement(loop.getIncrement(), newLoopCounter); return loop; }
/** * Because WebGL places limits on for loops it can be convenient to only visit the body of a * for loop, skipping the header. Subclasses can call this method to invoke this behaviour * during visitation, instead of calling super.visitForStmt(...). * * @param forStmt For statement whose body should be visited */ protected void visitForStmtBodyOnly(ForStmt forStmt) { pushScope(); visit(forStmt.getBody()); popScope(); }