To put signed pointers into global initializers (e.g. vtables) and other
desirable features there needs to be a Constant that represents “sign this
pointer in such and such way”. I propose adding a new child of Constant,
ConstantPtrAuth to represent this:
@var = global i32* ptrauth(i32* @something, ; Pointer to be signed
i32 0, ; Key to use for the signature
i32* @var, ; Address
discriminator, null if none
i16 1234) ; Discriminator
Anyone who has looked at the Xcode compiler output for arm64e will recognise
this as a pretty close analogue of the pseudo-Global that it emits
currently.
That was always intended to be a placeholder while the code was internal so that
we didn’t introduce bitcode incompatibility with OSS. Now that arm64e is being
upstreamed, it’s a good time to fix what was always really a ConstantExpr
pretending to be a global.
The fields specified were chosen to broadly match the features and relocations
available in arm64e MachO files: a 16-bit discriminator, possibly address
discriminated too.
I’ve posted the initial patch on Phabricator at
https://reviews.llvm.org/D92834. I’ve anticipated some
questions and done my best to respond below. What else occurs to people?
Could we make the discriminator a 64-bit field? For non-address-discriminated pointers it is possible to materialize the discriminator in a single instruction with almost 19 bits of entropy by making use of bit 30 (i.e. the selection between MOVN and MOVZ) and the HW bits. And I suppose that multi-instruction materialization of the discriminator is also possible (although it may not be practical to fit all of the bits into common object formats).
Shouldn’t this be a ConstantExpr?
There is one key interface for ConstantExpr we cannot currently support:
getAsInstruction. When an address discriminator is present, the ptrauth constant
represents an @llvm.ptrauth.blend followed by an @llvm.ptrauth.sign, two
separate instructions.
Because of that I’ve so far implemented it as its own separate entity in the
Constant hierarchy (kind of like blockaddress).
It might well be better to give up on intrinsic orthogonality and add one for
this case though. It would simplify the changes to lib/IR etc.
I mildly prefer keeping it as a Constant and not a ConstantExpr if we don’t realistically expect this to be converted between constant and non-constant operands. That’s similar to what we did for DSOLocalEquivalent for example. But I think I’d be fine either way.
Shouldn’t the key be i2 or something?
Possibly. That has legality implications in CodeGen though and is really not a
commonly used part of LLVM (there’s currently no llvm_i2_ty in
Intrinsics.td). i32 generally signals “don’t care”.
It seems like it should be wider than i2 at least. There is also the GA key which I suppose it’s conceivable that someone may want to use. And making it an i32 would easily allow future expansion, e.g. if more keys are added in the future, without requiring a bitcode upgrade path.
Peter