LLD PGO - Clang, Swift on iOS apps

Hi,

We are experimenting with using LLD for iOS builds(PGO and ThinLTO) and want to clarify what’s actually supported when it comes to PGO.

From what I understand, Swift doesn’t currently support context-sensitive PGO (CS-PGO) - only IR-PGO instrumentation (-profile-generate / -profile-use).

So if we pass CS-PGO generation flags (-fcs-profile-generate) to Clang but only -profile-generate to Swift (since Swift doesn’t support CS-PGO), is that considered a valid combination?

Also, are there known issues that would make the community recommend using a specific commit/revision of LLD or Clang that are tested well in production use-cases?

Or are there recommended practices in the community for mixing Swift + Clang code in iOS apps when using PGO, ThinLTO with LLD?

Would love to hear how others are setting this up in production builds (or if people just stick to IR-PGO only for Swift) and what specific flags (Xllvm, Xcc) flags they pass to swiftc

cc: @ellishg - a few folks mentioned you might have the most context here, so tagging you for input. Thanks!

Yes, Swift PGO via -profile-generate is a front-end instrumentation I believe (it injects instrumentation at the SIL level), and isn’t going to work well with Clang’s -f{cs-}profile-generate (I wish these names were more descriptive).

What we want is for Swift to generate LLVM IR, and have LLVM inject instrumented code with -f{cs-}profile-generate. This works fine, but the flags have not been created to support this. You would need to call PGOOptions() in populatePGOOptions() in the same way the Clang does and call TargetMachine->setPGOOption(PGOOpt);.

I think you’ll also need to make sure compiler-rt is linked in.

1 Like

Thanks, @ellishg! Really appreciate your insights here.
Do you have suggestions on whether this can be done without compiler changes - for example,
what the swiftc flags would look like to forward -fcs-profile-generate down to LLVM/Clang and ensure the emitted IR is instrumented accordingly OR is modifying the toolchain the only way to go

If swiftc allows you to pass llvm flags, there’s probably a way to spell it, but that also gets complicated if you use LTO, since you often need to pass those same flags to the linker. I’d venture that its an OK approach for experimentation, but that its an entirely reasonable request for Swift to add an option for those profile types if they do not.

We would need to modify the toolchain for it to work in general. Although if you use CSIRPGO and either LTO or thinLTO, I think you can get away with just passing -fcs-profile-generate in the link step.

Unfortunately there is no way to enable IRPGO/CSIRPGO with LLVM flags alone. We need to call PGOOptions() in the driver.

dang. I had a rough memory of using profdata that way, but maybe I’m halucinating.

Thank you @ellishg and @ilovepi!

I have these changes that I’m currently exploring: link. Were you referring specifically to these changes, or would additional modifications be needed as well? I’ll be doing some testing, but I’d like to gather all the inputs so we can prepare a PR next week.

Clang Compiler User’s Manual — Clang 22.0.0git documentation has some how-to (and the rationale) information for-fcs-profile-generate option.

1 Like

I had to make a few additional changes in swift-driver (commit link). With these updates, temporal profiles are now being parsed correctly for Swift.

I’ll continue running more tests and then start a thread on the Swift forums to gather community feedback. In case I’ve missed anything, please feel free to point it out.

1 Like