-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
SIL: add a utility which can manage per-block bitfields and flags efficiently. #35521
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
//===--- SILBitField.h - Defines the bitfield utilities ---------*- C++ -*-===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2021 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines the BasicBlockBitfield and BasicBlockFlag utilities. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef SWIFT_SIL_SILBITFIELD_H | ||
#define SWIFT_SIL_SILBITFIELD_H | ||
|
||
#include "swift/SIL/SILFunction.h" | ||
|
||
namespace swift { | ||
|
||
/// Utility to add a custom bitfield to a function's basic blocks. | ||
/// | ||
/// This can be used by transforms to store temporary flags or tiny values per | ||
/// basic block. | ||
/// It is very efficient: no memory allocation is needed, no hash set or map is | ||
/// needed for lookup and there is no initialization cost (in contrast to | ||
/// BasicBlockData which needs to iterate over all blocks at initialization). | ||
/// | ||
/// Restrictions: | ||
/// * BasicBlockBitfield instances must be allocated and deallocated | ||
/// following a strict stack discipline. This means, it's fine to use them as | ||
/// (or in) local variables in transformations. But it's e.g. not possible to | ||
/// store a BasicBlockBitfield in an Analysis. | ||
/// * The total number of bits which are alive at the same time must not exceed | ||
/// 32. | ||
class BasicBlockBitfield { | ||
/// The bitfield is "added" to the blocks of this function. | ||
SILFunction *function; | ||
|
||
/// A single linked list of currently alive BasicBlockBitfields (oldest is | ||
/// last, newest is first). | ||
/// The head of the list is function->lastAllocatedBitfield. | ||
BasicBlockBitfield *parent; | ||
|
||
/// Initialized with the monotonically increasing currentBitfieldID of the | ||
/// function. | ||
/// Used to check if the bitfield in a block is initialized. | ||
/// If a block's lastInitializedBitfieldID is less than this ID, it means | ||
/// that the bits of that block are not initialized yet. | ||
/// See also: SILBasicBlock::lastInitializedBitfieldID, | ||
/// SILFunction::currentBitfieldID | ||
unsigned bitfieldID; | ||
|
||
short startBit; | ||
short endBit; | ||
uint32_t mask; | ||
|
||
public: | ||
BasicBlockBitfield(SILFunction *function, int size) : | ||
function(function), | ||
parent(function->newestAliveBitfield), | ||
bitfieldID(function->currentBitfieldID), | ||
startBit(parent ? parent->endBit : 0), | ||
endBit(startBit + size), | ||
mask(0xffffffffu >> (32 - size) << startBit) { | ||
assert(size > 0 && "bit field size must be > 0"); | ||
assert(endBit <= 32 && "too many/large bit fields allocated in function"); | ||
assert((!parent || bitfieldID > parent->bitfieldID) && | ||
"BasicBlockBitfield indices are not in order"); | ||
function->newestAliveBitfield = this; | ||
++function->currentBitfieldID; | ||
assert(function->currentBitfieldID != 0 && "currentBitfieldID overflow"); | ||
} | ||
|
||
~BasicBlockBitfield() { | ||
assert(function->newestAliveBitfield == this && | ||
"BasicBlockBitfield destructed too early"); | ||
function->newestAliveBitfield = parent; | ||
} | ||
|
||
BasicBlockBitfield(const BasicBlockBitfield &) = delete; | ||
BasicBlockBitfield(BasicBlockBitfield &&) = delete; | ||
BasicBlockBitfield &operator=(const BasicBlockBitfield &) = delete; | ||
BasicBlockBitfield &operator=(BasicBlockBitfield &&) = delete; | ||
|
||
SILFunction *getFunction() const { return function; } | ||
|
||
unsigned get(SILBasicBlock *block) const { | ||
if (bitfieldID > block->lastInitializedBitfieldID) { | ||
// The bitfield is not initialized yet in this block. | ||
return 0; | ||
} | ||
return (block->customBits & mask) >> startBit; | ||
} | ||
|
||
void set(SILBasicBlock *block, unsigned value) { | ||
assert(((value << startBit) & ~mask) == 0 && | ||
"value too large for BasicBlockBitfield"); | ||
unsigned clearMask = mask; | ||
if (bitfieldID > block->lastInitializedBitfieldID) { | ||
|
||
// The bitfield is not initialized yet in this block. | ||
// Initialize the bitfield, and also initialize all parent bitfields, | ||
// which are not initialized, yet. Example: | ||
// | ||
// This field Last initialized field | ||
// | | | ||
// V V | ||
// EE DDD C BB AAA | ||
// | ||
// block->lastInitializedBitfieldID == AAA.bitfieldID | ||
// -> we have to initialize the fields: BB, C, DDD and EE | ||
// | ||
BasicBlockBitfield *bf = parent; | ||
while (bf && bf->bitfieldID > block->lastInitializedBitfieldID) { | ||
clearMask |= bf->mask; | ||
bf = bf->parent; | ||
} | ||
block->lastInitializedBitfieldID = bitfieldID; | ||
} | ||
block->customBits = (block->customBits & ~clearMask) | (value << startBit); | ||
} | ||
}; | ||
|
||
/// A BasicBlockBitfield containing a single bit - a flag. | ||
class BasicBlockFlag { | ||
BasicBlockBitfield bit; | ||
|
||
public: | ||
BasicBlockFlag(SILFunction *function) : bit(function, 1) {} | ||
|
||
SILFunction *getFunction() const { return bit.getFunction(); } | ||
|
||
bool get(SILBasicBlock *block) const { return (bool)bit.get(block); } | ||
|
||
void set(SILBasicBlock *block) { bit.set(block, 1); } | ||
void reset(SILBasicBlock *block) { bit.set(block, 0); } | ||
|
||
/// Sets the flag and returns the old value. | ||
bool testAndSet(SILBasicBlock *block) { | ||
bool oldValue = get(block); | ||
set(block); | ||
return oldValue; | ||
} | ||
}; | ||
|
||
/// A BasicBlockFlag with a set-like API. | ||
class BasicBlockSet { | ||
BasicBlockFlag flag; | ||
|
||
public: | ||
BasicBlockSet(SILFunction *function) : flag(function) {} | ||
|
||
SILFunction *getFunction() const { return flag.getFunction(); } | ||
|
||
bool contains(SILBasicBlock *block) const { return flag.get(block); } | ||
|
||
/// Returns true if \p block was not contained in the set before inserting. | ||
bool insert(SILBasicBlock *block) { return !flag.testAndSet(block); } | ||
|
||
void remove(SILBasicBlock *block) { flag.reset(block); } | ||
}; | ||
|
||
} // namespace swift | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eeckstein Post-commit review.
Can you add some more docs here? Specifically, you never describe where the actual bits are and why the bitfield needs to follow a strict bitfield discipline. I would also like a reference in the document
This would have given me all of the information that I needed to understand the code without having to search around. I found that I had to do that while reading the code.
That being said, I really like this change and see how it will save a bunch of compile time!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I improved the comment in #35583