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:
51
docs/SIL.rst
51
docs/SIL.rst
@@ -3590,3 +3590,54 @@ Performs a checked conversion from ``$A`` to ``$B``. If the conversion succeeds,
|
|||||||
control is transferred to ``bb1``, and the result of the cast is passed into
|
control is transferred to ``bb1``, and the result of the cast is passed into
|
||||||
``bb1`` as an argument. If the conversion fails, control is transferred to
|
``bb1`` as an argument. If the conversion fails, control is transferred to
|
||||||
``bb2``.
|
``bb2``.
|
||||||
|
|
||||||
|
Assertion configuration
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To be able to support disabling assertions at compile time there is a builtin
|
||||||
|
``assertion_configuration`` function. A call to this function can be replaced at
|
||||||
|
compile time by a constant or can stay opaque.
|
||||||
|
|
||||||
|
All calls to the ``assert_configuration`` function are replaced by the constant
|
||||||
|
propagation pass to the appropriate constant depending on compile time settings.
|
||||||
|
Subsequent passes remove dependent unwanted control flow. Using this mechanism
|
||||||
|
we support conditionally enabling/disabling of code in SIL libraries depending
|
||||||
|
on the assertion configuration selected when the library is linked into user
|
||||||
|
code.
|
||||||
|
|
||||||
|
There are three assertion configurations: Debug (0), Release (1) and
|
||||||
|
DisableReplacement (-1).
|
||||||
|
|
||||||
|
The optimization flag or a special assert configuration flag determines the
|
||||||
|
value. Depending on the configuration value assertions in the standard library
|
||||||
|
will be executed or not.
|
||||||
|
|
||||||
|
The standard library uses this builtin to define an assert that can be
|
||||||
|
disabled at compile time.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
func assert(...) {
|
||||||
|
if (Int32(Builtin.assert_configuration()) == 0) {
|
||||||
|
_fatal_error_message(message, ...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``assert_configuration`` function application is serialized when we build
|
||||||
|
the standard library (we recognize the ``-parse-stdlib`` option and don't do the
|
||||||
|
constant replacement but leave the function application to be serialized to
|
||||||
|
sil).
|
||||||
|
|
||||||
|
The compiler flag that influences the value of the ``assert_configuration``
|
||||||
|
funtion application is the optimization flag: at ``-O0`` the application will be
|
||||||
|
replaced by ``Debug`` at higher optimization levels the instruction will be
|
||||||
|
replaced by ``Release``. Optionally, the value to use for replacement can be
|
||||||
|
specified with the ``-AssertConf`` flag which overwrites the value selected by
|
||||||
|
the optimization flag (possible values are ``Debug``, ``Release``,
|
||||||
|
``DisableReplacement``).
|
||||||
|
|
||||||
|
If the call to the ``assert_configuration`` function stays opaque until IRGen,
|
||||||
|
IRGen will replace the application by the constant representing Debug mode (0).
|
||||||
|
This happens we can build the standard library .dylib. The generate sil will
|
||||||
|
retain the function call but the generated .dylib will contain code with
|
||||||
|
assertions enabled.
|
||||||
|
|||||||
@@ -241,6 +241,10 @@ BUILTIN_MISC_OPERATION(InsertElement, "insertelement", "n", Special)
|
|||||||
/// StaticReport has type (Builtin.Int1, Builtin.Int1, Builtin.RawPointer) -> ()
|
/// StaticReport has type (Builtin.Int1, Builtin.Int1, Builtin.RawPointer) -> ()
|
||||||
BUILTIN_MISC_OPERATION(StaticReport, "staticReport", "", Special)
|
BUILTIN_MISC_OPERATION(StaticReport, "staticReport", "", Special)
|
||||||
|
|
||||||
|
/// assert_configuration has type () -> Builtin.Int32
|
||||||
|
/// Returns the selected assertion configuration.
|
||||||
|
BUILTIN_MISC_OPERATION(AssertConf, "assert_configuration", "n", Special)
|
||||||
|
|
||||||
|
|
||||||
/// Special truncation builtins that check for sign and overflow errors. These
|
/// Special truncation builtins that check for sign and overflow errors. These
|
||||||
/// take an integer as an input and return a tuple of the truncated result and
|
/// take an integer as an input and return a tuple of the truncated result and
|
||||||
|
|||||||
@@ -64,6 +64,20 @@ public:
|
|||||||
|
|
||||||
/// Are we debugging sil serialization.
|
/// Are we debugging sil serialization.
|
||||||
bool DebugSerialization = false;
|
bool DebugSerialization = false;
|
||||||
|
|
||||||
|
enum AssertConfiguration: unsigned {
|
||||||
|
// Used by standard library code to distinguish between a debug and release
|
||||||
|
// build.
|
||||||
|
Debug = 0, // Enables asserts.
|
||||||
|
Release = 1, // Disables asserts.
|
||||||
|
|
||||||
|
// Leave the assert_configuration instruction around.
|
||||||
|
DisableReplacement = UINT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The assert configuration controls how assertions behave.
|
||||||
|
unsigned AssertConfig = DisableReplacement;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -193,6 +193,15 @@ def O_Group : OptionGroup<"<optimization level options>">;
|
|||||||
def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[FrontendOption]>;
|
def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[FrontendOption]>;
|
||||||
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[FrontendOption]>;
|
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[FrontendOption]>;
|
||||||
|
|
||||||
|
// Assert configuration identifiers.
|
||||||
|
|
||||||
|
def AssertConfig_Group : OptionGroup<"<Assert configuration>">;
|
||||||
|
|
||||||
|
def AssertConfig : JoinedOrSeparate<["-"], "AssertConfig">,
|
||||||
|
Group<AssertConfig_Group>, Flags<[FrontendOption]>;
|
||||||
|
def AssertConfigEq : Joined<["-"], "AssertConfig=">,
|
||||||
|
Group<AssertConfig_Group>, Alias<AssertConfig>, Flags<[FrontendOption]>;
|
||||||
|
|
||||||
// File types
|
// File types
|
||||||
|
|
||||||
def parse_as_library : Flag<["-"], "parse-as-library">,
|
def parse_as_library : Flag<["-"], "parse-as-library">,
|
||||||
|
|||||||
@@ -604,6 +604,14 @@ static ValueDecl *getCondFailOperation(ASTContext &C, Identifier Id) {
|
|||||||
return getBuiltinFunction(Id, CondElt, VoidTy);
|
return getBuiltinFunction(Id, CondElt, VoidTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ValueDecl *getAssertConfOperation(ASTContext &C, Identifier Id) {
|
||||||
|
// () -> Int32
|
||||||
|
auto Int32Ty = BuiltinIntegerType::get(32, C);
|
||||||
|
auto VoidTy = TupleType::getEmpty(C);
|
||||||
|
TupleTypeElt EmptyElt(VoidTy);
|
||||||
|
return getBuiltinFunction(Id, EmptyElt, Int32Ty);
|
||||||
|
}
|
||||||
|
|
||||||
static ValueDecl *getFixLifetimeOperation(ASTContext &C, Identifier Id) {
|
static ValueDecl *getFixLifetimeOperation(ASTContext &C, Identifier Id) {
|
||||||
// <T> T -> ()
|
// <T> T -> ()
|
||||||
Type GenericTy;
|
Type GenericTy;
|
||||||
@@ -1165,6 +1173,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
|
|||||||
|
|
||||||
case BuiltinValueKind::CondFail:
|
case BuiltinValueKind::CondFail:
|
||||||
return getCondFailOperation(Context, Id);
|
return getCondFailOperation(Context, Id);
|
||||||
|
|
||||||
|
case BuiltinValueKind::AssertConf:
|
||||||
|
return getAssertConfOperation(Context, Id);
|
||||||
|
|
||||||
case BuiltinValueKind::FixLifetime:
|
case BuiltinValueKind::FixLifetime:
|
||||||
return getFixLifetimeOperation(Context, Id);
|
return getFixLifetimeOperation(Context, Id);
|
||||||
|
|||||||
@@ -640,6 +640,7 @@ static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
|
static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
|
||||||
|
IRGenOptions &IRGenOpts,
|
||||||
DiagnosticEngine &Diags) {
|
DiagnosticEngine &Diags) {
|
||||||
using namespace options;
|
using namespace options;
|
||||||
|
|
||||||
@@ -675,7 +676,54 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
|
|||||||
llvm_unreachable("Unknown SIL linking option!");
|
llvm_unreachable("Unknown SIL linking option!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Opts.RemoveRuntimeAsserts = Args.hasArg(OPT_remove_runtime_asserts);
|
// Parse the optimization level.
|
||||||
|
if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
|
||||||
|
// The maximum optimization level we currently support.
|
||||||
|
unsigned MaxLevel = 3;
|
||||||
|
|
||||||
|
if (A->getOption().matches(OPT_O0)) {
|
||||||
|
IRGenOpts.OptLevel = 0;
|
||||||
|
} else {
|
||||||
|
unsigned OptLevel;
|
||||||
|
if (StringRef(A->getValue()).getAsInteger(10, OptLevel) ||
|
||||||
|
OptLevel > MaxLevel) {
|
||||||
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
||||||
|
A->getAsString(Args), A->getValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRGenOpts.OptLevel = OptLevel;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IRGenOpts.OptLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the build configuration identifier.
|
||||||
|
if (const Arg *A = Args.getLastArg(OPT_AssertConfig_Group)) {
|
||||||
|
// We currently understand build configuration up to 3 of which we only use
|
||||||
|
// 0 and 1 in the standard library.
|
||||||
|
unsigned MaxId = 3;
|
||||||
|
StringRef Configuration = A->getValue();
|
||||||
|
if (Configuration == "DisableReplacement") {
|
||||||
|
Opts.AssertConfig = SILOptions::DisableReplacement;
|
||||||
|
} else if (Configuration == "Debug") {
|
||||||
|
Opts.AssertConfig = SILOptions::Debug;
|
||||||
|
} else if (Configuration == "Release") {
|
||||||
|
Opts.AssertConfig = SILOptions::Release;
|
||||||
|
} else {
|
||||||
|
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
||||||
|
A->getAsString(Args), A->getValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set the assert configuration according to the optimization level.
|
||||||
|
Opts.AssertConfig =
|
||||||
|
IRGenOpts.OptLevel > 0 ? SILOptions::Release : SILOptions::Debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFast might also set removal of runtime asserts (cond_fail).
|
||||||
|
Opts.RemoveRuntimeAsserts |= Args.hasArg(OPT_remove_runtime_asserts);
|
||||||
|
|
||||||
Opts.EnableARCOptimizations = !Args.hasArg(OPT_disable_arc_opts);
|
Opts.EnableARCOptimizations = !Args.hasArg(OPT_disable_arc_opts);
|
||||||
Opts.VerifyAll = Args.hasArg(OPT_sil_verify_all);
|
Opts.VerifyAll = Args.hasArg(OPT_sil_verify_all);
|
||||||
Opts.PrintAll = Args.hasArg(OPT_sil_print_all);
|
Opts.PrintAll = Args.hasArg(OPT_sil_print_all);
|
||||||
@@ -746,24 +794,6 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
|
|||||||
Opts.LinkLibraries.push_back(LinkLibrary(A->getValue(), Kind));
|
Opts.LinkLibraries.push_back(LinkLibrary(A->getValue(), Kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
|
|
||||||
if (A->getOption().matches(OPT_O0)) {
|
|
||||||
Opts.OptLevel = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unsigned OptLevel;
|
|
||||||
if (StringRef(A->getValue()).getAsInteger(10, OptLevel) || OptLevel > 3) {
|
|
||||||
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
|
|
||||||
A->getAsString(Args), A->getValue());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Opts.OptLevel = OptLevel;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Opts.OptLevel = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const Arg *A = Args.getLastArg(OPT_target_cpu)) {
|
if (const Arg *A = Args.getLastArg(OPT_target_cpu)) {
|
||||||
Opts.TargetCPU = A->getValue();
|
Opts.TargetCPU = A->getValue();
|
||||||
}
|
}
|
||||||
@@ -849,7 +879,7 @@ bool CompilerInvocation::parseArgs(ArrayRef<const char *> Args,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParseSILArgs(SILOpts, *ParsedArgs, Diags)) {
|
if (ParseSILArgs(SILOpts, *ParsedArgs, IRGenOpts, Diags)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1813,6 +1813,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
|
|||||||
// No return value.
|
// No return value.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Builtin.ID == BuiltinValueKind::AssertConf) {
|
||||||
|
// Replace the call to assert_configuration by the Debug configuration
|
||||||
|
// value.
|
||||||
|
// TODO: assert(IGF.IGM.getOptions().AssertConfig ==
|
||||||
|
// SILOptions::DisableReplacement);
|
||||||
|
// Make sure this only happens in a mode where we build a library dylib.
|
||||||
|
|
||||||
|
llvm::Value *DebugAssert = IGF.Builder.getInt32(SILOptions::Debug);
|
||||||
|
out->add(DebugAssert);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
llvm_unreachable("IRGen unimplemented for this builtin!");
|
llvm_unreachable("IRGen unimplemented for this builtin!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -742,15 +742,29 @@ static SILValue constantFoldInstruction(SILInstruction &I,
|
|||||||
return SILValue();
|
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) {
|
static bool isFoldable(SILInstruction *I) {
|
||||||
return isa<IntegerLiteralInst>(I) || isa<FloatLiteralInst>(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()
|
DEBUG(llvm::dbgs() << "*** ConstPropagation processing: " << F.getName()
|
||||||
<< "\n");
|
<< "\n");
|
||||||
bool Changed = false;
|
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.
|
// 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
|
// This is used to avoid duplicate error reporting in case we reach the same
|
||||||
// instruction from different entry points in the WorkList.
|
// instruction from different entry points in the WorkList.
|
||||||
@@ -763,6 +777,8 @@ static bool CCPFunctionBody(SILFunction &F, bool EnableDiagnostics) {
|
|||||||
for (auto &I : BB) {
|
for (auto &I : BB) {
|
||||||
if (isFoldable(&I) && !I.use_empty())
|
if (isFoldable(&I) && !I.use_empty())
|
||||||
WorkList.insert(&I);
|
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);
|
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.
|
// Go through all users of the constant and try to fold them.
|
||||||
FoldedUsers.clear();
|
FoldedUsers.clear();
|
||||||
for (auto Use : I->getUses()) {
|
for (auto Use : I->getUses()) {
|
||||||
@@ -888,7 +921,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
/// The entry point to the transformation.
|
/// The entry point to the transformation.
|
||||||
void run() {
|
void run() {
|
||||||
if (CCPFunctionBody(*getFunction(), EnableDiagnostics))
|
if (CCPFunctionBody(*getFunction(), EnableDiagnostics,
|
||||||
|
getOptions().AssertConfig))
|
||||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
test/IRGen/assert_conf_default.sil
Normal file
20
test/IRGen/assert_conf_default.sil
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// RUN: %swift -AssertConfig=DisableReplacement -emit-ir %s | FileCheck %s --check-prefix=DISABLED
|
||||||
|
// RUN: %swift -AssertConfig=Release -emit-ir %s | FileCheck %s --check-prefix=RELEASE
|
||||||
|
// RUN: %swift -AssertConfig=Debug -emit-ir %s | FileCheck %s --check-prefix=DEBUG
|
||||||
|
|
||||||
|
import Builtin
|
||||||
|
|
||||||
|
sil @remove_assert_configuration : $@thin () -> Builtin.Int32 {
|
||||||
|
%0 = builtin_function_ref "assert_configuration" : $@thin () -> Builtin.Int32
|
||||||
|
%1 = apply %0() : $@thin () -> Builtin.Int32
|
||||||
|
return %1 : $Builtin.Int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// DISABLED-LABEL: @remove_assert_configuration
|
||||||
|
// DISABLED: ret i32 0
|
||||||
|
|
||||||
|
// DEBUG-LABEL: @remove_assert_configuration
|
||||||
|
// DEBUG: ret i32 0
|
||||||
|
|
||||||
|
// RELEASE-LABEL: @remove_assert_configuration
|
||||||
|
// RELEASE: ret i32 1
|
||||||
27
test/SILPasses/assert_configuration.sil
Normal file
27
test/SILPasses/assert_configuration.sil
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// RUN: %sil-opt %s -diagnostic-constant-propagation -assert-conf-id 1 | FileCheck %s --check-prefix=ONE
|
||||||
|
// RUN: %sil-opt %s -diagnostic-constant-propagation -assert-conf-id 4294967295 | FileCheck %s --check-prefix=DISABLED
|
||||||
|
// RUN: %sil-opt %s -performance-constant-propagation -assert-conf-id 1 | FileCheck %s --check-prefix=PERFONE
|
||||||
|
|
||||||
|
import Builtin
|
||||||
|
|
||||||
|
sil @assert_configuration : $@thin () -> Builtin.Int32 {
|
||||||
|
%0 = builtin_function_ref "assert_configuration" : $@thin () -> Builtin.Int32
|
||||||
|
%1 = apply %0() : $@thin () -> Builtin.Int32
|
||||||
|
return %1 : $Builtin.Int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether we can enable/disable replacement of the assert configuration
|
||||||
|
// id.
|
||||||
|
|
||||||
|
// DISABLED-LABEL: @assert_configuration
|
||||||
|
// DISABLED: [[REF:%.*]] = builtin_function_ref "assert_configuration"
|
||||||
|
// DISABLED: [[AP:%.*]] = apply [[REF]]
|
||||||
|
// DISABLED: return [[AP]]
|
||||||
|
|
||||||
|
// ONE-LABEL: @assert_configuration
|
||||||
|
// ONE: [[RES:%.*]] = integer_literal $Builtin.Int32, 1
|
||||||
|
// ONE: return [[RES]]
|
||||||
|
|
||||||
|
// PERFONE-LABEL: @assert_configuration
|
||||||
|
// PERFONE: [[RES:%.*]] = integer_literal $Builtin.Int32, 1
|
||||||
|
// PERFONE: return [[RES]]
|
||||||
@@ -198,6 +198,10 @@ VerifyMode("verify",
|
|||||||
llvm::cl::desc("verify diagnostics against expected-"
|
llvm::cl::desc("verify diagnostics against expected-"
|
||||||
"{error|warning|note} annotations"));
|
"{error|warning|note} annotations"));
|
||||||
|
|
||||||
|
static llvm::cl::opt<unsigned>
|
||||||
|
AssertConfId("assert-conf-id", llvm::cl::Hidden,
|
||||||
|
llvm::cl::init(0));
|
||||||
|
|
||||||
static llvm::cl::opt<unsigned>
|
static llvm::cl::opt<unsigned>
|
||||||
SILInlineThreshold("sil-inline-threshold", llvm::cl::Hidden,
|
SILInlineThreshold("sil-inline-threshold", llvm::cl::Hidden,
|
||||||
llvm::cl::init(50));
|
llvm::cl::init(50));
|
||||||
@@ -325,6 +329,7 @@ int main(int argc, char **argv) {
|
|||||||
SILOpts.VerifyAll = EnableSILVerifyAll;
|
SILOpts.VerifyAll = EnableSILVerifyAll;
|
||||||
SILOpts.PrintAll = EnableSILPrintAll;
|
SILOpts.PrintAll = EnableSILPrintAll;
|
||||||
SILOpts.RemoveRuntimeAsserts = RemoveRuntimeAsserts;
|
SILOpts.RemoveRuntimeAsserts = RemoveRuntimeAsserts;
|
||||||
|
SILOpts.AssertConfig = AssertConfId;
|
||||||
|
|
||||||
SILPassManager PM(CI.getSILModule(), SILOpts);
|
SILPassManager PM(CI.getSILModule(), SILOpts);
|
||||||
PM.registerAnalysis(createCallGraphAnalysis(CI.getSILModule()));
|
PM.registerAnalysis(createCallGraphAnalysis(CI.getSILModule()));
|
||||||
|
|||||||
Reference in New Issue
Block a user