[llvm-dev] Expanding a PseudoOp and accessing the DAG

Phil Tomson via llvm-dev llvm-dev at lists.llvm.org
Fri Jan 15 11:08:57 PST 2016


On Fri, Jan 15, 2016 at 10:49 AM, Phil Tomson <phil.a.tomson at gmail.com>
wrote:

>
>
> On Thu, Jan 14, 2016 at 6:05 AM, Krzysztof Parzyszek <
> kparzysz at codeaurora.org> wrote:
>
>> On 1/13/2016 4:47 PM, Phil Tomson wrote:
>>
>>>
>>> First off, I got this idea from the LLVM Cookbook chapter 8: Writing an
>>> LLVM Backend: Lowering to multiple instructions. (now I'm having my
>>> doubts as to whether this is the right approach)
>>>
>>
>> There is a pass "ExpandISelPseudos", which handles instructions with
>> custom inserters.  You can mark instructions as having custom inserters in
>> the .td files and then override the EmitInstrWithCustomInserter function to
>> deal with them.
>>
>>
>>
>> Let me explain at the assembly level what I'm trying to accomplish.
>>>
>>> We're trying to make position independent executables, so we intend to
>>> have a switch like -fPIE. In that case we've designated some registers
>>> to be pointers to various address spaces (and our processor is rather
>>> complicated so there are several address spaces).
>>>
>>> Right now,  given a global variable called 'answer' in C we end up with
>>> the following in the .s file:
>>>
>>>    movimm    r1, %rel(answer) # r1 <- offset to 'answer' symbol
>>>    load    r1, r1, 0                     # r1<-mem[r1+0]
>>>
>>> This isn't correct because it should be relative to the GRP register if
>>> the PIE mode is chosen, what I'd like to get is either:
>>>
>>>    movimm   r1, %rel(answer)
>>>    addI         r1, GRP              # r1 <- r1 + GRP
>>>    load         r1, r1, 0               # r1 <- mem[r1+0]
>>>
>>> Or even better:
>>>
>>>    movimm   r1, %rel(answer)
>>>    load         r1, r1, GRP      # r1 <- mem[r1+GRP]
>>>
>>> What I'm getting at the moment is just this part:
>>>
>>>    load        r1, r1, GRP
>>>
>>> So the movimm is missing. That's because I've added the Pseudo
>>> instruction RelAddr and GlobalAddress nodes get converted to RelAddr
>>> nodes in LowerGlobalAddress.... They used to get converted to the MVINI
>>> node type there prior to adding the RelAddr pseudo inst.
>>>
>>> It feels like more of this needs to be done in the LowerGlobalAddress
>>> function, but I have no idea how to do it there - you seem to only be
>>> able to get one instruction out of a lowering like that, not multiple
>>> instructions. It also seems like (as you point out) the expansion phase
>>> is too late to be doing it.
>>>
>>
>> Here's what I would do (based on what I understand about your target so
>> far):
>>
>> Define two additional ISD opcodes, specific to your target. One to denote
>> a "normal" address, the other to mean "address using GRP".  For example
>> (you can invent better names for them): XSTGISD::ADDR_NORMAL and
>> XSGTISD::ADDR_USE_GRP. Each of them will take a global address as an
>> operand and return an address, and their only function will be to serve as
>> a "tag" for the instruction selection algorithm to be able to apply
>> different selection patterns to them.
>>
>> In the .td file, define SDNodes corresponding to these opcodes, e.g.
>> "addr_normal" and "addr_use_grp".  Then, you can have these patterns for
>> loads:
>>
>> // Match a load from a non-relocatable address to a simple load
>> // instruction (with offset 0):
>> def: Pat<(load (addr_normal tglobaladdr:$addr)),
>>          (load tglobaladdr:$addr, 0)>;
>> // Match load from a relocatable address to a load with GRP:
>> def: Pat<(load (addr_use_grp tglobaladdr:$addr)),
>>          (load (movimm tglobaladdr:$addr), GRP)>;
>>
>
> I'm not entirely sure what to replace 'load' with in the patterns above.
>
> I notice that we have these defm's in our XSTGInstrInfo.td file:
>
> defm LOADI64 : LoadOp< 0b1001010, "load", OpInfo_I64, II_LOAD1 >;
> defm LOADF64 : LoadOp< 0b1001010, "load", OpInfo_F64, II_LOAD1 >;
> defm LOADI32 : LoadOp< 0b1001010, "load", OpInfo_I32, II_LOAD1 >;
> defm LOADF32 : LoadOp< 0b1001010, "load", OpInfo_F32, II_LOAD1 >;
> defm LOADI16 : LoadOp< 0b1001010, "load", OpInfo_I16, II_LOAD1 >;
> defm LOADI8  : LoadOp< 0b1001010, "load", OpInfo_I8,  II_LOAD1 >;
>
> I tried replacing 'load' with 'LOADI64' in the patter, like this:
>
> def: Pat<(LOADI64 (XSTGADDR_NORMAL tglobaladdr:$addr)),
>          (LOADI64 tglobaladdr:$addr, 0)>;
>
> But that resulted in:
>
> XSTGInstrPatterns.td:619:11: error: Variable not defined: 'LOADI64'
> def: Pat<(LOADI64 (XSTGADDR_NORMAL tglobaladdr:$addr)),
>
>
Ah, I see, the defm is a multi-class so I needed to change it to:

 def: Pat<(load (XSTGADDR_NORMAL tglobaladdr:$addr)),
         (LOADI64_RI tglobaladdr:$addr, 0)>;
// Match load from a relocatable address to a load with GRP:
def: Pat<(load (XSTGADDR_USE_GRP tglobaladdr:$addr)),
         (LOADI64_RI (MOVIMMZ_I64 tglobaladdr:$addr), GRP)>;

...at least that gets through TableGen.




>
>> The patterns above should use tglobaladdr, because you will still need
>> custom LowerGlobalAddress to generate them first, and it may need to attach
>> special "target flags" to these addresses.
>>
>> Finally, in LowerGlobalAddress, you can check the relocation model,
>> compilation options, etc. to see if you need to have relocatable addresses,
>> or not:
>>
>> SDValue XSTGISelLowering::LowerGlobalAddress(SDValue Addr, SelectionDAG
>> &DAG) {
>>   ...
>>   if (NeedGRP) {
>>     SpecialTargetFlags = ...;
>>     SDValue TAddr = DAG.getTargetGlobalAddress(..., SpecialTargetFlags);
>>     return DAG.getNode(XSTGISD::ADDR_USE_GRP, ..., TAddr);
>>   }
>>
>>   // Non-relocatable address:
>>   SDValue NAddr = DAG.getTargetGlobalAddress(...);
>>   return DAG.getNode(XSTGISD::ADDR_NORMAL, ..., NAddr);
>>
>> }
>>
>>
>> -Krzysztof
>>
>> --
>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted
>> by The Linux Foundation
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160115/950b7e74/attachment.html>


More information about the llvm-dev mailing list