Proposal to add Bitcode version field to bitcode file wrapper

Hi,

We would like to add a version number to the bitcode wrapper. This feature would allow easier identification of what compiler produced the bitcode so that known incompatibilities with LTO compilation could be detected. Roughly speaking, this version number would consist of the major, minor and optionally the patch version of the compiler used to produce the bitcode. The version information would be encoded in 4 bytes, with the first byte representing the major version number, the second byte the minor version number, and the third and fourth bytes optionally encoding the patch version or other information. As to where to place this information, we are considering two different possibilities for updating the bitcode wrapper specification.

The first is to simply add a single 32bit wide field at the end of the existing bitcode wrapper format field. This would result in the new structure looking like this:

[Magic_{32}, Version_{32}, Offset_{32}, Size_{32}, CPUType_{32}, BitcodeVersion_{32}]

All of the existing fields would keep their current meanings, and the new field BitcodeVersion is simply appended with the format described in the first paragraph.

A second idea was to use the existing Version field in the bitcode wrapper format to store the bitcode version information. According to the documentation (http://llvm.org/docs/BitCodeFormat.html#bitcode-wrapper-format) this field is currently always set to 0. This would allow us to make use of what is (presumably) an unused field.

As this is a feature that we feel would be beneficial to the community, we wanted to get feedback on the design for our upcoming patches. Any thoughts or opinions on this would be greatly appreciated.

Thanks!

Douglas Yung

Bitcode backward compatibility, at least for the current major version, is supposed to make this unnecessary. Can you provide more information about what “known incompatibilities” you’re seeing?

Sorry if I was unclear. There are currently no “known incompatibilities” that I am aware of, although I fully admit to not being an expert on the topic. The idea is that we add versioning information to the bitcode so that if an issue were discovered, it could be easily detected and dealt with.

Douglas Yung

Sorry if I was unclear. There are currently no “known incompatibilities” that I am aware of, although I fully admit to not being an expert on the topic. The idea is that we add versioning information to the bitcode so that if an issue were discovered, it could be easily detected and dealt with.

Douglas Yung

Sorry if I was unclear. There are currently no “known incompatibilities”
that I am aware of, although I fully admit to not being an expert on the
topic. The idea is that we add versioning information to the bitcode so
that if an issue were discovered, it could be easily detected and dealt
with.

It sounds like time would be better invested in improving the testing of
our bitcode compatibility promise.

-- Sean Silva

As I understand it, the bitcode compatibility promise doesn’t extend as far as debug info metadata (happy to be wrong here!). I think we have a usecase where need to guarantee that debug information from any two arbitrary bitcode files going into an LTO link will result in the expected/correct debug information going into the resulting ELF file; unless we can be sure that this will always work between bitcode files generated by different versions we’d need some way of flagging up an incompatibility and providing useful information on the reason to the user.

–Greg Bedwell
SN Systems - Sony Computer Entertainment Group

In general the story is these days that we won’t /crash/ on old debug info metadata formats, we’ll just drop the old debug info metadata - so you won’t get debug info, but you can still link/use your old IR libraries with new IR/compiler.

How is this use case different from the LTO-supported toolchains shipped by other vendors such as Apple? Do they have this theoretical problem too?

If the issue is solely constrained to debug info metadata, then why not use metadata to describe the format/version of the debug info?

Alex

How is this use case different from the LTO-supported toolchains shipped
by other vendors such as Apple? Do they have this theoretical problem too?

If the issue is solely constrained to debug info metadata, then why not
use metadata to describe the format/version of the debug info?

FWIW (I haven't followed the rest of this thread) - that's what we/Apple
have done. There's a module flag metadata that specifies the debug info
metadata schema version, then the verifier (or some other pass, I forget
how it's phrased) can check if the version matches the current LLVM's debug
info metadata version, and if it doesn't match, it strips out all the debug
info metadata.

Bitcode backward compatibility, at least for the current major version, is supposed to make this unnecessary.

I think the “at least for the current major version” part is one thing that concerns us. LLVM 4.0 will promise to read LLVM 3.4 bitcode, but LLVM 4.1 will not, according to my understanding of the current promise. Smoothly identifying that point and being able to provide an intelligent diagnostic seems like goodness. Hard to distinguish “old” bitcode from “broken” bitcode without recording version info of some kind, and the sooner we start recording the version number the more completely we’re able to diagnose the situation properly when the time comes.

–paulr

> Bitcode backward compatibility, at least for the current major version, is
supposed to make this unnecessary.

It didn't use to work that way, and I'm not sure we want it at all.

I think the "at least for the current major version" part is one thing that
concerns us. LLVM 4.0 will promise to read LLVM 3.4 bitcode, but LLVM 4.1
will not, according to my understanding of the current promise.

I've never heard such promises, but even if you're right (that there
is a promise), we cannot enforce it, since we have no tests to make
sure we do.

Right now, the only guarantee I know exists (and it's a new one, from
3.4 onwards) is that minor releases won't break ABI or API
compatibility, which includes IR logic. So 3.4.2 is guaranteed to
parse 3.4 IR but not 3.3 or 3.5.x.

Smoothly identifying that point and being able to provide an intelligent diagnostic
seems like goodness. Hard to distinguish "old" bitcode from "broken" bitcode
without recording version info of some kind, and the sooner we start
recording the version number the more completely we're able to diagnose the
situation properly when the time comes.

There are two problems with this:

1. Due to the nature of our development strategy, IR compatibility can
be broken between two releases, which means any two commits within the
same revision can fail to parse (or parse incorrectly) IR from each
other. Do we care about between-release compatibility?

Some people get specific commits, rather than releases, for timing
reasons, for their products, and in doing so, you could get a commit
that is actually IR incompatible with the next major release. If you
care about compatibility, you should increment the IR version every
time something radical changes, which can be multiple times between
the same two releases, or spawn across multiple releases.

IR versioning should be completely independent of major / minor
release cycles. The hard part is to truly detect, and validate, IR
compatibility changes.

2. IR incompatibility is different from metadata incompatibility. If
the IR is incompatible (say we drop or add a new type, or we change
how exceptions are propagated), the new parser will not understand the
old and vice-versa. But if metadata changes, it can still be parsed,
and as David said, if we can't understand it, we just drop it.

If you want your parser to break the least, you'll have to have at
least two version: IR and Debug. Other metadata versioning can be done
individually (since they change at different rates). You may want to
warn on stale metadata status (since it's not an error), but you
should stop on stale IR.

Finally, both problems end up in the same place: how do you validate
this? We'd have to add a new class of tests, and for every new change
in IR/metadata, we'd increase the version number and create a test
that checks old parser+new syntax and old syntax+new parser and makes
sure they fail/warn.

You'd also need to have a table of major releases vs. IR versions, so
that in the error/warning message you tell: please use LLVM M.N
instead.

cheers,
--renato

From: Renato Golin [mailto:renato.golin@linaro.org]
Sent: Monday, September 29, 2014 1:27 AM
To: Robinson, Paul
Cc: Greg Bedwell; Sean Silva; Yung, Douglas; cfe-dev@cs.uiuc.edu;
llvmdev@cs.uiuc.edu
Subject: Re: [LLVMdev] [cfe-dev] Proposal to add Bitcode version field to
bitcode file wrapper

> > Bitcode backward compatibility, at least for the current major
version, is
> supposed to make this unnecessary.

It didn't use to work that way, and I'm not sure we want it at all.

> I think the "at least for the current major version" part is one thing
that
> concerns us. LLVM 4.0 will promise to read LLVM 3.4 bitcode, but LLVM
4.1
> will not, according to my understanding of the current promise.

I've never heard such promises, but even if you're right (that there
is a promise), we cannot enforce it, since we have no tests to make
sure we do.

That promise is what I understood from a discussion within the past month,
e.g. http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-September/076815.html
If I misunderstood, clarification on the clarification would be helpful. :wink:

And recently tests have appeared that I thought were intended to validate
this sort of thing, e.g. r218297.
--paulr

I see, I missed that one. My concerns seem to be similar to Bob's,
though in the past, when we discussed the same topic, there was one
major hurdle to implement that: we'd have to know what features we
removed / stopped supporting and warn on what version brackets
supported that feature. This can only grow as the compiler ages.

Enforcing backwards compatibility with only the major version created
another hurdle: we'd only be able to deprecate bad/temporary features
every few years, creating another bag of legacy. Warnings can be made,
and deprecation of whole sets of features will happen at major
version, which will stress the release validation and increase the
influx of bugs on all major releases.

Whenever I think of any of that, I remember Chris' words: "LLVM IR is
a compiler IR. Nothing more, nothing less". I don't think we should
try to standardise that too much.

My tuppence.

--renato

It is a compiler IR but with LTO we need backward compatibility for IR in object files. This is not a new requirement. We have required auto-upgrade support for old bitcode files for as long as I have worked on LLVM for exactly this reason. The testing to enforce that has been pretty minimal, but we’re now making an effort to be more systematic about it.

By all means, I think we're on the same page as far as testing and the
burden of keeping the compatibility, I just didn't remember it being
such a big requirement.

Maybe I'm making a bigger issue than it needs to be... which is
actually quite likely. :slight_smile:

cheers,
--renato

Except, backward compatibility breaks are allowed at major versions.
See, for example, the type system rewrite.

-eric

Yes, that was stated in the original email. I think we all agree that
this is an important part of the policy.

cheers,
--renato

Hi All,

We have internal request to allow ‘_’ in addition to ‘.’ as version tuple separators.
So, in addition to 'major[.minor[.subminor]]’, proposal is to allow ‘major[_minor[_subminor]]’
as well. Is there a reason we shouldn’t do this?

  • Thanks, Fariborz

Hi All,

I would like to move on with this if there is no objections.

  • Fariborz