Skip to content
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

[SR-7277] -Onone should inline @inline(__always) #49825

Open
atrick opened this issue Mar 26, 2018 · 9 comments
Open

[SR-7277] -Onone should inline @inline(__always) #49825

atrick opened this issue Mar 26, 2018 · 9 comments
Labels
compiler The Swift compiler in itself improvement

Comments

@atrick
Copy link
Member

atrick commented Mar 26, 2018

Previous ID SR-7277
Radar rdar://23309007
Original Reporter @atrick
Type Improvement
Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Improvement
Assignee None
Priority Medium

md5: 5b473394d4161c33c60f34650a4dfd6d

relates to:

  • SR-7278 -Onone should inline no-escape closures
  • SR-8742 Terrible performance with Range iteration in -Onone
  • SR-7274 More UnsafePointer operations should be @transparent

Issue Description:

There needs to be a way to force inlining at -Onone. @inline(__always) is a fine way to do that for now.

This probably has to be done as a separate -Onone inlining pass, because we don't want that inlining to affect diagnostics.

@atrick
Copy link
Member Author

atrick commented Mar 26, 2018

@swift-ci create

@atrick
Copy link
Member Author

atrick commented Apr 20, 2018

Remember: as with "early inlining" in the -O pipeline, any additional -Onone inlining pass should never inline an @semantics function, even when it is marked @inline(__always). Inlining those is illegal until after SIL serialization. e.g. inlining optimize.sil.preserve.exclusivity before serialization would be catastrophic.

@atrick
Copy link
Member Author

atrick commented Dec 6, 2018

@eeckstein, @airspeedswift, @milseman
I think we should have consensus on fixing this bug before we get much
further into annotating the stdlib.

There are two kinds of stdlib functions that need to be annotated:

(1) Macro-ish functions that should be inlined at -Onone, even when
they are not specialized, and which we generally don't care about
stepping into.

[I think this should be @inline(__always).]

(2) Helpers (typically generic) that we need to heavily bias toward inlining when the
caller is already specialized because:

  • we have special knowledge of how these stdlib functions tend to be used in hot loops

  • we happen to know that most of the abstraction will fold away when inlining

  • we need very predictable performance for key language features

[I think this should be @inline(__optimized).]

The behavior of @inline(__optimized) should be: inline whenever the
caller is specialized AND not on a cold path.

@belkadan, the argument against my proposal is that @_transparent already serves
the first purpose, and that we can just change @inline(__always) to
behave in the aforementioned manner. I think that argument is wrong
for two reasons but I need help making the point...

So, why can't @transparent be used in those cases where we truly want
guaranteed inlining and don't care too much about stepping into the
function?

Take for example:

private var kCFStringEncodingASCII : _swift_shims_CFStringEncoding {
  @inline(__always) get { return 0x0600 }
}

private var kCFStringEncodingUTF8 : _swift_shims_CFStringEncoding {
  @inline(__always) get { return 0x8000100 }
}

extension Unicode.Scalar {
  @inline(__always) // common fast-path
  internal var _hasNormalizationBoundaryBefore: Bool {
    // Fast-path: All scalars up through U+02FF are NFC and have boundaries
    // before them
    if self.value < 0x300 { return true }

    _internalInvariant(Int32(exactly: self.value) != nil, "top bit shouldn't be set")
    let value = Int32(bitPattern: self.value)
    return 0 != __swift_stdlib_unorm2_hasBoundaryBefore(
      _Normalization._nfcNormalizer, value)
  }
}


On the other point of argument, I think it's wrong to change the
behavior of @inline(__always) to only work on warm, specialized
code. We do need a way to control generic inlining, and
@inline(__always) is a perfect way to do that. As an example, at
-Onone we need to remove copies that cause uniqueness checks to fail
in cases where there is obviously no user-level copy. What's more, the
expectation of any sane person is that @inline(__always) predictably
does what it says.

@belkadan
Copy link
Contributor

belkadan commented Dec 6, 2018

_transparent is for diagnostics, which means it affects the speed of Live Issues. I don't think we want to pay the time inlining other things at that point.

I think separating (1) and (2) is reasonable, but I still think there's a difference between (1) and _transparent.

@belkadan
Copy link
Contributor

belkadan commented Dec 6, 2018

(Alternately, I'd be fine with not having (1), just (2) under its new name, but then I'm worried people will say "oh, this really needs to be inlined at -Onone" and start abusing _transparent for it.)

@atrick
Copy link
Member Author

atrick commented Dec 6, 2018

@inline(__always) is still a useful way to control, test, and experiment with generic inlining at -Onone, regardless of whether it's absolutely required for the stdlib.

I'm mainly advocating that we add @inline(__optimized) with somewhat different behavior from @inline(__always) , and start using that instead in at least most of the stdlib APIs.

@atrick
Copy link
Member Author

atrick commented Dec 6, 2018

To elaborate, I'm sure we will eventually need to do much more performance work for -Onone and @inline(__always) will become more useful over time.

@eeckstein
Copy link
Member

The concern I have with adding more attribute variations is that it's hard to explain when to use which one. Even today people are confused about transparent vs inline(__always).

@atrick
Copy link
Member Author

atrick commented Dec 7, 2018

The proposed naming eliminates the current confusion about which annotation to use.

Anyone reaching for "always inline" will naturally use @inline(__always) and get precisely what they ask for.

People will stop mistakenly using @_transparent when they just need -Onone inlining. It's for a very specific diagnostic purpose. I think many of the current uses should actually be @inline(__always). As @belkadan said, we don't want all these misuses of `@transparent` slowing down Live issues. It should only be used for overflow checking on the numeric types and a few builtins, maybe like withoutActuallyEscaping. The fact that it's being misused now is exactly why it's so confusing.

Most of the cases we have been adding to the stdlib recently are actually "try hard to inline this into optimized code". Naturally those should use @inline(__optimized) to get the new and improved behavior. The difference between this and normal inlining is that it shifts the burden of proof on the optimizer: prove this should not be inlined rather than prove that it should be inlined.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler The Swift compiler in itself improvement
Projects
None yet
Development

No branches or pull requests

3 participants