This is an archive of the discontinued LLVM Phabricator instance.

[ARM] Miscompilation on arrays promoted to constant pools
Needs ReviewPublic

Authored by iid_iunknown on Apr 26 2017, 3:49 PM.

Details

Summary

This addresses the ARM miscompilation issue described in PR32780.

Problem
When a constant array is promoted to a constant pool, the constant islands pass can create several constpool entries with inlined copies of that array. If the array elements are accessed via multiple pointers, it might happen that the pointers would point to different array copies, thereby making all the operations on these pointers (such as comparison, subtraction, etc) invalid.

Solution
This patch restricts promotion to arrays having one use only, which guarantees that address of a promoted array can be taken only once.
As an extra small benefit, the patch merges similar allUsersAreInFunction and allUsersAreInFunctions functions into a single function to reduce code duplication and, possibly, make it a bit faster.

Diff Detail

Repository
rL LLVM

Event Timeline

iid_iunknown created this revision.Apr 26 2017, 3:49 PM
efriedma added inline comments.
lib/Target/ARM/ARMISelLowering.cpp
2972

IsCDAInit seems a bit dubious; for example, you could have a struct which contains an array, or use a scalar as a one-element array, or type-pun a scalar into an array. Or you could even end up comparing the address of a constant against itself.

One use in the IR could lead to more than one use in the actual generated code; for example, consider the case where the only use is a GEP, which feeds into multiple instructions. I think we can solve this, though: since ISel doesn't work across basic blocks, all the uses of the address of the global will be replaced with the return value of promoteToConstantPool. We just need to prevent later passes from trying to rematerialize it, so we have only one instruction which references the constant pool entry by the time we get to the constant islands pass.

yinma added a subscriber: yinma.Apr 27 2017, 11:12 AM

Hi, I am facing the same issue. In my case, I disable the rematerialization of all instructions that referring contant pool. I think only t2LEApcrel is rematerializable right now. Because
the safety assumption of ContantIslandPass is that the reference to an constant pool entry should be one use. ARM common subexpression elimination will make single reference to one constant pool, the
rest reference should be copy. I believe the only re-introduction of referencing instruction is the rematerialization in register allocation pass. If we disable rematerialization. the assumption of one use should hold
until constant island pass in general. So in constant island, we can simply check if the CPE->RefCount is not greater than 1, if is greater than 1, no cloning. How do you think?

yinma added a comment.May 2 2017, 3:40 PM

I tried this patch, I think it is a little bit too restrictive. If something like
define i8* @foo() {
entry:

store i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), i8** @b, align 4
ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0)

}

this is a write->read back to back case. I don't think it will cause any issue when it is promoted to constant pool.

As this patch has not been accepted and 4.0.1 is apporaching, and taking into account the severity level of the problem, another patch is suggested to temporarily disable globals promotion:

https://reviews.llvm.org/D33446