Hi,
After the recent patch to ConstantFolder concerning folding of gep of gep ([ConstantFold] Drop gep of gep fold entirely by nikic · Pull Request #95126 · llvm/llvm-project · GitHub) I’ve noticed an issue in our downstream compiler.
We have an analysis that among other things goes over users of global variables and checks them for validity for some particular transformation. The problem the aforementioned patch caused is some globals which were used in at least one ConstantExpr of ‘gep of gep’ type kept their original user in the user list, even though InstCombine folded those original expressions into something else.
I’d rather demonstrate this on a simple example:
%t = type {ptr, i64, i64, i64, i64, i64, [3 x { i64, i64, i64 }] }
@a = global %t { ptr null, i64 0, i64 0, i64 1073741952, i64 3, i64 0, [3 x { i64, i64, i64 }] zeroinitializer }
define void @foo() {
store i64 1, ptr getelementptr inbounds ({ i64, i64, i64 }, ptr getelementptr inbounds (%t, ptr @a, i32 0, i32 6, i32 0), i32 0, i32 1)
ret void
}
InstCombine transforms the store into
store i64 32, ptr getelementptr inbounds (i8, ptr @a, i64 56)
so the original ConstantExprs are effectively dead. But the resulting user list of @a contains both the original ones and the intermediate folding results, which are itself not dead because they are used in the enclosing ConstantExprs (which are dead):
U: ptr getelementptr inbounds (i8, ptr @a, i64 56), uses = 1
U: ptr getelementptr inbounds (i8, ptr @a, i64 48), uses = 1
UU: ptr getelementptr inbounds ({ i64, i64, i64 }, ptr getelementptr inbounds (i8, ptr @a, i64 48), i64 0, i32 1), uses = 0
U: ptr getelementptr inbounds (%t, ptr @a, i64 0, i32 6, i64 0), uses = 0
U: ptr getelementptr inbounds (%t, ptr @a, i32 0, i32 6, i32 0), uses = 1
UU: ptr getelementptr inbounds ({ i64, i64, i64 }, ptr getelementptr inbounds (%t, ptr @a, i32 0, i32 6, i32 0), i32 0, i32 1), uses = 0
One workaround I figured out is to use Constant::hasZeroLiveUses
in our analysis to check if the expression is dead, but that still does seem hacky. Is there any nicer existing way to clean up (or ignore) such users before analyzing the IR?
Per my understanding the problem is caused by the fact that constant folder performs the folding bottom-up, i.e. when the enclosing expression is folded and the original one declared dead the inner ones have already been processed and there’s no way to call removeDeadConstantUsers
for them. A separate cleanup utility looks like an overkill too.
Would appreciate any advice!