I’d like to share a couple of improvements to the (textual) IR parser I have made recently, as they may be useful to other people as well.
Intrinsics no longer require declarations
To use an intrinsic like call i64 @llvm.ctpop.i64(i64 %value)
it was previously necessary to add a declaration like declare i64 @llvm.ctpop.i64(i64)
as well.
This is no longer necessary, and the IR parser will automatically add the declaration. This makes it a bit easier to write IR tests and alive2 proofs.
Unnamed values no longer have to be consecutive
It’s now allowed to write something like this:
define i32 @test(i32 %0, i32 %1) {
%3 = add i32 %0, 1
%5 = add i32 %3, 1
ret i32 %5
}
Note that the value %4
has been skipped. This means you can now easily delete unnamed instructions in the IR, without having to renumber all the following instructions by hand. (This is also supported for unnamed globals.)
Parsing of incomplete IR
opt
supports a new -allow-incomplete-ir
option, which will drop references to undefined metadata and try to insert missing global declarations.
For example
define i32 @test() {
%ptr = call ptr @foo()
%v = load i32, ptr %ptr, !tbaa !2
ret i32 %v
}
will be accepted and converted into
define i32 @test() {
%ptr = call ptr @foo()
%v = load i32, ptr %ptr, align 4
ret i32 %v
}
declare ptr @foo()
if you pass -allow-incomplete-ir
.
This makes it easier to work with the output of -print-after-all
and similar, which contains dumps of individual functions only, without references declarations. Of course, this is all done on a best-effort basis only.