This is an archive of the discontinued LLVM Phabricator instance.

[GlobalISel][InstructionSelect] Add support for selecting pointer types with TableGen
Needs ReviewPublic

Authored by tstellar on Dec 19 2018, 8:35 PM.

Details

Summary

There is no way to represent pointer types in TableGen, so have the instruction
selector convert pointer types to scalar types in GIM_SwitchType.

This will be tested by CodeGen/AMDGPU/GlobalIsel/smrd.ll once AMDGPU moves
load selection logic into TableGen.

Diff Detail

Event Timeline

tstellar created this revision.Dec 19 2018, 8:35 PM
arsenm added a subscriber: arsenm.Dec 19 2018, 9:26 PM

Aren't we going to need a way to represent this in tablegen eventually?

Aren't we going to need a way to represent this in tablegen eventually?

I think so, but I was hoping to find a solution that wouldn't require us to add a pattern for every pointer type.

Would it be difficult to add ptr types in tablegen's version of MVT, which the table gen backend converts as appropriate?

Would it be difficult to add ptr types in tablegen's version of MVT, which the table gen backend converts as appropriate?

I've looked at this, but it was more difficult than I thought, because the GlobalISelEmitter reuses the normal ISel pattern parsing and types are stored internally as MVT. One possibility might be to have the GlobalISelEmitter pre-process the patterns and replace pointer types with regular integers, but that's no too different from what this patch does.

You can actually use iPTR types in patterns already, but the GlobalISel backend converts it to a scalar integer when generating the ISel code.

You can actually use iPTR types in patterns already, but the GlobalISel backend converts it to a scalar integer when generating the ISel code.

Hmm, I'm not keen on munging the types together. I'd prefer to generate appropriate checks.

Just to give some background on iPTR:
DAGISel patterns are a bit inconsistent on their usage of iPTR. iPTR is just a scalar integer with a dynamically assigned size and as a result the patterns have scalar integers in patterns that should have pointers and pointers in patterns that should have scalar integers. This is mentioned in the iPTR definition (llvm/CodeGen/MachineValueType.h):

// An int value the size of the pointer of the current
// target to any address space. This must only be used internal to
// tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.

and TargetLoweringBase::getPointerTy():

MVT TargetLoweringBase::getPointerTy(const DataLayout &DL, uint32_t AS = 0) const {
  return MVT::getIntegerVT(DL.getPointerSizeInBits(AS));
}

It doesn't matter much for DAGISel as pointers aren't really a concept it deals with but GlobalISel considers pointers and scalars to be different things and as a result iPTR has some context specific behaviour. For ptypeN operands on instructions (e.g. the pointer operand of a G_LOAD) it's a pointer and GlobalISelEmitter emits a different predicate (OperandMatcher::addTypeCheckPredicate()), while all other contexts convert it to a scalar integer like DAGISel did (but only if there's only one choice after applying type constraints, if there's more it will reject the pattern). If you trace it back, it's CodeGenInstruction::isOperandAPointer() that triggers that special behaviour which is looking for TypedOperand.IsPointer in the InOperandList for the instruction.

What opcodes do you need to cover? If they're generic opcodes, does changing typeN to ptypeN have the desired effect? If they're more general things like G_ADD, then this wasn't an issue for AArch64 and our out-of-tree targets. We could potentially add predicates for pointer-sized scalars so that we emit the right checks.

You can actually use iPTR types in patterns already, but the GlobalISel backend converts it to a scalar integer when generating the ISel code.

Hmm, I'm not keen on munging the types together. I'd prefer to generate appropriate checks.

Just to give some background on iPTR:
DAGISel patterns are a bit inconsistent on their usage of iPTR. iPTR is just a scalar integer with a dynamically assigned size and as a result the patterns have scalar integers in patterns that should have pointers and pointers in patterns that should have scalar integers. This is mentioned in the iPTR definition (llvm/CodeGen/MachineValueType.h):

// An int value the size of the pointer of the current
// target to any address space. This must only be used internal to
// tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.

and TargetLoweringBase::getPointerTy():

MVT TargetLoweringBase::getPointerTy(const DataLayout &DL, uint32_t AS = 0) const {
  return MVT::getIntegerVT(DL.getPointerSizeInBits(AS));
}

It doesn't matter much for DAGISel as pointers aren't really a concept it deals with but GlobalISel considers pointers and scalars to be different things and as a result iPTR has some context specific behaviour. For ptypeN operands on instructions (e.g. the pointer operand of a G_LOAD) it's a pointer and GlobalISelEmitter emits a different predicate (OperandMatcher::addTypeCheckPredicate()), while all other contexts convert it to a scalar integer like DAGISel did (but only if there's only one choice after applying type constraints, if there's more it will reject the pattern). If you trace it back, it's CodeGenInstruction::isOperandAPointer() that triggers that special behaviour which is looking for TypedOperand.IsPointer in the InOperandList for the instruction.

What opcodes do you need to cover? If they're generic opcodes, does changing typeN to ptypeN have the desired effect? If they're more general things like G_ADD, then this wasn't an issue for AArch64 and our out-of-tree targets. We could potentially add predicates for pointer-sized scalars so that we emit the right checks.

I'm trying to add a pattern for G_LOAD when the output type is a pointer. I was able to figure out how to get the GlobalISelEmitter to do this and I just create a new review for it D57065.