Teach the SIL cast optimizer to handle conditional conformance.

Previously the cast optimizer bailed out on any conformance with
requirements.

We can now constant-propagate this:

```
protocol P {}
struct S<E> {
  var e: E
}

extension S : P where E == Int {}

func specializeMe<T>(_ t: T) {
  if let p = t as? P {
    // do fast things.
  }
}

specializeMe(S(e: 0))
```

This turns out to be as simple as calling the TypeChecker.

<rdar://problem/46375150> Inlining does not seem to handle
specialization properly for Data.

This enabled two SIL transformations required to optimize
the code above:

(1) The witness method call can be devirtualized.

(2) The allows expensive dynamic runtime checks such as:

  unconditional_checked_cast_addr Array<UInt8> in %array : $*Array<UInt8> to ContiguousBytes in %protocol : $*ContiguousBytes

Will be converted into:

  %value = init_existential_addr %existential : $*ContiguousBytes, $Array<UInt8>
  store %array to %value : $*Array<UInt8>
This commit is contained in:
Andrew Trick
2018-12-04 19:27:03 -08:00
parent a30c32dc7c
commit 0976c1f76e
6 changed files with 474 additions and 67 deletions

View File

@@ -392,6 +392,12 @@ public:
Optional<ProtocolConformanceRef>
lookupExistentialConformance(Type type, ProtocolDecl *protocol);
/// Exposes TypeChecker functionality for querying protocol conformance.
/// Returns a valid ProtocolConformanceRef only if all conditional
/// requirements are successfully resolved.
Optional<ProtocolConformanceRef>
conformsToProtocol(Type sourceTy, ProtocolDecl *targetProtocol);
/// Find a member named \p name in \p container that was declared in this
/// module.
///