Skip to content

Commit d0b7eca

Browse files
authored
Merge pull request swiftlang#27244 from ravikandhadai/constexpr-oslog-constant-evaluable-check
2 parents d77ed7a + 22861ec commit d0b7eca

File tree

12 files changed

+152
-127
lines changed

12 files changed

+152
-127
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,10 @@ NOTE(constexpr_overflow,none, "integer overflow detected", ())
377377
NOTE(constexpr_overflow_operation,none, "operation"
378378
"%select{| performed during this call}0 overflows", (bool))
379379

380-
NOTE(constexpr_trap,none, "trap detected", ())
381-
NOTE(constexpr_trap_operation,none, "operation"
380+
NOTE(constexpr_trap, none, "%0", (StringRef))
381+
NOTE(constexpr_trap_operation, none, "operation"
382382
"%select{| performed during this call}0 traps", (bool))
383383

384-
NOTE(constexpr_assertion_failed, none, "assertion failed with message: %0",
385-
(StringRef))
386-
NOTE(constexpr_assertion_failed_here, none, "assertion failed"
387-
"%select{ here| during this call}0 ", (bool))
388-
389384
NOTE(constexpr_invalid_operand_seen, none,
390385
"operation with invalid operands encountered during evaluation",())
391386
NOTE(constexpr_operand_invalid_here, none,

include/swift/SIL/SILConstants.h

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,45 @@ struct UnknownSymbolicValue;
3737

3838
extern llvm::cl::opt<unsigned> ConstExprLimit;
3939

40+
/// An abstract class that exposes functions for allocating symbolic values.
41+
/// The implementors of this class have to determine where to allocate them and
42+
/// and manage the lifetime of the allocated symbolic values.
43+
class SymbolicValueAllocator {
44+
public:
45+
virtual ~SymbolicValueAllocator() {}
46+
47+
/// Allocate raw bytes.
48+
/// \param byteSize number of bytes to allocate.
49+
/// \param alignment alignment for the allocated bytes.
50+
virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0;
51+
52+
/// Allocate storage for a given number of elements of a specific type
53+
/// provided as a template parameter. Precondition: \c T must have an
54+
/// accesible zero argument constructor.
55+
/// \param numElts number of elements of the type to allocate.
56+
template <typename T> T *allocate(unsigned numElts) {
57+
T *res = (T *)allocate(sizeof(T) * numElts, alignof(T));
58+
for (unsigned i = 0; i != numElts; ++i)
59+
new (res + i) T();
60+
return res;
61+
}
62+
};
63+
64+
/// A class that allocates symbolic values in a local bump allocator. The
65+
/// lifetime of the bump allocator is same as the lifetime of \c this object.
66+
class SymbolicValueBumpAllocator : public SymbolicValueAllocator {
67+
private:
68+
llvm::BumpPtrAllocator bumpAllocator;
69+
70+
public:
71+
SymbolicValueBumpAllocator() {}
72+
~SymbolicValueBumpAllocator() {}
73+
74+
void *allocate(unsigned long byteSize, unsigned alignment) {
75+
return bumpAllocator.Allocate(byteSize, alignment);
76+
}
77+
};
78+
4079
/// When we fail to constant fold a value, this captures a reason why,
4180
/// allowing the caller to produce a specific diagnostic. The "Unknown"
4281
/// SymbolicValue representation also includes a pointer to the SILNode in
@@ -58,13 +97,9 @@ class UnknownReason {
5897
/// Integer overflow detected.
5998
Overflow,
6099

61-
/// Unspecified trap detected.
100+
/// Trap detected. Traps will a message as a payload.
62101
Trap,
63102

64-
/// Assertion failure detected. These have an associated message unlike
65-
/// traps.
66-
AssertionFailure,
67-
68103
/// An operation was applied over operands whose symbolic values were
69104
/// constants but were not valid for the operation.
70105
InvalidOperandValue,
@@ -111,14 +146,20 @@ class UnknownReason {
111146
// Auxiliary information for different unknown kinds.
112147
union {
113148
SILFunction *function;
114-
const char *failedAssertMessage;
149+
const char *trapMessage;
115150
} payload;
116151

117152
public:
118153
UnknownKind getKind() { return kind; }
119154

120155
static bool isUnknownKindWithPayload(UnknownKind kind) {
121-
return kind == UnknownKind::CalleeImplementationUnknown;
156+
switch (kind) {
157+
case UnknownKind::CalleeImplementationUnknown:
158+
case UnknownKind::Trap:
159+
return true;
160+
default:
161+
return false;
162+
}
122163
}
123164

124165
static UnknownReason create(UnknownKind kind) {
@@ -141,57 +182,23 @@ class UnknownReason {
141182
return payload.function;
142183
}
143184

144-
static UnknownReason createAssertionFailure(const char *message,
145-
size_t size) {
146-
assert(message[size] == '\0' && "message must be null-terminated");
185+
static UnknownReason createTrap(StringRef message,
186+
SymbolicValueAllocator &allocator) {
187+
// Copy and null terminate the string.
188+
size_t size = message.size();
189+
char *messagePtr = allocator.allocate<char>(size + 1);
190+
std::uninitialized_copy(message.begin(), message.end(), messagePtr);
191+
messagePtr[size] = '\0';
192+
147193
UnknownReason reason;
148-
reason.kind = UnknownKind::AssertionFailure;
149-
reason.payload.failedAssertMessage = message;
194+
reason.kind = UnknownKind::Trap;
195+
reason.payload.trapMessage = messagePtr;
150196
return reason;
151197
}
152198

153-
const char *getAssertionFailureMessage() {
154-
assert(kind == UnknownKind::AssertionFailure);
155-
return payload.failedAssertMessage;
156-
}
157-
};
158-
159-
/// An abstract class that exposes functions for allocating symbolic values.
160-
/// The implementors of this class have to determine where to allocate them and
161-
/// and manage the lifetime of the allocated symbolic values.
162-
class SymbolicValueAllocator {
163-
public:
164-
virtual ~SymbolicValueAllocator() {}
165-
166-
/// Allocate raw bytes.
167-
/// \param byteSize number of bytes to allocate.
168-
/// \param alignment alignment for the allocated bytes.
169-
virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0;
170-
171-
/// Allocate storage for a given number of elements of a specific type
172-
/// provided as a template parameter. Precondition: \c T must have an
173-
/// accesible zero argument constructor.
174-
/// \param numElts number of elements of the type to allocate.
175-
template <typename T> T *allocate(unsigned numElts) {
176-
T *res = (T *)allocate(sizeof(T) * numElts, alignof(T));
177-
for (unsigned i = 0; i != numElts; ++i)
178-
new (res + i) T();
179-
return res;
180-
}
181-
};
182-
183-
/// A class that allocates symbolic values in a local bump allocator. The
184-
/// lifetime of the bump allocator is same as the lifetime of \c this object.
185-
class SymbolicValueBumpAllocator : public SymbolicValueAllocator {
186-
private:
187-
llvm::BumpPtrAllocator bumpAllocator;
188-
189-
public:
190-
SymbolicValueBumpAllocator() {}
191-
~SymbolicValueBumpAllocator() {}
192-
193-
void *allocate(unsigned long byteSize, unsigned alignment) {
194-
return bumpAllocator.Allocate(byteSize, alignment);
199+
const char *getTrapMessage() {
200+
assert(kind == UnknownKind::Trap);
201+
return payload.trapMessage;
195202
}
196203
};
197204

include/swift/SILOptimizer/Utils/ConstExpr.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class UnknownReason;
4545
class ConstExprEvaluator {
4646
SymbolicValueAllocator &allocator;
4747

48+
// Assert configuration that must be used by the evaluator. This determines
49+
// the result of the builtin "assert_configuration".
50+
unsigned assertConfig;
51+
4852
/// The current call stack, used for providing accurate diagnostics.
4953
llvm::SmallVector<SourceLoc, 4> callStack;
5054

@@ -58,13 +62,15 @@ class ConstExprEvaluator {
5862

5963
public:
6064
explicit ConstExprEvaluator(SymbolicValueAllocator &alloc,
61-
bool trackCallees = false);
65+
unsigned assertConf, bool trackCallees = false);
6266
~ConstExprEvaluator();
6367

6468
explicit ConstExprEvaluator(const ConstExprEvaluator &other);
6569

6670
SymbolicValueAllocator &getAllocator() { return allocator; }
6771

72+
unsigned getAssertConfig() { return assertConfig; }
73+
6874
void pushCallStack(SourceLoc loc) { callStack.push_back(loc); }
6975

7076
void popCallStack() {
@@ -124,7 +130,8 @@ class ConstExprStepEvaluator {
124130
/// Constructs a step evaluator given an allocator and a non-null pointer to a
125131
/// SILFunction.
126132
explicit ConstExprStepEvaluator(SymbolicValueAllocator &alloc,
127-
SILFunction *fun, bool trackCallees = false);
133+
SILFunction *fun, unsigned assertConf,
134+
bool trackCallees = false);
128135
~ConstExprStepEvaluator();
129136

130137
/// Evaluate an instruction in the current interpreter state.

lib/SIL/SILConstants.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -656,20 +656,13 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) {
656656
diagnose(ctx, triggerLoc, diag::constexpr_overflow_operation,
657657
triggerLocSkipsInternalLocs);
658658
return;
659-
case UnknownReason::Trap:
660-
diagnose(ctx, diagLoc, diag::constexpr_trap);
659+
case UnknownReason::Trap: {
660+
const char *message = unknownReason.getTrapMessage();
661+
diagnose(ctx, diagLoc, diag::constexpr_trap, StringRef(message));
661662
if (emitTriggerLocInDiag)
662663
diagnose(ctx, triggerLoc, diag::constexpr_trap_operation,
663664
triggerLocSkipsInternalLocs);
664665
return;
665-
case UnknownReason::AssertionFailure: {
666-
const char *message = unknownReason.getAssertionFailureMessage();
667-
diagnose(ctx, diagLoc, diag::constexpr_assertion_failed,
668-
StringRef(message));
669-
if (emitTriggerLocInDiag)
670-
diagnose(ctx, triggerLoc, diag::constexpr_assertion_failed_here,
671-
triggerLocSkipsInternalLocs);
672-
return;
673666
}
674667
case UnknownReason::InvalidOperandValue:
675668
diagnose(ctx, diagLoc, diag::constexpr_invalid_operand_seen);

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ class EmitDFDiagnostics : public SILFunctionTransform {
194194

195195
if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) {
196196
SymbolicValueBumpAllocator allocator;
197-
ConstExprEvaluator constantEvaluator(allocator);
197+
ConstExprEvaluator constantEvaluator(allocator,
198+
getOptions().AssertConfig);
198199
for (auto &BB : *getFunction())
199200
for (auto &I : BB)
200201
diagnosePoundAssert(&I, M, constantEvaluator);

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,10 @@ class FoldState {
186186
SmallVector<SILValue, 4> constantSILValues;
187187

188188
public:
189-
FoldState(SILFunction *fun, SILInstruction *beginInst,
189+
FoldState(SILFunction *fun, unsigned assertConfig, SILInstruction *beginInst,
190190
ArrayRef<SILInstruction *> endInsts)
191-
: constantEvaluator(allocator, fun), beginInstruction(beginInst),
191+
: constantEvaluator(allocator, fun, assertConfig),
192+
beginInstruction(beginInst),
192193
endInstructions(endInsts.begin(), endInsts.end()) {}
193194

194195
void addConstantSILValue(SILValue value) {
@@ -627,13 +628,14 @@ static bool detectAndDiagnoseErrors(Optional<SymbolicValue> errorInfo,
627628
/// Constant evaluate instructions starting from 'start' and fold the uses
628629
/// of the value 'oslogMessage'. Stop when oslogMessageValue is released.
629630
static void constantFold(SILInstruction *start,
630-
SingleValueInstruction *oslogMessage) {
631+
SingleValueInstruction *oslogMessage,
632+
unsigned assertConfig) {
631633

632634
// Initialize fold state.
633635
SmallVector<SILInstruction *, 2> lifetimeEndInsts;
634636
getLifetimeEndInstructionsOfSILValue(oslogMessage, lifetimeEndInsts);
635637

636-
FoldState state(start->getFunction(), start, lifetimeEndInsts);
638+
FoldState state(start->getFunction(), assertConfig, start, lifetimeEndInsts);
637639

638640
auto errorInfo = collectConstants(state);
639641

@@ -738,6 +740,7 @@ class OSLogOptimization : public SILFunctionTransform {
738740
/// The entry point to the transformation.
739741
void run() override {
740742
auto &fun = *getFunction();
743+
unsigned assertConfig = getOptions().AssertConfig;
741744

742745
// Don't rerun optimization on deserialized functions or stdlib functions.
743746
if (fun.wasDeserializedCanonical()) {
@@ -778,7 +781,7 @@ class OSLogOptimization : public SILFunctionTransform {
778781
continue;
779782
}
780783

781-
constantFold(interpolationStart, oslogInit);
784+
constantFold(interpolationStart, oslogInit, assertConfig);
782785
}
783786
}
784787
};

lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class ConstantEvaluableSubsetChecker : public SILModuleTransform {
6464
// Create a step evaluator and run it on the function.
6565
SymbolicValueBumpAllocator allocator;
6666
ConstExprStepEvaluator stepEvaluator(allocator, fun,
67+
getOptions().AssertConfig,
6768
/*trackCallees*/ true);
6869
bool previousEvaluationHadFatalError = false;
6970

lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class ConstantEvaluatorTester : public SILFunctionTransform {
5959
llvm::errs() << "@" << fun->getName() << "\n";
6060

6161
SymbolicValueBumpAllocator allocator;
62-
ConstExprStepEvaluator stepEvaluator(allocator, fun);
62+
ConstExprStepEvaluator stepEvaluator(allocator, fun,
63+
getOptions().AssertConfig);
6364

6465
for (auto currI = fun->getEntryBlock()->begin();;) {
6566
auto *inst = &(*currI);

0 commit comments

Comments
 (0)