Skip to content

[SIL] Extracted SILInstructionWorklist from SILCombine. #27020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions include/swift/SIL/SILInstructionWorklist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===--- SILInstructionWorklist.h -------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// When visiting the instructions in a function/basic block, one often modifies
/// the list of instructions to be visited. That fact introduces complexity in
/// the form of ensuring that no effort is wasted moving items down in the list
/// when an item is removed from it and also in the form of ensuring that no
/// instructions which have been modified/deleted are visited.
///
/// The SILInstructionWorklist manages that complexity. It is responsible for
/// ensuring that removing an instruction is not unnecessarily expensive and
/// that only valid instructions are removed from the list.
///
//===----------------------------------------------------------------------===//

#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"

namespace swift {

/// Manages a list of instructions awaiting visitation.
class SILInstructionWorklist final {
llvm::SmallVector<SILInstruction *, 256> worklist;
llvm::DenseMap<SILInstruction *, unsigned> worklistMap;
StringRef loggingName;

void operator=(const SILInstructionWorklist &rhs) = delete;
SILInstructionWorklist(const SILInstructionWorklist &worklist) = delete;

public:
SILInstructionWorklist(const char *loggingName = "InstructionWorklist")
: loggingName(loggingName) {}

/// Returns true if the worklist is empty.
bool isEmpty() const { return worklist.empty(); }

/// Add the specified instruction to the worklist if it isn't already in it.
void add(SILInstruction *instruction);

/// If the given ValueBase is a SILInstruction add it to the worklist.
void addValue(ValueBase *value) {
if (auto *instruction = value->getDefiningInstruction())
add(instruction);
}

/// Add the given list of instructions in reverse order to the worklist. This
/// routine assumes that the worklist is empty and the given list has no
/// duplicates.
void addInitialGroup(ArrayRef<SILInstruction *> list);

// If instruction is in the worklist, remove it.
void remove(SILInstruction *instruction) {
auto iterator = worklistMap.find(instruction);
if (iterator == worklistMap.end())
return; // Not in worklist.

// Don't bother moving everything down, just null out the slot. We will
// check before we process any instruction if it is null.
worklist[iterator->second] = nullptr;
worklistMap.erase(iterator);
}

/// Remove the top element from the worklist.
SILInstruction *removeOne() {
SILInstruction *instruction = worklist.pop_back_val();
worklistMap.erase(instruction);
return instruction;
}

/// When an instruction has been simplified, add all of its users to the
/// worklist, since additional simplifications of its users may have been
/// exposed.
void addUsersToWorklist(ValueBase *instruction) {
for (auto *use : instruction->getUses())
add(use->getUser());
}

void addUsersToWorklist(SILValue value) {
for (auto *use : value->getUses())
add(use->getUser());
}

/// When an instruction has been simplified, add all of its users to the
/// worklist, since additional simplifications of its users may have been
/// exposed.
void addUsersOfAllResultsToWorklist(SILInstruction *instruction) {
for (auto result : instruction->getResults()) {
addUsersToWorklist(result);
}
}

/// Check that the worklist is empty and nuke the backing store for the map if
/// it is large.
void zap() {
assert(worklistMap.empty() && "Worklist empty, but the map is not?");

// Do an explicit clear, this shrinks the map if needed.
worklistMap.clear();
}
};

} // end namespace swift
1 change: 1 addition & 0 deletions lib/SIL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_swift_host_library(swiftSIL STATIC
SILGlobalVariable.cpp
SILInstruction.cpp
SILInstructions.cpp
SILInstructionWorklist.cpp
SILLocation.cpp
SILModule.cpp
SILFunctionBuilder.cpp
Expand Down
38 changes: 38 additions & 0 deletions lib/SIL/SILInstructionWorklist.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- SILInstructionWorklist.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-instruction-worklist"
#include "swift/SIL/SILInstructionWorklist.h"

using namespace swift;

void SILInstructionWorklist::add(SILInstruction *instruction) {
if (!worklistMap.insert(std::make_pair(instruction, worklist.size())).second)
return;

LLVM_DEBUG(llvm::dbgs() << loggingName << ": ADD: " << *instruction << '\n');
worklist.push_back(instruction);
}

void SILInstructionWorklist::addInitialGroup(ArrayRef<SILInstruction *> list) {
assert(worklist.empty() && "worklist must be empty to add initial group");
worklist.reserve(list.size() + 16);
worklistMap.reserve(list.size());
LLVM_DEBUG(llvm::dbgs() << loggingName << ": ADDING: " << list.size()
<< " instrs to worklist\n");
while (!list.empty()) {
SILInstruction *instruction = list.back();
list = list.slice(0, list.size() - 1);
worklistMap.insert(std::make_pair(instruction, worklist.size()));
worklist.push_back(instruction);
}
}
28 changes: 3 additions & 25 deletions lib/SILOptimizer/SILCombiner/SILCombine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void SILCombiner::addReachableCodeToWorklist(SILBasicBlock *BB) {
}

static void eraseSingleInstFromFunction(SILInstruction &I,
SILCombineWorklist &Worklist,
SILInstructionWorklist &Worklist,
bool AddOperandsToWorklist) {
LLVM_DEBUG(llvm::dbgs() << "SC: ERASE " << I << '\n');

Expand All @@ -127,21 +127,13 @@ static void eraseSingleInstFromFunction(SILInstruction &I,
// Implementation
//===----------------------------------------------------------------------===//

void SILCombineWorklist::add(SILInstruction *I) {
if (!WorklistMap.insert(std::make_pair(I, Worklist.size())).second)
return;

LLVM_DEBUG(llvm::dbgs() << "SC: ADD: " << *I << '\n');
Worklist.push_back(I);
}

// Define a CanonicalizeInstruction subclass for use in SILCombine.
class SILCombineCanonicalize final : CanonicalizeInstruction {
SILCombineWorklist &Worklist;
SILInstructionWorklist &Worklist;
bool changed = false;

public:
SILCombineCanonicalize(SILCombineWorklist &Worklist)
SILCombineCanonicalize(SILInstructionWorklist &Worklist)
: CanonicalizeInstruction(DEBUG_TYPE), Worklist(Worklist) {}

void notifyNewInstruction(SILInstruction *inst) override {
Expand Down Expand Up @@ -270,20 +262,6 @@ bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) {
return MadeChange;
}

void SILCombineWorklist::addInitialGroup(ArrayRef<SILInstruction *> List) {
assert(Worklist.empty() && "Worklist must be empty to add initial group");
Worklist.reserve(List.size()+16);
WorklistMap.reserve(List.size());
LLVM_DEBUG(llvm::dbgs() << "SC: ADDING: " << List.size()
<< " instrs to worklist\n");
while (!List.empty()) {
SILInstruction *I = List.back();
List = List.slice(0, List.size()-1);
WorklistMap.insert(std::make_pair(I, Worklist.size()));
Worklist.push_back(I);
}
}

bool SILCombiner::runOnFunction(SILFunction &F) {
clear();

Expand Down
83 changes: 3 additions & 80 deletions lib/SILOptimizer/SILCombiner/SILCombiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILInstructionWorklist.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
Expand All @@ -37,84 +38,6 @@ namespace swift {

class AliasAnalysis;

/// This is the worklist management logic for SILCombine.
class SILCombineWorklist {
llvm::SmallVector<SILInstruction *, 256> Worklist;
llvm::DenseMap<SILInstruction *, unsigned> WorklistMap;

void operator=(const SILCombineWorklist &RHS) = delete;
SILCombineWorklist(const SILCombineWorklist &Worklist) = delete;
public:
SILCombineWorklist() {}

/// Returns true if the worklist is empty.
bool isEmpty() const { return Worklist.empty(); }

/// Add the specified instruction to the worklist if it isn't already in it.
void add(SILInstruction *I);

/// If the given ValueBase is a SILInstruction add it to the worklist.
void addValue(ValueBase *V) {
if (auto *I = V->getDefiningInstruction())
add(I);
}

/// Add the given list of instructions in reverse order to the worklist. This
/// routine assumes that the worklist is empty and the given list has no
/// duplicates.
void addInitialGroup(ArrayRef<SILInstruction *> List);

// If I is in the worklist, remove it.
void remove(SILInstruction *I) {
auto It = WorklistMap.find(I);
if (It == WorklistMap.end())
return; // Not in worklist.

// Don't bother moving everything down, just null out the slot. We will
// check before we process any instruction if it is null.
Worklist[It->second] = nullptr;
WorklistMap.erase(It);
}

/// Remove the top element from the worklist.
SILInstruction *removeOne() {
SILInstruction *I = Worklist.pop_back_val();
WorklistMap.erase(I);
return I;
}

/// When an instruction has been simplified, add all of its users to the
/// worklist, since additional simplifications of its users may have been
/// exposed.
void addUsersToWorklist(ValueBase *I) {
for (auto UI : I->getUses())
add(UI->getUser());
}

void addUsersToWorklist(SILValue value) {
for (auto *use : value->getUses())
add(use->getUser());
}

/// When an instruction has been simplified, add all of its users to the
/// worklist, since additional simplifications of its users may have been
/// exposed.
void addUsersOfAllResultsToWorklist(SILInstruction *I) {
for (auto result : I->getResults()) {
addUsersToWorklist(result);
}
}

/// Check that the worklist is empty and nuke the backing store for the map if
/// it is large.
void zap() {
assert(WorklistMap.empty() && "Worklist empty, but the map is not?");

// Do an explicit clear, this shrinks the map if needed.
WorklistMap.clear();
}
};

/// This is a class which maintains the state of the combiner and simplifies
/// many operations such as removing/adding instructions and syncing them with
/// the worklist.
Expand All @@ -134,7 +57,7 @@ class SILCombiner :
ClassHierarchyAnalysis *CHA;

/// Worklist containing all of the instructions primed for simplification.
SILCombineWorklist Worklist;
SILInstructionWorklist Worklist;

/// Variable to track if the SILCombiner made any changes.
bool MadeChange;
Expand All @@ -156,7 +79,7 @@ class SILCombiner :
AliasAnalysis *AA, DominanceAnalysis *DA,
ProtocolConformanceAnalysis *PCA, ClassHierarchyAnalysis *CHA,
bool removeCondFails)
: AA(AA), DA(DA), PCA(PCA), CHA(CHA), Worklist(), MadeChange(false),
: AA(AA), DA(DA), PCA(PCA), CHA(CHA), Worklist("SC"), MadeChange(false),
RemoveCondFails(removeCondFails), Iteration(0), Builder(B),
CastOpt(FuncBuilder, nullptr /*SILBuilderContext*/,
/* ReplaceValueUsesAction */
Expand Down