mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Add support for an assert_configuration builtin function
This patch adds support for a builtin function assert_configuration that is
replaced by constant progpagation by an appropriate value dependent on a compile
time setting. This replacement can also be disabled when serializing sil for a
library.
Using this mechanism we implement assertions that can be disabled (or whose
behavior changes) depending on compile time build settings (Debug, Release,
DisableReplacement).
In the standard library we can now write one assert function that uses this
builtin function to provide different compile time selectable runtime behavior.
Example
Assert.swift:
@transparent
func assert<T : LogicValue>(
condition: @auto_closure () -> T, message: StaticString = StaticString(),
// Do not supply these parameters explicitly; they will be filled in
// by the compiler and aren't even present when asserts are disabled
file: StaticString = __FILE__, line: UWord = __LINE__
) {
// Only in debug mode.
if _isDebug() {
assert(condition().getLogicValue(), message, file, line)
}
}
AssertCommon.swift:
@transparent
func _isDebug() -> Bool {
return Int32(Builtin.assert_configuration()) == 0;
}
rdar://16458612
Swift SVN r16472
This commit is contained in:
@@ -742,15 +742,29 @@ static SILValue constantFoldInstruction(SILInstruction &I,
|
||||
return SILValue();
|
||||
}
|
||||
|
||||
static bool isAssertConfigurationApply(SILInstruction &I) {
|
||||
if (auto *AI = dyn_cast<ApplyInst>(&I))
|
||||
if (auto *FR = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
|
||||
if (FR->getBuiltinInfo().ID == BuiltinValueKind::AssertConf)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isFoldable(SILInstruction *I) {
|
||||
return isa<IntegerLiteralInst>(I) || isa<FloatLiteralInst>(I);
|
||||
}
|
||||
|
||||
static bool CCPFunctionBody(SILFunction &F, bool EnableDiagnostics) {
|
||||
static bool CCPFunctionBody(SILFunction &F, bool EnableDiagnostics,
|
||||
unsigned AssertConfiguration) {
|
||||
DEBUG(llvm::dbgs() << "*** ConstPropagation processing: " << F.getName()
|
||||
<< "\n");
|
||||
bool Changed = false;
|
||||
|
||||
// Should we replace calls to assert_configuration by the assert
|
||||
// configuration.
|
||||
bool InstantiateAssertConfiguration =
|
||||
(AssertConfiguration != SILOptions::DisableReplacement);
|
||||
|
||||
// The list of instructions whose evaluation resulted in errror or warning.
|
||||
// This is used to avoid duplicate error reporting in case we reach the same
|
||||
// instruction from different entry points in the WorkList.
|
||||
@@ -763,6 +777,8 @@ static bool CCPFunctionBody(SILFunction &F, bool EnableDiagnostics) {
|
||||
for (auto &I : BB) {
|
||||
if (isFoldable(&I) && !I.use_empty())
|
||||
WorkList.insert(&I);
|
||||
else if (InstantiateAssertConfiguration && isAssertConfigurationApply(I))
|
||||
WorkList.insert(&I);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,6 +790,23 @@ static bool CCPFunctionBody(SILFunction &F, bool EnableDiagnostics) {
|
||||
|
||||
DEBUG(llvm::dbgs() << "Visiting: " << *I);
|
||||
|
||||
// Replace assert_configuration instructions by their constant value. We
|
||||
// want them to be replace even if we can't fully propagate the constant.
|
||||
if (InstantiateAssertConfiguration)
|
||||
if (auto *AI = dyn_cast<ApplyInst>(I))
|
||||
if (isAssertConfigurationApply(*AI)) {
|
||||
// Instantiate the constant.
|
||||
SILBuilder B(AI);
|
||||
auto AssertConfInt = B.createIntegerLiteral(
|
||||
AI->getLoc(), AI->getType(0), AssertConfiguration);
|
||||
AI->replaceAllUsesWith(AssertConfInt);
|
||||
// Schedule users for constant folding.
|
||||
WorkList.insert(AssertConfInt);
|
||||
// Delete the call.
|
||||
recursivelyDeleteTriviallyDeadInstructions(AI);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go through all users of the constant and try to fold them.
|
||||
FoldedUsers.clear();
|
||||
for (auto Use : I->getUses()) {
|
||||
@@ -888,7 +921,8 @@ public:
|
||||
private:
|
||||
/// The entry point to the transformation.
|
||||
void run() {
|
||||
if (CCPFunctionBody(*getFunction(), EnableDiagnostics))
|
||||
if (CCPFunctionBody(*getFunction(), EnableDiagnostics,
|
||||
getOptions().AssertConfig))
|
||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user