Narrowing pointers to storage width from GPR width

I have a platform that I am targeting that has 64-bit general purpose
registers but uses 32-bit pointers (ie, sizeof(void*) == 4) but
unfortunately it also requires that the top 32-bits of the pointer value
be clear. This sometimes becomes a problem with certain pointer
calculations such as using a 32-bit negative value for indexing into an
array can cause the upper bits to be set, generating access violations
when used.

My first thought for fixing this issue was to modify GetElementPtr and
IntToPtr to perform pointer math on register width values and truncating
them down to the required size as specified in the platform's target
data string but all of these added operations disappear at optimization
time.

The current hack that I have in place is to force a clear of the upper
32-bits before every load and store which works from a correctness point
of view but does horrible things to code size. I was thinking also of
modifying the front end to use i32's as the storage type for all
pointers and converting to/from the appropriate pointer type as
necessary but I am hesitant because I'm not sure of the potential impact
it may have on code generation/optimization.

Does anyone have tips on how to take care of this properly?

-Max

The current hack that I have in place is to force a clear of the upper
32-bits before every load and store which works from a correctness point
of view but does horrible things to code size.

Hmm... you might want to try custom-lowering loads and stores in
CodeGen to a target-specific node that takes 64-bit zero-extended
value for the address. It might not get you code that's quite ideal,
but the combine pass that runs after Legalize should improve the code
significantly.

You could also try hacking SelectionDAGLowering::visitLoad and
SelectionDAGLowering::visitGetElementPtr and friends so that pointers
are 64 bits in CodeGen even though they're 32 bits in the IR; it's
probably the best place to handle it in terms of code quality because
that's where GEP (which has undefined overflow) transitions to normal
arithmetic. The downside is that it's kind of messy, and I'm not sure
if the inconsistency will have any other side-effects.

I was thinking also of
modifying the front end to use i32's as the storage type for all
pointers and converting to/from the appropriate pointer type as
necessary but I am hesitant because I'm not sure of the potential impact
it may have on code generation/optimization.

I don't think I'd suggest doing that... it would generate correct
code, but it would really mess up the IR-level optimizations.

-Eli