Sret in llvm 13.0 breaks compatibility with swift

Hi, I'm sure the Swift core team are familiar with this underlying problem so I thought I'd ping on here to see if anyone can give advice or insight.

I have tried upgrading my standalone bitcode/llvm-IR compiler backend to LLVM 13.0 as I want all the latest bugfixes for my back end.

However it will no longer compile LLVM IR output by Swift (to be honest I haven't tried binary bitcode yet because I assumed if the text version is incompatible then the binary version will surely be horrrendously incompatible).

It seems that the issue is that around November last year, the LLVM project changed the sret keyword to have a mandatory type, like sret(%myStructType), which was a breaking change in terms of LLVM IR compatibility between versions.

I tried upgrading my swiftc to release/5.4 and trying again but it seems like even version 5.4 does not have this llvm change.

Can anyone explain what I'm doing wrong or give me some advice how to fix this please?

You cannot update LLVM arbitrarily without updating Swift to match. Swift's main branch generally follows LLVM's main branch, and when we cut release branches for Swift, we cut matching LLVM branches too. Unfortunately, you can't take an older Swift branch, switch out a newer LLVM, and expect it to just work, because LLVM is not a stable interface.

3 Likes

So, to clarify a little...

I checked out release/5.4 from swift then did an utils/update-checkout --scheme release/5.4 after this, the swift directory is synced to the release/5.4 branch with the llvm-project directory synced to the swift/release/5.4 branch from the fork https://github.com/apple/llvm-project.git as you'd expect. This builds and produces a valid swiftc, etc.

I then run the swift compile but I output using --emit-ir to make LLVM IR files.

Call them X.ll, Y.ll, Z.ll, etc...

In a completely separate folder elsewhere on the drive, I have checked out the tag llvmorg-13-init from the branch main from https://github.com/llvm/llvm-project.git and built clang, llc, lld, etc. there.

I use this llc to compile the LLVM IR files that swiftc produced...

bin/llc X.ll -o X.o ... etc.

This is usually working, but sometimes failing in some project, because it encounters an sret attribute on a function parameter. swift 5.4 is producing sret without a type parameter but the llc expects sret to have a type with it, so it won't compile those files. This is a new problem.

Interestingly, I tried using bitcode instead of llvm IR, this afternoon (after writing this post) and it works fine!

I appreciate that llvm isn't exactly a stable interface and LLVM IR isn't a 100% stable "language" really... What I don't quite understand is... the version of LLVM I'm building llc from is from the main branch about January this year... swift release/5.4 is just a few weeks old... so it should have a much more up to date version of llvm? Given that making a type parameter mandatory in sret seems to have occurred on llvm main starting some time in November last year, I don't quite understand why that's not in the llvm that is in swift release/5.4?

When I look at llvm-project/llvm/lib/AsmParser/LLParser.cpp, in the llvm folder where I'm tracking 13.0, the function bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) has this code in it (around line 1712)...

    case lltok::kw_sret: {
      Type *Ty;
      if (parseRequiredTypeAttr(Ty, lltok::kw_sret))
        return true;
      B.addStructRetAttr(Ty);
      continue;
    }

...but in the swift/release/5.4 version the keyword seems to only be in a general block with other similar attributes...

    case lltok::kw_byval:
    case lltok::kw_inalloca:
    case lltok::kw_nest:
    case lltok::kw_nocapture:
    case lltok::kw_returned:
    case lltok::kw_sret:
    case lltok::kw_swifterror:
    case lltok::kw_swiftself:
    case lltok::kw_swiftasync:
    case lltok::kw_immarg:
      HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
      break;

So it looks a bit like llvm 13.0 functionality didn't make it into swift release/5.4?

Again... maybe I'm missing something?

I don't think we rebranched LLVM from main going from Swift 5.3 to Swift 5.4, so it is very likely the matching LLVM branch for Swift 5.4 is older than what main currently uses.

2 Likes

OK, yeah, it's difficult to work out exactly where your llvm was branched from. For me, I've found a hack that keeps me going... I use the binary bitcode rather than the text LLVM IR and it seems to work. I guess the information is degenerate enough. Hopefully will all work going forward. It might seem a bit odd me using a different llvm but I want the latest bugfixes for the AVR platform... which are an evolving target. I'll probably even use more recent llvm. You know me... I never make it easy for myself... I'll probably try to chat to you at wwdc. Thanks again Joe.

The branching schema is described here, but basically there is a swift/release/X branch of apple/llvm-project that is aligned with the X release of Swift. That's true for X >= 5.3; for older versions it's generally swift/swift-X-branch.

Thanks. It seems you guys do the best you can to keep llvm up to date. I appreciate how difficult it must be!

Terms of Service

Privacy Policy

Cookie Policy