Skip to content

Add Builtin.isConcrete<T>(T.Type) -> Int1 #26466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 29, 2019

Conversation

nvzqz
Copy link
Contributor

@nvzqz nvzqz commented Aug 2, 2019

Returns true if T.Type is known to refer to a concrete type during IRGen. Otherwise, if still generic, then it is lowered to false right before IRGen in IRGenPrepare. This allows for the optimizer to specialize this at -O and eliminate conditional code.

This also Includes:

  • Swift._isConcrete<T>(T.Type) -> Bool wrapper function.
  • tests on the [un]optimized SIL generated from calling isConcrete on generic and concrete types in -O[none] builds.

This is prior work to adding Builtin.generic_add<T>(T, T) -> T and friends for SIMD vector types.

@stephentyrone
Copy link
Contributor

Thanks @nvzqz! I'll take a look later today.

@stephentyrone
Copy link
Contributor

@swift-ci please smoke test

@jckarter
Copy link
Contributor

jckarter commented Aug 2, 2019

Our existing precedent for this is to name these sorts of things canBe. Check out canBeClass for an example. canBeClass also returns a tristate, because it ended up being valuable to know whether the answer is "definitely no", "definitely yes", or "maybe".

@stephentyrone
Copy link
Contributor

Our existing precedent for this is to name these sorts of things canBe. Check out canBeClass for an example. canBeClass also returns a tristate, because it ended up being valuable to know whether the answer is "definitely no", "definitely yes", or "maybe".

Is this actually tri-state logically though, or do we always know by the time we reach IRGen?

@jckarter
Copy link
Contributor

jckarter commented Aug 2, 2019

If you look at how TypeBase::canBeClass is implemented in the SILCombinerBuiltinVisitors, on top of TypeTraitResult TypeBase::canBeClass(), there should also be a bunch of existing code you can factor out and share between these two traits.

@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 2, 2019

@jckarter that name does seem better. I'm not sure if there's a way of expressing this as a tristate.

@jckarter
Copy link
Contributor

jckarter commented Aug 2, 2019

@nvzqz Maybe not in this case, but I think by following the pattern set by canBeClass, you could leverage a bunch of existing implementation, and make it easier to add more traits like this in the future.

@jckarter
Copy link
Contributor

jckarter commented Aug 2, 2019

The way that canBeClass works is that the optimizer immediately constant-folds to Is or IsNot when the trait method gives a definite answer, but leaves the builtin in place for CanBe. IRGen then lowers the builtin to the constant value CanBe if it hasn't already been lowered away. In the case of "is-concrete", the only interesting cases are Is and CanBe, I guess, but I think you still want to share the same approach, because this allows the builtin to constant-fold early, thereby allowing SIL-level optimizations to take advantage of the constant folding, without preventing it from also folding later as more information gets exposed.

@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 3, 2019

@swift-ci please smoke test

1 similar comment
@stephentyrone
Copy link
Contributor

@swift-ci please smoke test

Copy link
Contributor

@stephentyrone stephentyrone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, modulo @jckarter's questions about naming and reuse of existing code.

@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 5, 2019

After thinking about it some more, I'm not sure if a tri-state naming convention makes sense for this. I think that isConcrete already says what it does on the tin in that it expresses how the compiler sees the metatype in a given situation and configuration (e.g. -O and -Onone).


@jckarter I've attempted a different implementation that is done at the same stage as canBeClass but still using BUILTIN_MISC_OPERATION and returning a boolean. However, it's not producing the desired results and the compiler produces a segmentation fault in release builds. See nvzqz@010b6e3, branch.

See stack dump
0.	Program arguments: /Users/nvzqz/dev/swift-lang/build/Ninja-ReleaseAssert+stdlib-DebugAssert/swift-macosx-x86_64/bin/swiftc
	-frontend -target x86_64-apple-macosx10.9
	-module-cache-path /Users/nvzqz/dev/swift-lang/build/Ninja-ReleaseAssert+stdlib-DebugAssert/swift-macosx-x86_64/swift-test-results/x86_64-apple-macosx10.9/clang-module-cache
	-sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
	-swift-version 4 -typo-correction-limit 10
	-module-name constant_propagation_stdlib
	/Users/nvzqz/dev/swift-lang/swift/test/SILOptimizer/constant_propagation_stdlib.swift
	-parse-stdlib -emit-ir -o - -O
1.	Swift version 5.1-dev (LLVM 8d110eebee, Swift 74559a07d8)
2.	While running pass #71 SILFunctionTransform "SILCombine" on SILFunction "@$s27constant_propagation_stdlib15isConcrete_trueyBi1_AA5MyIntVF".
 for 'isConcrete_true(_:)' (at /Users/nvzqz/dev/swift-lang/swift/test/SILOptimizer/constant_propagation_stdlib.swift:19:8)
0  swiftc                   0x000000010d1b9155 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
1  swiftc                   0x000000010d1b8198 llvm::sys::RunSignalHandlers() + 248
2  swiftc                   0x000000010d1b9748 SignalHandler(int) + 264
3  libsystem_platform.dylib 0x00007fff76a16b5d _sigtramp + 29
4  libsystem_platform.dylib 000000000000000000 _sigtramp + 2304677056
5  swiftc                   0x0000000109b8ce52 swift::SILCombiner::runOnFunction(swift::SILFunction&) + 258
6  swiftc                   0x0000000109b8dc11 (anonymous namespace)::SILCombine::run() + 561
7  swiftc                   0x0000000109b7884f swift::SILPassManager::runPassOnFunction(unsigned int, swift::SILFunction*) + 1711
8  swiftc                   0x0000000109b7958f swift::SILPassManager::runFunctionPasses(unsigned int, unsigned int) + 1279
9  swiftc                   0x0000000109b7a43e swift::SILPassManager::execute() + 606
10 swiftc                   0x00000001097578db swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 187
11 swiftc                   0x0000000109b81a55 swift::runSILOptimizationPasses(swift::SILModule&) + 117
12 swiftc                   0x0000000109816901 swift::CompilerInstance::performSILProcessing(swift::SILModule*, swift::UnifiedStatsReporter*) + 977
13 swiftc                   0x000000010960738c performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 11564
14 swiftc                   0x0000000109603730 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3024
15 swiftc                   0x00000001095ab309 main + 729
16 libdyld.dylib            0x00007fff7682b3d5 start + 1
17 libdyld.dylib            0x0000000000000014 start + 2306690112
[1]    93337 segmentation fault   -frontend -target x86_64-apple-macosx10.9 -module-cache-path  -sdk   4  10

I'm of the opinion that the current changes are sufficient for now and that we should defer optimizing it or reusing the code for canBeClass. I'll see if this still happens when isConcrete does use a tri state via the same route as canBeClass; i.e. use BUILTIN_TYPE_TRAIT_OPERATION.

@gottesmm
Copy link
Contributor

gottesmm commented Aug 5, 2019

Just as an exploration of the state space, consider the following:

Imagine that we had a builtin called canBeConcrete. It returns either always, never, sometimes (i.e. a tri-state).

If we have a concrete type, easily the builtin must return always since once a type is concrete we can not further specialize it.

What about generic types? Easily, there are two possibilities:

  • If we are still allowing for further specialization, we want to return maybe. This ensures that we do not eliminate the builtin too early.

  • If we somehow have the knowledge that no matter specialization will occur (for whatever reason), then we can lower to never.

The key thing to notice is that the 2nd bullet point via our semantics is IRGen time/Lowered SIL. That might be the way forward for this in a way that keeps the logic of when to fold this in a utility that the various code can invoke.

Thats all I got.

NOTE: If we were to embed these semantics if we don't assert that the specialization machinery never runs in Lowered SIL, we would necessarily have to do so in order to be careful and prevent mistakes.

@jckarter
Copy link
Contributor

jckarter commented Aug 6, 2019

@nvzqz I commented on the linked commit. You should not be erasing the instruction from inside the SILCombiner method, since that will mess up SILCombiner's state. It'll clean up for you. You'd also need to implement the IRGen fallback implementation that emits false when the builtin still exists at IRGen time. With those changes, you should get the same benefits as canBeClass even if it isn't literally implemented the same. I don't care too much about the naming, but I think having an idiosyncratic name does help call attention to the fact that these have unusual compile-time-state behavior.

@nvzqz nvzqz force-pushed the is_concrete_builtin branch from d184918 to 45777bc Compare August 14, 2019 04:24
@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 14, 2019

I walked through my implementations of @jckarter's suggestions with @atrick and found places where it was ill-formed. The concerns I expressed to @airspeedswift and @gottesmm previously with regard to eager evaluation (always emitting false/0) were apparently an artifact of this.

@nvzqz nvzqz force-pushed the is_concrete_builtin branch from 45777bc to 44cc730 Compare August 14, 2019 04:41
@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 14, 2019

@swift-ci please smoke test

@stephentyrone stephentyrone self-requested a review August 15, 2019 12:10
/// this returns `false` if the check has failed.
///
/// Note that there may be cases in which, despite `T` being concrete at some
/// point in the caller chain, this function will return `false`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add that it will never return a false positive.

@airspeedswift
Copy link
Member

@swift-ci please smoke test

@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 20, 2019

@swift-ci please smoke test

@nvzqz nvzqz requested review from stephentyrone and atrick August 20, 2019 20:11
@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 20, 2019

@swift-ci please smoke test

@nvzqz nvzqz force-pushed the is_concrete_builtin branch from a3e180c to a73e146 Compare August 27, 2019 20:40
@nvzqz nvzqz requested a review from stephentyrone August 27, 2019 20:56
@stephentyrone
Copy link
Contributor

My concerns are resolved, but please check with @atrick to make sure he's satisfied with the updated SIL tests.

nvzqz added 12 commits August 27, 2019 16:51
Returns `true` if `T.Type` is known to refer to a concrete type. The
implementation allows for the optimizer to specialize this at -O and
eliminate conditional code.

Includes `Swift._isConcrete<T>(T.Type) -> Bool` wrapper function.
The `Builtin.isConcrete` function is apparently sensitive to inlining in
unoptimized builds.
Returns `false` otherwise in Debug builds because it is generic.
When calling `Builtin.isConcrete` in SIL, the provided type parameter
should be sufficient.
@nvzqz nvzqz force-pushed the is_concrete_builtin branch from c649378 to 931ab46 Compare August 27, 2019 23:51
@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 27, 2019

@atrick the SIL tests have been addressed as well as the concerns around constantFoldIsConcrete being called twice. 🙂

@airspeedswift
Copy link
Member

@atrick you good to go with this?

@airspeedswift
Copy link
Member

@swift-ci please smoke test

@airspeedswift airspeedswift removed their request for review August 28, 2019 21:41
Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the unreachable code in constandFoldBuiltin was removed. And the .sil test cases look reasonable. Thanks.

@nvzqz
Copy link
Contributor Author

nvzqz commented Aug 28, 2019

@swift-ci please test and merge

@swift-ci swift-ci merged commit b8f42d6 into swiftlang:master Aug 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants