<div dir="ltr"><div>The AVR backend's approach does require some workarounds for the legalizer as it stands.</div><div><br></div><div>On AVR, there are 31 8-bit general purpose registers. Only the last six, R26-R31, may be used for pointer operations, giving us a maximum of three pointer registers at any one time (commonly named X, Y, and Z). Although the AVR does have 16-bit registers, only the memory load/store instructions (LD, LDD, ST, STD, LPM, ...) are defined for 16-bit values. Every other 16-bit operation must be expanded into two 8-bit ones, including ADD, SUB, MUL, bitshifts, comparisons.. everything.</div><div><br></div><div>The legalizer is where this expansion should happen. The legalizer bases it's lowering logic on the size of the <b>largest legal integer type</b>. The legalizer defines the size of this as the size of the largest CPU register (I cannot find the source of this. The implicit assumption is that if a value is small enough to be stored in a CPU register, then the operation must be legal and thus no further expansion (i16->2x i8) happens. The legalizer does not know that i16 addition, subtraction, bitshifting, is illegal and emits an ISel node that the silicon can never fulfill. The legalizer, in each of the case statements for the different node types it handles, decides whether an <i>operation</i> is legal or should be expanded, but approximates this by simply checking if the underlying <i>type</i> is legal. The impedance mismatch occurs because even though a value is small enough to be stored in hardware ("is a legal integer type"), it does not necessarily mean that the hardware for executing that operation exists.</div><div><br></div><div>This means that on AVR, the legalizer never expands out to 8-bit nodes, always leaving technically illegal 16-bit DAGs for instruction selection and TableGen pattern matching. To work around this, on every single of the dozens of hardware instructions that can't be expanded further, we've added dozens of 16-bit pseudoinstructions along with handcrafted MachineInst expansion logic, performing the expansion in the <a href="https://github.com/llvm/llvm-project/blob/master/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp">AVRExpandPseudoInsts pass</a>. It's quite a maintenance burden, along with a lot of mostly-redundant code, that should be able to be replicated higher up at the legalizer level, where expansion logic is handed target-independently, avoiding a lot of the finicky details at the MachineInst level. The better solution would be to generalize the legalizer so that it understands the distinction between legal types and legal operations.<br></div><div><br></div><div>I believe this problem could affect you if you added the 64-bit register pair to the lists in RISCVRegisterInfo.td, as then 64-bit would be the largest legal integer type, causing expansion to halt and stop before lowering to i32 or smaller. It's been a long time since I've looked into the legalizer regarding this though, and I imagine AVR is a little more constrained than RISC-V, so perhaps YMMV.</div><div><br></div><div>I just had another read of your original message and this sticks out:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>Example for node "i64 = TargetGlobalAddress<[3 x i64] addrspace(1)* 
@foo> 0", it does not automatically expand the i64 result into two 
i32. We tried to convert i64 into v2i32 so that it can pass the 
legalizer but that does not seem to work well. Is there any simpler way 
to handle this? <br></div></blockquote><div><br></div><div>Sounds pretty similar. <br></div><div><br></div><div>I've described the issue a couple times before:</div><div><ul><li><a href="http://llvm.1065342.n5.nabble.com/llvm-dev-Status-of-the-AVR-backend-2019-LLVM-7-0-td125084.html#backend-implementation-maintenance-pain-points">http://llvm.1065342.n5.nabble.com/llvm-dev-Status-of-the-AVR-backend-2019-LLVM-7-0-td125084.html#backend-implementation-maintenance-pain-points</a></li><li><a href="https://github.com/avr-llvm/llvm/issues/163#issuecomment-143044993">https://github.com/avr-llvm/llvm/issues/163#issuecomment-143044993</a></li></ul></div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jun 11, 2019 at 8:08 PM Reshabh Sharma <<a href="mailto:reshabhsh@gmail.com">reshabhsh@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Reshabh, and congratulations on being selected for GSoC. I haven't<br>looked at supporting larger than native-width pointers on a target<br>before. I'd thought that AVR might be relevant (given it uses 16-bit<br>pointers but has 8-bit GPRs). See the description here<br><<a href="http://lists.llvm.org/pipermail/llvm-dev/2019-January/129089.html" rel="noreferrer" target="_blank">http://lists.llvm.org/pipermail/llvm-dev/2019-January/129089.html</a>>.<br></blockquote><div><br></div><div>Many thanks Alex, the AVR backend looks like a very promising reference. I'm planning to follow their approach. </div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jun 10, 2019 at 9:33 PM Alex Bradbury <<a href="mailto:asb@lowrisc.org" target="_blank">asb@lowrisc.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Wed, 5 Jun 2019 at 08:41, Reshabh Sharma via llvm-dev<br>
<<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
><br>
> Hello everyone,<br>
><br>
> We are working on extending RISC-V LLVM backend which will help us to achieve the goal of improving programmability in the second generation design of our open source RISC-V manycore processor (<a href="http://bjump.org/manycore" rel="noreferrer" target="_blank">bjump.org/manycore</a>).<br>
><br>
> We started with supporting 64 bit pointers in RISCV 32 bit backend using address spaces and register pairs. We aim to support 64 bit pointers in address space 1 using a pair of i32 registers. The 64 bit address will be stored in two i32 registers and we will add custom load/store instructions to concat the data from the two registers for getting the 64 bit address at the hardware level.<br>
><br>
> We started with updating the data layout string to "e-m:e-p:32:32-p1:64:64-i64:64-n32-S128" and we are stuck in the legalization phase.<br>
><br>
> Example for node "i64 = TargetGlobalAddress<[3 x i64] addrspace(1)* @foo> 0", it does not automatically expand the i64 result into two i32. We tried to convert i64 into v2i32 so that it can pass the legalizer but that does not seem to work well. Is there any simpler way to handle this?<br>
><br>
> We would be happy to hear your views and suggestions on this :)<br>
<br>
Hi Reshabh, and congratulations on being selected for GSoC. I haven't<br>
looked at supporting larger than native-width pointers on a target<br>
before. I'd thought that AVR might be relevant (given it uses 16-bit<br>
pointers but has 8-bit GPRs). See the description here<br>
<<a href="http://lists.llvm.org/pipermail/llvm-dev/2019-January/129089.html" rel="noreferrer" target="_blank">http://lists.llvm.org/pipermail/llvm-dev/2019-January/129089.html</a>>.<br>
CCing Dylan McKay in case he has any thoughts.<br>
<br>
Best,<br>
<br>
Alex<br>
</blockquote></div>
</blockquote></div>