Problem matching i24 loads when a byte is 16 bits

We have a special architecture where i24 is a legal data type, and where 16 bits – not 8 bits – is considered a byte. Thus, the smallest addressable unit is 16 bits, which in combination with i24 causes problems during matching in global-isel. Let us assume that we have the following pattern:

(ld:{ *:[i24] } aN32_0_7:{ *:[i32] }:$addr)<<P:Predicate_unindexedload>><<P:Predicate_load>>

for which the matching table looks as follows:

GIM_CheckMemorySizeEqualToLLT, /MI/0, /MMO/0, /OpIdx/0,

GIM_CheckAtomicOrdering, /MI/0, /Order/(int64_t)AtomicOrdering::NotAtomic,

// MIs[0] addr

GIM_CheckPointerToAny, /MI/0, /Op/1, /SizeInBits/32,

GIM_CheckRegBankForClass, /MI/0, /Op/1, /RC/PHX::aN32_0_7RegClassID,

Because 24 bits is not a multiple of 16, we load 2 “bytes” aligned at 1. Hence, the table above is expected to match:

%1(s24) = G_LOAD %0 :: (load 2, align 1)

However, this is always rejected due to:

GIM_CheckMemorySizeEqualToLLT, /MI/0, /MMO/0, /OpIdx/0,

which checks whether the size of the result (24 bits) is equal to the size of the memory size (32 bits), which naturally is false.

A simple fix would be to simply remove the check, but then there is no check ensuring that the result of the source pattern matches the result of the destination pattern. Also, I get the feeling that there are underlying assumptions surrounding G_LOAD that you either load data of equal or greater size (which is then extended), but never of smaller size (as in this case).

What is the proper fix to this problem? As I see it, either we allow G_LOAD to load smaller sizes and patch the code impacted by this, or we patch TableGen to generate code that allows such matches.

We could also try to promote i24 to i32, but that would involve modifying a lot of the existing patterns we have (and i24 is anyhow a legal size in our architecture).

Best regards,

Gabriel Hjort Åkerlund

Hi Hjort,

I’m not sure whether your use-case is supported (yet) in TableGen with GlobalISel, so one workaround would be to implement the instruction selection for G_LOAD in your InstructionSelector.cpp::select method. You could take a look at the AArch64 or AMDGPU InstructionSelector.cpp if you need some more complex examples on how to do that.

AFAIU the GlobalISel TableGen backend isn’t as mighty yet so a lot of the more niche-cases need to be implemented manually at the moment.

I’m sure the GlobalISel maintainers can give you a more detailed answer and maybe even a solution for your use-case. For the meantime though I hope that this helps a bit.