| Index: pkg/compiler/lib/src/ssa/nodes.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
|
| index 12d82d9a966f2b318da8dc2c7aabcb4a2f287b77..5d9f10c8c994985d899219e8e0b294a5bca84ccd 100644
|
| --- a/pkg/compiler/lib/src/ssa/nodes.dart
|
| +++ b/pkg/compiler/lib/src/ssa/nodes.dart
|
| @@ -866,6 +866,8 @@ class HBasicBlock extends HInstructionList {
|
| } while (other != null && other.id >= id);
|
| return dominatesCache[other] = false;
|
| }
|
| +
|
| + toString() => 'HBasicBlock($id)';
|
| }
|
|
|
| abstract class HInstruction implements Spannable {
|
| @@ -1277,60 +1279,9 @@ abstract class HInstruction implements Spannable {
|
| removeFromList(oldInput.usedBy, this);
|
| }
|
|
|
| - // Compute the set of users of this instruction that is dominated by
|
| - // [other]. If [other] is a user of [this], it is included in the
|
| - // returned set.
|
| - Setlet<HInstruction> dominatedUsers(HInstruction other) {
|
| - // Keep track of all instructions that we have to deal with later
|
| - // and count the number of them that are in the current block.
|
| - Setlet<HInstruction> users = new Setlet<HInstruction>();
|
| - int usersInCurrentBlock = 0;
|
| -
|
| - // Run through all the users and see if they are dominated or
|
| - // potentially dominated by [other].
|
| - HBasicBlock otherBlock = other.block;
|
| - for (int i = 0, length = usedBy.length; i < length; i++) {
|
| - HInstruction current = usedBy[i];
|
| - HBasicBlock currentBlock = current.block;
|
| - if (otherBlock.dominates(currentBlock)) {
|
| - if (identical(currentBlock, otherBlock)) usersInCurrentBlock++;
|
| - users.add(current);
|
| - }
|
| - }
|
| -
|
| - // Run through all the phis in the same block as [other] and remove them
|
| - // from the users set.
|
| - if (usersInCurrentBlock > 0) {
|
| - for (HPhi phi = otherBlock.phis.first; phi != null; phi = phi.next) {
|
| - if (users.contains(phi)) {
|
| - users.remove(phi);
|
| - if (--usersInCurrentBlock == 0) break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Run through all the instructions before [other] and remove them
|
| - // from the users set.
|
| - if (usersInCurrentBlock > 0) {
|
| - HInstruction current = otherBlock.first;
|
| - while (!identical(current, other)) {
|
| - if (users.contains(current)) {
|
| - users.remove(current);
|
| - if (--usersInCurrentBlock == 0) break;
|
| - }
|
| - current = current.next;
|
| - }
|
| - }
|
| -
|
| - return users;
|
| - }
|
| -
|
| void replaceAllUsersDominatedBy(
|
| HInstruction cursor, HInstruction newInstruction) {
|
| - Setlet<HInstruction> users = dominatedUsers(cursor);
|
| - for (HInstruction user in users) {
|
| - user.changeUse(this, newInstruction);
|
| - }
|
| + DominatedUses.of(this, cursor).replaceWith(newInstruction);
|
| }
|
|
|
| void moveBefore(HInstruction other) {
|
| @@ -1417,6 +1368,134 @@ abstract class HInstruction implements Spannable {
|
| }
|
| }
|
|
|
| +/// The set of uses of [source] that are dominated by [dominator].
|
| +class DominatedUses {
|
| + final HInstruction _source;
|
| +
|
| + // Two list of matching length holding (instruction, input-index) pairs for
|
| + // the dominated uses.
|
| + final List<HInstruction> _instructions = <HInstruction>[];
|
| + final List<int> _indexes = <int>[];
|
| +
|
| + DominatedUses._(this._source);
|
| +
|
| + /// The uses of [source] that are dominated by [dominator].
|
| + ///
|
| + /// The uses by [dominator] are included in the result, unless
|
| + /// [excludeDominator] is `true`, so `true` selects uses following
|
| + /// [dominator].
|
| + ///
|
| + /// The uses include the in-edges of a HPhi node that corresponds to a
|
| + /// dominated block. (There can be many such edges on a single phi at the exit
|
| + /// of a loop with many break statements). If [excludePhiOutEdges] is `true`
|
| + /// then these edge uses are not included.
|
| + static of(HInstruction source, HInstruction dominator,
|
| + {bool excludeDominator: false, bool excludePhiOutEdges: false}) {
|
| + return new DominatedUses._(source)
|
| + .._compute(source, dominator, excludeDominator, excludePhiOutEdges);
|
| + }
|
| +
|
| + bool get isEmpty => _instructions.isEmpty;
|
| + bool get isNotEmpty => !isEmpty;
|
| +
|
| + /// Changes all the uses in the set to [newInstruction].
|
| + void replaceWith(HInstruction newInstruction) {
|
| + assert(!identical(newInstruction, _source));
|
| + if (isEmpty) return;
|
| + for (int i = 0; i < _instructions.length; i++) {
|
| + HInstruction user = _instructions[i];
|
| + int index = _indexes[i];
|
| + HInstruction oldInstruction = user.inputs[index];
|
| + assert(
|
| + identical(oldInstruction, _source),
|
| + 'Input ${index} of ${user} changed.'
|
| + '\n Found: ${oldInstruction}\n Expected: ${_source}');
|
| + user.inputs[index] = newInstruction;
|
| + oldInstruction.usedBy.remove(user);
|
| + newInstruction.usedBy.add(user);
|
| + }
|
| + }
|
| +
|
| + void _addUse(HInstruction user, int inputIndex) {
|
| + _instructions.add(user);
|
| + _indexes.add(inputIndex);
|
| + }
|
| +
|
| + void _compute(HInstruction source, HInstruction dominator,
|
| + bool excludeDominator, bool excludePhiOutEdges) {
|
| + // Keep track of all instructions that we have to deal with later and count
|
| + // the number of them that are in the current block.
|
| + Set<HInstruction> users = new Setlet<HInstruction>();
|
| + Set<HInstruction> seen = new Setlet<HInstruction>();
|
| + int usersInCurrentBlock = 0;
|
| +
|
| + HBasicBlock dominatorBlock = dominator.block;
|
| +
|
| + // Run through all the users and see if they are dominated, or potentially
|
| + // dominated, or partially dominated by [dominator]. It is easier to
|
| + // de-duplicate [usedBy] and process all inputs of an instruction than to
|
| + // track the repeated elements of usedBy and match them up by index.
|
| + for (HInstruction current in source.usedBy) {
|
| + if (!seen.add(current)) continue;
|
| + HBasicBlock currentBlock = current.block;
|
| + if (dominatorBlock.dominates(currentBlock)) {
|
| + users.add(current);
|
| + if (identical(currentBlock, dominatorBlock)) usersInCurrentBlock++;
|
| + } else if (!excludePhiOutEdges && current is HPhi) {
|
| + // A non-dominated HPhi.
|
| + // See if there a dominated edge into the phi. The input must be
|
| + // [source] and the position must correspond to a dominated block.
|
| + List<HBasicBlock> predecessors = currentBlock.predecessors;
|
| + for (int i = 0; i < predecessors.length; i++) {
|
| + if (current.inputs[i] != source) continue;
|
| + HBasicBlock predecessor = predecessors[i];
|
| + if (dominatorBlock.dominates(predecessor)) {
|
| + _addUse(current, i);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Run through all the phis in the same block as [dominator] and remove them
|
| + // from the users set. These come before [dominator].
|
| + // TODO(sra): Could we simply not add them in the first place?
|
| + if (usersInCurrentBlock > 0) {
|
| + for (HPhi phi = dominatorBlock.phis.first; phi != null; phi = phi.next) {
|
| + if (users.remove(phi)) {
|
| + if (--usersInCurrentBlock == 0) break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Run through all the instructions before [dominator] and remove them from
|
| + // the users set.
|
| + if (usersInCurrentBlock > 0) {
|
| + HInstruction current = dominatorBlock.first;
|
| + while (!identical(current, dominator)) {
|
| + if (users.contains(current)) {
|
| + // TODO(29302): Use 'user.remove(current)' as the condition.
|
| + users.remove(current);
|
| + if (--usersInCurrentBlock == 0) break;
|
| + }
|
| + current = current.next;
|
| + }
|
| + if (excludeDominator) {
|
| + users.remove(dominator);
|
| + }
|
| + }
|
| +
|
| + // Convert users into a list of (user, input-index) uses.
|
| + for (HInstruction user in users) {
|
| + var inputs = user.inputs;
|
| + for (int i = 0; i < inputs.length; i++) {
|
| + if (inputs[i] == source) {
|
| + _addUse(user, i);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| /// A reference to a [HInstruction] that can hold its own source information.
|
| ///
|
| /// This used for attaching source information to reads of locals.
|
|
|