Expanding a PseudoOp and accessing the DAG

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".

I'm guessing these would be Pseudo Instr nodes?

Initially I had this:

def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL",
SDT_XSTGADDR_NORMAL>;

def addr_normal : XSTGPseudo< (outs),
                                          (ins i64imm:$addr),
                                          "! ADDR_NORMAL $addr",
                                          [(XSTGADDR_NORMAL i64:$addr)]>;

But then TableGen gave me:
utils/TableGen/DAGISelMatcherGen.cpp:893: void
{anonymous}::MatcherGen::EmitResultInstructionAsOperand(const
llvm::TreePatternNode*, llvm::SmallVectorImpl<unsigned int>&): Assertion
`(!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && "Node has no
result"' failed.

This is apparently because (outs) is empty. So looks like I either need
SDNPOutGlue or SDNPHasChain based on the assertion message.

This seems to work:

def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL",
SDT_XSTGADDR_NORMAL,[SDNPOutGlue]>;

def addr_normal : XSTGPseudo< (outs),
                                          (ins i64imm:$addr),
                                          "! ADDR_NORMAL $addr",
                                          [(XSTGADDR_NORMAL i64:$addr)]>;

...but I'm not entirely sure if that's the right definition.

Resending to include the mailing list.

>
> I'm guessing these would be Pseudo Instr nodes?

No, they won't be instructions at all, just SDNodes.

> Initially I had this:
>
> def SDT_XSTGADDR_NORMAL : SDTypeProfile<0, 1, [SDTCisInt<0>]>;

The type should be "address in, address out", i.e. 1 result and 1 argument:
def SDT_XSTGADDR_NORMAL : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>;

> def XSTGADDR_NORMAL : SDNode<"XSTGISD::ADDR_NORMAL",
> SDT_XSTGADDR_NORMAL>;

This is pretty much it. The XSTGADDR_NORMAL is what "addr_normal" was meant to be. Now you can use XSTGADDR_NORMAL in patterns for loads and stores.

-Krzysztof