Purpose of MSP430Wrapper

Hello,

I'm considering creating an LLVM backend for a 16 bit processor and modelling it around the (experimental) MSP430 back end.

When reviewing MSP430InstrInfo.td I see

def MSP430Wrapper : SDNode<"MSP430ISD::Wrapper", SDT_MSP430Wrapper>;

and can see in MSP430ISelLowering.cpp that

ISD::GlobalAddress:
ISD::BlockAddress:
ISD::ExternalSymbol

all get lowered to MSP430ISD::Wrapper(address space) plus the wrapped address node.

What has me mystified is that in some of the patterns in MSP430InstrInfo.td take the form

def : Pat<(i16 (MSP430Wrapper tglobaladdr:$dst)), (MOV16ri tglobaladdr:$dst)>;

and others ...

def : Pat<(MSP430call (i16 tglobaladdr:$dst)), (CALLi tglobaladdr:$dst)>;

In other words, some patterns rely on MSP430Wrapper being part of the pattern then extract the wrapped info anyway, and some others just directly match tglobaladdr and friends.

I have noticed that many other backends use the same idiom but so far I can't see what it offers to the matching process.

Can someone please explain what I'm not seeing ?

Thanks, Paul.

I'm not sure about the MSP430 backend but I can talk about the XCore backend which uses a similar idiom. The XCore has 3 ways of accessing a global: using PC relative addressing, via an immediate offset from the thread's DP (data pointer) register or via an immediate offset from the thread's CP (constant pool) register. When lowering a global address to a target global address XCoreISelLowering wraps the tglobaladdress node with one of three wrappers (PCRelativeWrapper, DPRelativeWrapper, CPRelativeWrapper) based on properties of the global (is it a function, is it constant, etc) .

The wrapper is used in patterns in XCoreInstrInfo.td to ensure the right instruction is selected to access the global (for example to get the address of the global into a register the backend uses the LDAP instruction if the PCRelativeWrapper is present, LDAWCP if the CPRelativeWrapper is present and LDAWDP if the DPRelativeWrapper is present).

Thanks Richard,

You're correct, they are similar. In the XCoreInstrInfo.td patterns what I'm struggling with is why this ....

def BL_lu10 : _FLU10<
                   (outs),
                   (ins calltarget:$target, variable_ops),
                   "bl $target",
                   [(XCoreBranchLink immU20:$target)]>;

def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BL_lu10 tglobaladdr:$addr)>;
def : Pat<(XCoreBranchLink texternalsym:$addr), (BL_lu10 texternalsym:$addr)>;

is necessary. Are the Pat<> s just 'casting' tglobaladdr:$addr and texternalsym:$addr to an immU20 to force a match ?

I'm guessing similar Pat<> 's aren't required for the BL_u10/immU10 cases because they match without any assistance ?

Is the XCoreBranchLink enough of a match hint that an address wrapper isn't required to clarify the pattern match for these call instructions ?

Cheers, Paul

Thanks Richard,

You're correct, they are similar. In the XCoreInstrInfo.td patterns what I'm struggling with is why this ....

def BL_lu10 : _FLU10<
                  (outs),
                  (ins calltarget:$target, variable_ops),
                  "bl $target",
                  [(XCoreBranchLink immU20:$target)]>;

def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BL_lu10 tglobaladdr:$addr)>;
def : Pat<(XCoreBranchLink texternalsym:$addr), (BL_lu10 texternalsym:$addr)>;

is necessary. Are the Pat<> s just 'casting' tglobaladdr:$addr and texternalsym:$addr to an immU20 to force a match ?

There is no casting going on, there are just 3 separate patterns all which select to the BL_lu10 instruction. You could rewrite this as:

def BL_lu10 : _FLU10<
                   (outs),
                   (ins calltarget:$target, variable_ops),
                   "bl $target",
                   []>;

def : Pat<(XCoreBranchLink immU20:$addr), (BL_lu10 immU20:$addr)>;
def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BL_lu10 tglobaladdr:$addr)>;
def : Pat<(XCoreBranchLink texternalsym:$addr), (BL_lu10 texternalsym:$addr)>;

The advantage of specifying the pattern inline is:

* Less typing.
* Properties of the instruction are inferred from the pattern it matches (e.g does the instruction load or store, does it have other side effects). If there is no pattern you would need to specify these manually (let mayLoad=1 in ...)

I'm guessing similar Pat<> 's aren't required for the BL_u10/immU10 cases because they match without any assistance ?

No, the BL_u10 instructions are not matched. At least for the XCore target, we always conservatively use the branch instruction with the largest offset. instructions can be relaxed (replaced by smaller versions) later.

Is the XCoreBranchLink enough of a match hint that an address wrapper isn't required to clarify the pattern match for these call instructions?

There's no wrapper in these patterns because the lowering code which creates the XCoreBranchLink SDNode (XCoreTargetLowering::LowerCCCCallTo()) doesn't add a wrapper around the callee. There is no need to add a wrapper because in the case of a call there is no ambiguity - a call of a global always use pc relative addressing on the XCore. The important thing here is that the pattern must match the nodes the introduced during the lowering.

Thanks Richard,

You're correct, they are similar. In the XCoreInstrInfo.td patterns what I'm struggling with is why this ....

def BL_lu10 : _FLU10<
                  (outs),
                  (ins calltarget:$target, variable_ops),
                  "bl $target",
                  [(XCoreBranchLink immU20:$target)]>;

def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BL_lu10 tglobaladdr:$addr)>;
def : Pat<(XCoreBranchLink texternalsym:$addr), (BL_lu10 texternalsym:$addr)>;

is necessary. Are the Pat<> s just 'casting' tglobaladdr:$addr and texternalsym:$addr to an immU20 to force a match ?

There is no casting going on, there are just 3 separate patterns all which select to the BL_lu10 instruction. You could rewrite this as:

def BL_lu10 : _FLU10<
                  (outs),
                  (ins calltarget:$target, variable_ops),
                  "bl $target",
                  []>;

def : Pat<(XCoreBranchLink immU20:$addr), (BL_lu10 immU20:$addr)>;
def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BL_lu10 tglobaladdr:$addr)>;
def : Pat<(XCoreBranchLink texternalsym:$addr), (BL_lu10 texternalsym:$addr)>;

The advantage of specifying the pattern inline is:

* Less typing.
* Properties of the instruction are inferred from the pattern it matches (e.g does the instruction load or store, does it have other side effects). If there is no pattern you would need to specify these manually (let mayLoad=1 in ...)

I think I see my mistake. I was thinking that inputs to a def like def BL_lu10 : _FLU10<
                   (outs),
                   (ins calltarget:$target, variable_ops),
                   "bl $target",
                   [(XCoreBranchLink immU20:$target)]>;

had to match the pattern (in this case [(XCoreBranchLink immU20:$target)], but of course the pattern is used for matching, not expansion of (Pat<>) definitions.

I'm guessing similar Pat<> 's aren't required for the BL_u10/immU10 cases because they match without any assistance ?

No, the BL_u10 instructions are not matched. At least for the XCore target, we always conservatively use the branch instruction with the largest offset. instructions can be relaxed (replaced by smaller versions) later.

Is the XCoreBranchLink enough of a match hint that an address wrapper isn't required to clarify the pattern match for these call instructions?

There's no wrapper in these patterns because the lowering code which creates the XCoreBranchLink SDNode (XCoreTargetLowering::LowerCCCCallTo()) doesn't add a wrapper around the callee. There is no need to add a wrapper because in the case of a call there is no ambiguity - a call of a global always use pc relative addressing on the XCore. The important thing here is that the pattern must match the nodes the introduced during the lowering.

Second penny dropped, I see that the XCoreBranchLink SDNode is created by

Chain = DAG.getNode(XCoreISD::BL, dl, NodeTys, &Ops[0], Ops.size());

I'm finally starting to get a better feel for this. Thanks for your help.