TableGen error message: top-level forms in instruction pattern should have void types

I’m trying to figure out what this error message means:

error: In RelAddr: Top-level forms in instruction pattern should have void types

The definitions it’s complaining about:

//===----------------------------------------------------------------------===//
// RELADDR
//===----------------------------------------------------------------------===//

def SDT_RELADDR : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>;
def XSTGRELADDR : SDNode<“XSTGISD::RELADDR”, SDT_RELADDR>;

let Uses= [GRP] in {
def RelAddr : XSTGPseudo< (outs),
(ins GPRC:$spoff, GPRC:$dst),
“! RELADDR $spoff, $dst”,
[(XSTGRELADDR GPRC:$spoff, GPRC: $dst)]>;
}

(specifically that ‘def RelAddr’ line)

If I change it to have an empty pattern match like this:
let Uses= [GRP] in {
def RelAddr : XSTGPseudo< (outs),
(ins GPRC:$spoff, GPRC:$dst),
“! RELADDR $spoff, $dst”,
[]>;
}

It will compile, but without the pattern it’s not a very useful def.

Any suggestions?

I have other XSGTGPseudo definitions in the .td file which are similar which do compile, like this:

def SDT_XSTGEhRet : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>;
def XSTGEhReturn : SDNode<“XSTGISD::EH_Return”, SDT_XSTGEhRet,
[SDNPHasChain, SDNPOptInGlue]>;
//
// EhReturn takes the place of regular return instruction
// but takes two arguments (R2, R3) which are used for storing
// the offset and return address respectively.
//
let Uses = [R2, R3], isTerminator = 1, isReturn = 1, isBarrier = 1 in {
def EhReturn : XSTGPseudo< (outs),
(ins GPRC:$spoff, GPRC:$dst),
“! EH_RETURN $spoff, $dst”,
[(XSTGEhReturn GPRC:$spoff, GPRC:$dst)]>;
}

Phil

Remove the "dst" operand from XSTGRELADDR and try something like
[(set GPRC:$dst, (XSTGRELADDR GPRC:$spoff))]

-Krzysztof

let Uses= [GRP] in {
   def RelAddr : XSTGPseudo< (outs),
                                       (ins GPRC:$spoff, GPRC:$dst),
                                       "! RELADDR $spoff, $dst",
                                       [(XSTGRELADDR GPRC:$spoff, GPRC:
$dst)]>;
}

Remove the "dst" operand from XSTGRELADDR and try something like
[(set GPRC:$dst, (XSTGRELADDR GPRC:$spoff))]

That's better, but now I get:

XSTGInstrInfo.td:902:3: error: In RelAddr: XSTGRELADDR node requires
exactly 2 operands!

Which makes some sense as XSTGRELADDR is defined as:
def SDT_RELADDR : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0,
1>]>;
def XSTGRELADDR : SDNode<"XSTGISD::RELADDR", SDT_RELADDR>;

Phil

-Krzysztof

The problem is that the pattern that you use in the instruction definition cannot have any value. That is, the top node has to consume all values produced by the nodes below it. The node XSTGRELADDR does have a value, and so it cannot be the top node.
If the intent is to have the second operand as the target register for that value, it shouldn't be an operand to the SDNode, and in the instruction definition it should be listed in the (outs) list. If the second operand is not an output operand, then the RelAddr instruction should have some additional operand in (outs) and use "set ..." in the pattern, or have some other consumer as the top node in the selection pattern.

-Krzysztof

Let me explain what I'm trying to achieve: In certain relocation modes we
need to have addresses for symbols be relative to a special pointer
register we call GRP. For example, let's say we want to access a global
variable called 'answer'. The relevant part of the .ll file looks like:

@answer = addrspace(4) global i32 42, align 4
@two = addrspace(3) global i32 2, align 4
@seven = addrspace(2) global i32 7, align 4
@xint = common global i32 0, align 4
@y = global [1 x i32*] [i32* @xint], align 8

; Function Attrs: nounwind uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %bint = alloca i32, align 4
  %cint = alloca i32, align 4
  %a = alloca i32**, align 8
  %b = alloca i32*, align 8
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %0 = load i32 addrspace(4)* @answer, align 4
  store i32 %0, i32* @xint, align 4
...

Currently this produces the following assembly code:
.Ltmp0:
    .cfi_def_cfa_offset 48
    store r510, r509, 0, 64
.Ltmp1:
    .cfi_offset 510, -48
    bitop1 r510, r509, 0, OR, 64
.Ltmp2:
    .cfi_def_cfa_register 510
    store r0, r510, 44, 32
    store r1, r510, 32, 64
    movimm r0, %hi(xint), 64
    movimmshf32 r0, r0, %lo(xint)
    movimm r1, %rel(answer), 64 #<--- relevant lines
    load r1, r1, 0, 32 #<---
...
(%rel is a macro that returns the delta from the global section to the
'answer' symbol)

Instead of that last load instruction there, I want it to be:

    load r1, GRP, r1, 32 # r1 <-mem[GRP+r1]

GRP is what we call the Global Relocation Pointer - it holds the address
of the global address segment. So what this should do is load the contents
pointed to by the address (GRP+r1) into r1.

Of course, this is only if a non-static relocation model is chosen via
commandline options.

Phil

That's better, but now I get:

  XSTGInstrInfo.td:902:3: error: In RelAddr: XSTGRELADDR node requires
exactly 2 operands!

Which makes some sense as XSTGRELADDR is defined as:
def SDT_RELADDR : SDTypeProfile<1, 2, [SDTCisInt<0>,
SDTCisSameAs<0, 1>]>;
def XSTGRELADDR : SDNode<"XSTGISD::RELADDR", SDT_RELADDR>;

The problem is that the pattern that you use in the instruction
definition cannot have any value. That is, the top node has to consume all
values produced by the nodes below it. The node XSTGRELADDR does have a
value, and so it cannot be the top node.
If the intent is to have the second operand as the target register for
that value, it shouldn't be an operand to the SDNode, and in the
instruction definition it should be listed in the (outs) list. If the
second operand is not an output operand, then the RelAddr instruction
should have some additional operand in (outs) and use "set ..." in the
pattern, or have some other consumer as the top node in the selection
pattern.

I got it to compile by changing to:
def SDT_RELADDR : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0,
1>]>;
def XSTGRELADDR : SDNode<"XSTGISD::RELADDR", SDT_RELADDR>;

let Uses= [GRP] in {
  def RelAddr : XSTGPseudo< (outs GPRC:$dst),
                                      (ins GPRC:$spoff, GPRC:$addr),
                                      "! RELADDR $spoff, $dst",
                                      [(set GPRC:$dst, (XSTGRELADDR
GPRC:$addr, GPRC:$spoff))]>;
}

...though I'm not entirely sure if it's going to do what I want.

If you want the final address to be put in the same register as the input, you can add a constraint "$dst = $addr":

let Uses= [GRP] in {
    def RelAddr : XSTGPseudo<(outs GPRC:$dst),
               (ins GPRC:$spoff, GPRC:$addr),
               "! RELADDR $spoff, $dst",
               [(set GPRC:$dst, (XSTGRELADDR GPRC:$addr, GPRC:$spoff))],
               "$dst = $addr">;
}

-Krzysztof

I got it to compile by changing to:
def SDT_RELADDR : SDTypeProfile<1, 2, [SDTCisInt<0>,
SDTCisSameAs<0, 1>]>;
def XSTGRELADDR : SDNode<"XSTGISD::RELADDR", SDT_RELADDR>;

let Uses= [GRP] in {
   def RelAddr : XSTGPseudo< (outs GPRC:$dst),
                                       (ins GPRC:$spoff, GPRC:$addr),
                                       "! RELADDR $spoff, $dst",
                                       [(set GPRC:$dst, (XSTGRELADDR
GPRC:$addr, GPRC:$spoff))]>;
}

...though I'm not entirely sure if it's going to do what I want.

If you want the final address to be put in the same register as the input,
you can add a constraint "$dst = $addr":

let Uses= [GRP] in {
   def RelAddr : XSTGPseudo<(outs GPRC:$dst),
              (ins GPRC:$spoff, GPRC:$addr),
              "! RELADDR $spoff, $dst",
              [(set GPRC:$dst, (XSTGRELADDR GPRC:$addr, GPRC:$spoff))],
              "$dst = $addr">;

}

Our XSTGPseudo constructor doesn't allow for that. Is there a way to add
this kind of constraing after the definition?

Phil

After the definition, no. Could you try this instead?

let Constraints = "$dst = $addr", Uses= [GRP] in {
          def RelAddr : XSTGPseudo<(outs GPRC:$dst),
                     (ins GPRC:$spoff, GPRC:$addr),
                     "! RELADDR $spoff, $dst",
                     [(set GPRC:$dst, (XSTGRELADDR GPRC:$addr, GPRC:$spoff))]>;
}

-Krzysztof