Skip to content

Commit ef254c0

Browse files
committed
[Constant Evaluator] Add support for evaluating checked_cast_br
instruction and store_borrow.
1 parent a99f24f commit ef254c0

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,11 @@ NOTE(constexpr_untracked_sil_value_use_found, none,
419419
NOTE(constexpr_untracked_sil_value_used_here, none,
420420
"untracked variable used %select{here|by this call}0", (bool))
421421

422+
NOTE(constexpr_unevaluable_cast_found, none,
423+
"encountered an unevaluable cast", ())
424+
NOTE(constexpr_unevaluable_cast_used_here, none,
425+
"unevaluable cast encountered %select{here|by this call}0", (bool))
426+
422427
NOTE(constexpr_unresolvable_witness_call, none,
423428
"encountered unresolvable witness method call: '%0'", (StringRef))
424429
NOTE(constexpr_no_witness_table_entry, none, "cannot find witness table entry "

include/swift/SIL/SILConstants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ class UnknownReason {
120120
/// the interpreter.
121121
UntrackedSILValue,
122122

123+
/// Encountered a checked cast operation whose result cannot be evaluated
124+
/// to a constant.
125+
UnknownCastResult,
126+
123127
/// Attempted to find a concrete protocol conformance for a witness method
124128
/// and failed.
125129
UnknownWitnessMethodConformance,

lib/SIL/SILConstants.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,13 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) {
10001000
diagnose(ctx, triggerLoc, diag::constexpr_untracked_sil_value_used_here,
10011001
triggerLocSkipsInternalLocs);
10021002
return;
1003+
case UnknownReason::UnknownCastResult: {
1004+
diagnose(ctx, diagLoc, diag::constexpr_unevaluable_cast_found);
1005+
if (emitTriggerLocInDiag)
1006+
diagnose(ctx, triggerLoc, diag::constexpr_unevaluable_cast_used_here,
1007+
triggerLocSkipsInternalLocs);
1008+
return;
1009+
}
10031010
case UnknownReason::UnknownWitnessMethodConformance: {
10041011
SmallString<8> witnessMethodName;
10051012
getWitnessMethodName(dyn_cast<WitnessMethodInst>(unknownNode),

lib/SILOptimizer/Utils/ConstExpr.cpp

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
#define DEBUG_TYPE "ConstExpr"
1414
#include "swift/SILOptimizer/Utils/ConstExpr.h"
1515
#include "swift/AST/ProtocolConformance.h"
16+
#include "swift/AST/SemanticAttrs.h"
1617
#include "swift/AST/SubstitutionMap.h"
1718
#include "swift/Basic/Defer.h"
1819
#include "swift/Basic/NullablePtr.h"
19-
#include "swift/AST/SemanticAttrs.h"
2020
#include "swift/Demangling/Demangle.h"
2121
#include "swift/SIL/ApplySite.h"
22+
#include "swift/SIL/DynamicCasts.h"
2223
#include "swift/SIL/FormalLinkage.h"
2324
#include "swift/SIL/SILBuilder.h"
2425
#include "swift/SIL/SILConstants.h"
@@ -1684,7 +1685,7 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
16841685
if (auto apply = dyn_cast<ApplyInst>(inst))
16851686
return computeCallResult(apply);
16861687

1687-
if (isa<StoreInst>(inst)) {
1688+
if (isa<StoreInst>(inst) || isa<StoreBorrowInst>(inst)) {
16881689
auto stored = getConstantValue(inst->getOperand(0));
16891690
if (!stored.isConstant())
16901691
return stored;
@@ -1837,6 +1838,50 @@ ConstExprFunctionState::evaluateInstructionAndGetNext(
18371838
return {caseBB->begin(), None};
18381839
}
18391840

1841+
if (isa<CheckedCastBranchInst>(inst)) {
1842+
CheckedCastBranchInst *checkedCastInst =
1843+
dyn_cast<CheckedCastBranchInst>(inst);
1844+
SymbolicValue value = getConstantValue(checkedCastInst->getOperand());
1845+
if (!value.isConstant())
1846+
return {None, value};
1847+
1848+
// Determine success or failure of this cast.
1849+
CanType sourceType;
1850+
if (value.getKind() == SymbolicValue::Array) {
1851+
sourceType = value.getArrayType()->getCanonicalType();
1852+
} else {
1853+
// Here, the source type cannot be an address-only type as this is
1854+
// not a CheckedCastBranchAddr inst. Therefore, it has to be a struct
1855+
// type or String or Metatype. Since the types of aggregates are not
1856+
// tracked, we recover it from the declared type of the source operand
1857+
// and generic parameter subsitutions in the interpreter state.
1858+
sourceType = substituteGenericParamsAndSimpify(
1859+
checkedCastInst->getSourceFormalType());
1860+
}
1861+
CanType targetType = substituteGenericParamsAndSimpify(
1862+
checkedCastInst->getTargetFormalType());
1863+
DynamicCastFeasibility castResult = classifyDynamicCast(
1864+
inst->getModule().getSwiftModule(), sourceType, targetType);
1865+
if (castResult == DynamicCastFeasibility::MaySucceed) {
1866+
return {None,
1867+
getUnknown(evaluator, inst, UnknownReason::UnknownCastResult)};
1868+
}
1869+
// Determine the basic block to jump to.
1870+
SILBasicBlock *resultBB =
1871+
(castResult == DynamicCastFeasibility::WillSucceed)
1872+
? checkedCastInst->getSuccessBB()
1873+
: checkedCastInst->getFailureBB();
1874+
// Set up the arguments of the basic block, if any.
1875+
if (resultBB->getNumArguments() == 0)
1876+
return {resultBB->begin(), None};
1877+
// There should be at most one argument to the basic block, which is the
1878+
// casted value with the right type, or the input value if the cast fails,
1879+
// and inst is in OSSA.
1880+
assert(resultBB->getNumArguments() == 1);
1881+
setValue(resultBB->getArgument(0), value);
1882+
return {resultBB->begin(), None};
1883+
}
1884+
18401885
LLVM_DEBUG(llvm::dbgs() << "ConstExpr: Unknown Branch Instruction: " << *inst
18411886
<< "\n");
18421887

test/SILOptimizer/constant_evaluable_subset_test.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,3 +892,22 @@ func testArrayOfClosures(_ byte: @escaping () -> Int) -> [(Int) -> Int] {
892892
func interpretArrayOfClosures() -> [(Int) -> Int] {
893893
return testArrayOfClosures({ 10 })
894894
}
895+
896+
// Test checked casts.
897+
898+
// CHECK-LABEL: @testMetaTypeCast
899+
// CHECK-NOT: error:
900+
@_semantics("constant_evaluable")
901+
func testMetaTypeCast<T>(_ x: T.Type) -> Bool {
902+
return (x is Int.Type)
903+
}
904+
905+
@_semantics("test_driver")
906+
func interpretMetaTypeCast() -> Bool {
907+
return testMetaTypeCast(Int.self)
908+
}
909+
910+
// FIXME: this cast is not found to be false by the classifyDynamicCast utility.
911+
func interpretMetaTypeCast2() -> Bool {
912+
return testMetaTypeCast(((Int) -> Int).self)
913+
}

test/SILOptimizer/constant_evaluator_test.sil

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,3 +1475,31 @@ bb0:
14751475
return %3 : $@callee_guaranteed () -> Int64
14761476
} // CHECK: Returns closure: target: closure4 captures
14771477
// CHECK-NEXT: values:
1478+
1479+
// Tests for checked cast instruction.
1480+
1481+
sil [ossa] @testMetatypeCast : $@convention(thin) <T> (@thick T.Type) -> Builtin.Int1 {
1482+
bb0(%0 : $@thick T.Type):
1483+
checked_cast_br %0 : $@thick T.Type to Int64.Type, bb1, bb2
1484+
1485+
bb1(%3 : $@thick Int64.Type):
1486+
%4 = metatype $@thin Int64.Type
1487+
%5 = integer_literal $Builtin.Int1, -1
1488+
br bb3(%5 : $Builtin.Int1)
1489+
1490+
bb2(%7 : $@thick T.Type):
1491+
%8 = integer_literal $Builtin.Int1, 0
1492+
br bb3(%8 : $Builtin.Int1)
1493+
1494+
bb3(%10 : $Builtin.Int1):
1495+
return %10 : $Builtin.Int1
1496+
}
1497+
1498+
// CHECK-LABEL: @interpretMetatypeCast
1499+
sil [ossa] @interpretMetatypeCast : $@convention(thin) () -> Builtin.Int1 {
1500+
bb0:
1501+
%1 = metatype $@thick Int64.Type
1502+
%2 = function_ref @testMetatypeCast : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Builtin.Int1
1503+
%3 = apply %2<Int64>(%1) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> Builtin.Int1
1504+
return %3 : $Builtin.Int1
1505+
} // CHECK: Returns int: -1

0 commit comments

Comments
 (0)