Skip to content

Commit 881526f

Browse files
committed
---
yaml --- r: 311295 b: refs/heads/tensorflow-merge c: f738d23 h: refs/heads/master i: 311293: d547a11 311291: 43dc3f4 311287: fd23282 311279: 3a1d5e0 311263: b5a60c1 311231: 28636ac 311167: 6f1eff1 311039: 54c8d39 310783: 1d190a0 310271: 3367229 309247: fc77328 307199: fae99bb 303103: 0224212 294911: 1f1cc10
1 parent 674788d commit 881526f

File tree

8 files changed

+167
-81
lines changed

8 files changed

+167
-81
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1379,7 +1379,7 @@ refs/heads/chase-my-tail: 8bb91443a9e81bbfac92a2621a0af887a1da8dbf
13791379
refs/heads/consider-outer-alternatives: 708bac749ec60a22a79e2eefbe734f9488a7370d
13801380
refs/heads/revert-25740-oops-i-linked-it-again: fdd41aeb682fc488572bdc1cf71b2ff6997ba576
13811381
refs/heads/swift-5.1-branch-06-12-2019: e63b7b2d3b93c48232d386099d0ec525d21d8f8d
1382-
refs/heads/tensorflow-merge: da93d3e5a7d92853001c6b5674960d5fa93a415b
1382+
refs/heads/tensorflow-merge: f738d231e6e37f24218610c50e3907bdae700746
13831383
refs/heads/update-checkout-sha-info: 5832743c5c2a842976c42a508a4c6dcceefb0aef
13841384
refs/tags/swift-5.1-DEVELOPMENT-SNAPSHOT-2019-06-12-a: 228f0448d9bb909aacbba4afcb7c600a405d15da
13851385
refs/tags/swift-5.1-DEVELOPMENT-SNAPSHOT-2019-06-14-a: 922861a77b5fc2bf46bc917da70ceb15eef76836

branches/tensorflow-merge/include/swift/SIL/SILConstants.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,13 @@ enum class UnknownReason {
4545
TooManyInstructions,
4646

4747
/// A control flow loop was found.
48-
Loop
48+
Loop,
49+
50+
/// Integer overflow detected.
51+
Overflow,
52+
53+
/// Unspecified trap detected.
54+
Trap,
4955
};
5056

5157

branches/tensorflow-merge/include/swift/SIL/SILModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ class SILModule {
268268
SILModule(const SILModule&) = delete;
269269
void operator=(const SILModule&) = delete;
270270

271+
// SWIFT_ENABLE_TENSORFLOW
272+
public:
271273
/// Method which returns the SerializedSILLoader, creating the loader if it
272274
/// has not been created yet.
273275
SerializedSILLoader *getSILLoader();

branches/tensorflow-merge/lib/SIL/SILConstants.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,7 @@ void SymbolicValue::print(llvm::raw_ostream &os, unsigned indent) const {
3535
case RK_UninitMemory: os << "uninit\n"; return;
3636
case RK_Unknown: {
3737
std::pair<SILNode *, UnknownReason> unknown = getUnknownValue();
38-
switch (unknown.second) {
39-
case UnknownReason::Default: os << "unknown: "; break;
40-
case UnknownReason::TooManyInstructions: os << "unknown(toobig): "; break;
41-
case UnknownReason::Loop: os << "unknown(loop): "; break;
42-
}
38+
os << "unknown(" << (int)unknown.second << "): ";
4339
unknown.first->dump();
4440
return;
4541
}
@@ -446,14 +442,21 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) {
446442
case UnknownReason::Loop:
447443
error = "control flow loop found";
448444
break;
445+
case UnknownReason::Overflow:
446+
error = "integer overflow detected";
447+
break;
448+
case UnknownReason::Trap:
449+
error = "trap detected";
450+
break;
449451
}
450452

451453
auto &module = badInst->getModule();
452454

453455
auto loc = skipInternalLocations(badInst->getDebugLocation()).getLocation();
454456
if (loc.isNull()) {
455457
// If we have important clarifying information, make sure to emit it.
456-
if (unknown.second != UnknownReason::Default)
458+
if (unknown.second == UnknownReason::Default ||
459+
fallbackLoc.isNull())
457460
return;
458461
loc = fallbackLoc;
459462
}

branches/tensorflow-merge/lib/SILOptimizer/Mandatory/TFConstExpr.cpp

Lines changed: 132 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,30 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap,
4343
// ConstantFolding.h/cpp files should be subsumed by this, as this is a more
4444
// general framework.
4545

46+
47+
// We have a list of functions that we hackily special case. In order to keep
48+
// this localized, we use this classifier function. This should be replaced
49+
// with an attribute put on the standard library that captures this info.
50+
enum class WellKnownFunction {
51+
Unknown,
52+
StringInitEmpty, // String.init()
53+
AssertionFailure, // _assertionFailure(_:_:file:line:flags:)
54+
};
55+
56+
57+
static WellKnownFunction classifyFunction(StringRef mangledName) {
58+
if (mangledName == "$SS2SycfC")
59+
return WellKnownFunction::StringInitEmpty;
60+
61+
if (mangledName.contains("_assertionFailure"))
62+
return WellKnownFunction::AssertionFailure;
63+
return WellKnownFunction::Unknown;
64+
}
65+
66+
67+
4668
//===----------------------------------------------------------------------===//
47-
// MemoryValue implementation.
69+
// AddressValue implementation.
4870
//===----------------------------------------------------------------------===//
4971

5072
namespace {
@@ -253,6 +275,10 @@ namespace {
253275

254276
AddressValue computeSingleStoreAddressValue(SILValue addr);
255277
llvm::Optional<SymbolicValue> computeCallResult(ApplyInst *apply);
278+
279+
llvm::Optional<SymbolicValue>
280+
computeOpaqueCallResult(ApplyInst *apply, SILFunction *callee);
281+
256282
SymbolicValue computeLoadResult(SILValue addr);
257283
llvm::Optional<SymbolicValue> computeFSStore(SymbolicValue storedCst,
258284
SILValue dest);
@@ -268,20 +294,9 @@ Type ConstExprFunctionState::simplifyType(Type ty) {
268294
return substitutionMap.empty() ? ty : ty.subst(substitutionMap);
269295
}
270296

271-
/// Lazily initialize the specified SIL Loader.
272-
static SerializedSILLoader &
273-
initLoader(std::unique_ptr<SerializedSILLoader> &silLoader, SILModule &module) {
274-
if (!silLoader)
275-
silLoader = SerializedSILLoader::create(module.getASTContext(),
276-
&module, nullptr);
277-
return *silLoader;
278-
}
279-
280-
281297
// TODO: refactor this out somewhere sharable between autodiff and this code.
282298
static void lookupOrLinkWitnessTable(ProtocolConformanceRef confRef,
283-
SILModule &module,
284-
std::unique_ptr<SerializedSILLoader> &silLoader) {
299+
SILModule &module) {
285300
// Cannot resolve abstract conformances.
286301
if (!confRef.isConcrete())
287302
return;
@@ -295,7 +310,8 @@ static void lookupOrLinkWitnessTable(ProtocolConformanceRef confRef,
295310
conf->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
296311
auto linkage = getSILLinkage(getDeclLinkage(decl), NotForDefinition);
297312
auto *newTable = module.createWitnessTableDeclaration(conf, linkage);
298-
newTable = initLoader(silLoader, module).lookupWitnessTable(newTable);
313+
newTable = module.getSILLoader()->lookupWitnessTable(newTable);
314+
299315
// Update linkage for witness methods.
300316
// FIXME: Figure out why witnesses have shared linkage by default.
301317
for (auto &entry : newTable->getEntries())
@@ -374,8 +390,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
374390
module.lookUpFunctionInWitnessTable(conf, wmi->getMember()).first;
375391
if (!fn) {
376392
// If that failed, try force loading it, and try again.
377-
lookupOrLinkWitnessTable(conf, wmi->getModule(),
378-
evaluator.getSILLoader());
393+
lookupOrLinkWitnessTable(conf, wmi->getModule());
379394
fn = module.lookUpFunctionInWitnessTable(conf, wmi->getMember()).first;
380395
}
381396

@@ -416,7 +431,27 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
416431
return SymbolicValue::getUnknown(SILValue(inst), UnknownReason::Default);
417432
};
418433

419-
// Unary operations first.
434+
// Nullary operations.
435+
if (inst->getNumOperands() == 0) {
436+
switch (builtin.ID) {
437+
default: break;
438+
case BuiltinValueKind::AssertConf: {
439+
// assert_configuration builtin gets replaces with debug/release/etc
440+
// constants.
441+
auto config = inst->getModule().getOptions().AssertConfig;
442+
// Don't replace assert_configuration if we're not supposed to.
443+
if (config == SILOptions::DisableReplacement)
444+
break;
445+
auto resultBitWidth =
446+
inst->getType().castTo<BuiltinIntegerType>()->getGreatestWidth();
447+
auto result = APInt(resultBitWidth, config);
448+
return SymbolicValue::getInteger(result, evaluator.getAllocator());
449+
}
450+
}
451+
}
452+
453+
454+
// Unary operations.
420455
if (inst->getNumOperands() == 1) {
421456
auto operand = getConstantValue(inst->getOperand(0));
422457
// TODO: Could add a "value used here" sort of diagnostic.
@@ -451,6 +486,10 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
451486
if (builtin.ID == BuiltinValueKind::UToSCheckedTrunc)
452487
overflowed |= result.isSignBitSet();
453488

489+
if (overflowed)
490+
return SymbolicValue::getUnknown(SILValue(inst),
491+
UnknownReason::Overflow);
492+
454493
auto &allocator = evaluator.getAllocator();
455494
// Build the Symbolic value result for our truncated value.
456495
return SymbolicValue::getAggregate({
@@ -663,14 +702,20 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
663702
[&](const std::function<APInt(const APInt &, const APInt &, bool &)> &fn)
664703
-> SymbolicValue {
665704
if (operand0.getKind() != SymbolicValue::Integer ||
666-
operand1.getKind() != SymbolicValue::Integer)
705+
operand1.getKind() != SymbolicValue::Integer ||
706+
operand2.getKind() != SymbolicValue::Integer)
667707
return unknownResult();
668708

669-
// TODO: We can/should diagnose statically detectable integer overflow
670-
// errors and subsume the ConstantFolding.cpp mandatory SIL pass.
671709
auto l = operand0.getIntegerValue(), r = operand1.getIntegerValue();
672710
bool overflowed = false;
673711
auto result = fn(l, r, overflowed);
712+
713+
// Return a statically diagnosed overflow if the operation is supposed to
714+
// trap on overflow.
715+
if (overflowed && !operand2.getIntegerValue().isNullValue())
716+
return SymbolicValue::getUnknown(SILValue(inst),
717+
UnknownReason::Overflow);
718+
674719
auto &allocator = evaluator.getAllocator();
675720
// Build the Symbolic value result for our normal and overflow bit.
676721
return SymbolicValue::getAggregate({
@@ -714,6 +759,34 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
714759
return unknownResult();
715760
}
716761

762+
// Handle calls to opaque callees, either by handling them and returning None or
763+
// by returning with a Unknown indicating a failure.
764+
llvm::Optional<SymbolicValue>
765+
ConstExprFunctionState::computeOpaqueCallResult(ApplyInst *apply,
766+
SILFunction *callee) {
767+
// This is a termination point like fatalError.
768+
if (callee->hasSemanticsAttr("arc.programtermination_point")) {
769+
// TODO: Actually get the message out of fatalError. We can literally get
770+
// its string and file/line/col info and propagate it up!
771+
return SymbolicValue::getUnknown((SILInstruction*)apply,
772+
UnknownReason::Trap);
773+
}
774+
775+
if (classifyFunction(callee->getName()) ==
776+
WellKnownFunction::AssertionFailure) {
777+
// TODO: Actually get the message out of fatalError. We can literally get
778+
// its string and file/line/col info and propagate it up!
779+
return SymbolicValue::getUnknown((SILInstruction*)apply,
780+
UnknownReason::Trap);
781+
}
782+
783+
DEBUG(llvm::errs() << "ConstExpr Opaque Callee: " << *callee << "\n");
784+
return SymbolicValue::getUnknown((SILInstruction*)apply,
785+
UnknownReason::Default);
786+
}
787+
788+
789+
// TODO: Refactor this to someplace common, this is defined in Devirtualize.cpp.
717790
SubstitutionMap
718791
getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI, SILFunction *F,
719792
ProtocolConformanceRef CRef);
@@ -726,48 +799,45 @@ llvm::Optional<SymbolicValue>
726799
ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
727800
auto conventions = apply->getSubstCalleeConv();
728801

729-
// The many failure paths through this function invoke this to return their
730-
// failure information.
731-
auto failure = [&](UnknownReason reason) -> SymbolicValue {
732-
auto unknown = SymbolicValue::getUnknown((SILInstruction*)apply, reason);
733-
// Remember that this call produced unknown as well as any indirect results.
734-
calculatedValues[apply] = unknown;
735-
736-
for (unsigned i = 0, e = conventions.getNumIndirectSILResults();
737-
i != e; ++i) {
738-
auto resultOperand = apply->getOperand(i+1);
739-
assert(resultOperand->getType().isAddress() &&
740-
"Indirect results should be by-address");
741-
calculatedValues[resultOperand] = unknown;
742-
}
743-
return unknown;
744-
};
745-
746802
// Determine the callee.
747-
auto calleeLV = getConstantValue(apply->getOperand(0));
748-
if (!calleeLV.isConstant())
749-
return failure(UnknownReason::Default);
803+
auto calleeFn = getConstantValue(apply->getOperand(0));
804+
if (!calleeFn.isConstant())
805+
return SymbolicValue::getUnknown((SILInstruction*)apply,
806+
UnknownReason::Default);
750807

751808
SILFunction *callee;
752809
Optional<ProtocolConformanceRef> conformance;
753-
std::tie(callee, conformance) = calleeLV.getFunctionValue();
810+
std::tie(callee, conformance) = calleeFn.getFunctionValue();
754811

755812

756813
// If we reached an external function that hasn't been deserialized yet, make
757814
// sure to pull it in so we can see its body. If that fails, then we can't
758815
// analyze the function.
759816
if (callee->isExternalDeclaration()) {
760-
auto newCallee = initLoader(evaluator.getSILLoader(),
761-
callee->getModule()).lookupSILFunction(callee);
762-
if (!newCallee || newCallee->isExternalDeclaration()) {
763-
DEBUG(llvm::errs() << "ConstExpr Opaque Callee: " << *callee << "\n");
764-
return failure(UnknownReason::Default);
765-
}
766-
callee = newCallee;
817+
callee->getModule().loadFunction(callee);
818+
if (callee->isExternalDeclaration())
819+
return computeOpaqueCallResult(apply, callee);
767820
}
768821

769822
// TODO: Verify that the callee was defined as a @constexpr function.
770823

824+
// If this is a well-known function, do not step into it.
825+
//
826+
// FIXME: This should be based on the SILFunction carrying a
827+
// @constexprSemantics sort of attribute that indicates it is well known,
828+
// just like the existing SemanticsAttr thing.
829+
switch (classifyFunction(callee->getName())) {
830+
default: break;
831+
case WellKnownFunction::StringInitEmpty: { // String.init()
832+
assert(conventions.getNumDirectSILResults() == 1 &&
833+
conventions.getNumIndirectSILResults() == 0 &&
834+
"unexpected String.init() signature");
835+
auto result = SymbolicValue::getString("", evaluator.getAllocator());
836+
setValue(apply->getResults()[0], result);
837+
return None;
838+
}
839+
}
840+
771841
// Verify that we can fold all of the arguments to the call.
772842
SmallVector<SymbolicValue, 4> paramConstants;
773843
unsigned applyParamBaseIndex = 1+conventions.getNumIndirectSILResults();
@@ -834,7 +904,7 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
834904
if (unsigned numNormalResults = conventions.getNumDirectSILResults()) {
835905
// TODO: unclear when this happens, is this for tuple result values?
836906
assert(numNormalResults == 1 && "Multiple results aren't supported?");
837-
calculatedValues[apply->getResults()[0]] = results[nextResult];
907+
setValue(apply->getResults()[0], results[nextResult]);
838908
++nextResult;
839909
}
840910

@@ -863,6 +933,13 @@ SymbolicValue ConstExprFunctionState::getConstantValue(SILValue value) {
863933

864934
// Compute the value of a normal instruction based on its operands.
865935
auto result = computeConstantValue(value);
936+
937+
// If this is the top-level lazy interpreter, output a debug trace.
938+
if (!fn) {
939+
DEBUG(llvm::errs() << "ConstExpr top level: "; value->dump());
940+
DEBUG(llvm::errs() << " RESULT: "; result.dump());
941+
}
942+
866943
return calculatedValues[value] = result;
867944
}
868945

@@ -1185,11 +1262,12 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
11851262

11861263
if (isa<CondFailInst>(inst)) {
11871264
auto failed = getConstantValue(inst->getOperand(0));
1188-
if (failed.isConstant() && failed.getIntegerValue() == 0)
1189-
return None;
1190-
// TODO: Emit a diagnostic if this cond_fail actually fails under constant
1191-
// folding.
1192-
DEBUG(llvm::errs() << "CONDFAIL FAILED!\n");
1265+
if (failed.getKind() == SymbolicValue::Integer) {
1266+
if (failed.getIntegerValue() == 0)
1267+
return None;
1268+
// Conditional fail actually failed.
1269+
return SymbolicValue::getUnknown(inst, UnknownReason::Trap);
1270+
}
11931271
}
11941272

11951273
// If this is a call, evaluate it.

branches/tensorflow-merge/lib/SILOptimizer/Mandatory/TFConstExpr.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ namespace swift {
3232
class SILBuilder;
3333
class SILModule;
3434
class SILValue;
35-
class SerializedSILLoader;
3635
class SymbolicValue;
3736

3837
namespace tf {
@@ -44,17 +43,13 @@ class ConstExprEvaluator {
4443
/// result values for the cached constexpr calls we have already analyzed.
4544
llvm::BumpPtrAllocator allocator;
4645

47-
/// This is a handle to a loader for serialized code.
48-
std::unique_ptr<SerializedSILLoader> silLoader;
49-
5046
ConstExprEvaluator(const ConstExprEvaluator &) = delete;
5147
void operator=(const ConstExprEvaluator &) = delete;
5248
public:
5349
explicit ConstExprEvaluator(SILModule &m);
5450
~ConstExprEvaluator();
5551

5652
llvm::BumpPtrAllocator &getAllocator() { return allocator; }
57-
std::unique_ptr<SerializedSILLoader> &getSILLoader() { return silLoader; }
5853

5954
/// Analyze the specified values to determine if they are constant values.
6055
/// This is done in code that is not necessarily itself a constexpr

0 commit comments

Comments
 (0)