Instcombine Creating Illegal Code? (in LLVM 7)

Hi all,

I was playing around with LLVM 7 and I discovered something that seems to me to be a bug – or at least something that I don’t understand.

Take the following valid simple program and run -instcombine on it

declare i8* @malloc(i64)

define void @caller() {
entry:
call void @callee()
ret void
}

define fastcc void @callee() {
entry:
%malloccall = call i8* @malloc(i64 9)
store i8 0, i8* %malloccall
ret void
}

It get’s transformed into the following invalid code after the optimization (now having an illegal store):

; ModuleID = ‘blarg.ll’
source_filename = “blarg.ll”

declare i8* @malloc(i64)

define void @caller() {
entry:
store i1 true, i1* undef, align 1
ret void
}

define fastcc void @callee() {
entry:
ret void
}

Anyone seen this before and/or could shed some light on this behavior.

I think the issue here is that callee is declared with the fastcc calling convention, but the call in caller doesn’t use fastcc. So InstCombine deleted the call and is emitting the store i1 true, i1* undef, align 1 to indicate to a different pass that this code is unreachable.

I see, that makes sense.

Would it be worthwhile checking that caller/callee’s match as part of the verifier or is there a reason that it simply emits undefined behavior?

In general, the callee of a “call” instruction is an arbitrary pointer, so the verifier can’t tell if the calling convention matches. And it would be very hard to write optimization passes if a call instruction could become invalid due to constant propagation.

There is a “lint” pass (lib/Analysis/Lint.cpp) which can detect suspicious constructs like this.

-Eli