/** * Determines whether this block is guaranteed to begin executing before the given block does. */ boolean provablyExecutesBefore(BasicBlock thatBlock) { // If thatBlock is a descendant of this block, and there are no hoisted // blocks between them, then this block must start before thatBlock. BasicBlock currentBlock; for (currentBlock = thatBlock; currentBlock != null && currentBlock != this; currentBlock = currentBlock.getParent()) {} if (currentBlock == this) { return true; } return isGlobalScopeBlock() && thatBlock.isGlobalScopeBlock(); }
/** @return Whether the variable is only assigned a value once for its lifetime. */ boolean isAssignedOnceInLifetime() { Reference ref = getOneAndOnlyAssignment(); if (ref == null) { return false; } // Make sure this assignment is not in a loop. for (BasicBlock block = ref.getBasicBlock(); block != null; block = block.getParent()) { if (block.isFunction) { if (ref.getSymbol().getScope() != ref.scope) { return false; } break; } else if (block.isLoop) { return false; } } return true; }
/** * Determines if the variable for this reference collection is "well-defined." A variable is * well-defined if we can prove at compile-time that it's assigned a value before it's used. * * <p>Notice that if this function returns false, this doesn't imply that the variable is used * before it's assigned. It just means that we don't have enough information to make a * definitive judgment. */ protected boolean isWellDefined() { int size = references.size(); if (size == 0) { return false; } // If this is a declaration that does not instantiate the variable, // it's not well-defined. Reference init = getInitializingReference(); if (init == null) { return false; } Preconditions.checkState(references.get(0).isDeclaration()); BasicBlock initBlock = init.getBasicBlock(); for (int i = 1; i < size; i++) { if (!initBlock.provablyExecutesBefore(references.get(i).getBasicBlock())) { return false; } } return true; }