Adding address registers to back-end

Hi!

  I'm writing a new back-end for a new architecture. First, I'll do some "tests" with an existing back-end (I chose the Sparc back-end). My architecture has special address-registers and I want to add such new address-registers to my Sparc back-end.

1) I defined a new register call AddrRegs
2) I registered the class AddrRegs (addRegisterClass(MVT::iPTR, .. ))
3) I added method addPointerRegClass() to my InstrInfo class

  The compiler generates the some code as before, but that seems to be ok, because I haven't used ptr_rc yet.

4) I changed the address mode MEMri:

def MEMri : Operand<iPTR> {
   let PrintMethod = "printMemOperand";
   // was: let MIOperandInfo = (ops IntRegs, i32imm);
   let MIOperandInfo = (ops ptr_rc, i32imm);
}

for the C code int c; void f(void) { c = 4711; } I get the error message:

Register class of operand and regclass of use don't agree!
Operand = 0
Op->Val = 0x42b08d60: i32 = SETHIi 0x42b08d00
MI = STri %reg1026
VReg = 1026
VReg RegClass size = 4, align = 4
Expected RegClass size = 4, align = 4

  The GlobalAddress for variable c is replaced by an ADD(HI(c), LO(c)) during lowering. I assume the code-generator cant place values in the address registers? All address-registers are elements in the register sets IntRegs and AddrRegs.

  Using address registers is part of the ppc code-generator and I'm checking that one, but I can't see the differences. Can someone guide me?

Thanks,
Boris

Hi!

  I'm writing a new back-end for a new architecture. First, I'll do
some "tests" with an existing back-end (I chose the Sparc back-end).
My architecture has special address-registers and I want to add such
new address-registers to my Sparc back-end.

1) I defined a new register call AddrRegs
2) I registered the class AddrRegs (addRegisterClass(MVT::iPTR, .. ))
3) I added method addPointerRegClass() to my InstrInfo class

  The compiler generates the some code as before, but that seems to
be ok, because I haven't used ptr_rc yet.

4) I changed the address mode MEMri:

def MEMri : Operand<iPTR> {
   let PrintMethod = "printMemOperand";
   // was: let MIOperandInfo = (ops IntRegs, i32imm);
   let MIOperandInfo = (ops ptr_rc, i32imm);
}

for the C code int c; void f(void) { c = 4711; } I get the error
message:

Register class of operand and regclass of use don't agree!
Operand = 0
Op->Val = 0x42b08d60: i32 = SETHIi 0x42b08d00
MI = STri %reg1026
VReg = 1026
VReg RegClass size = 4, align = 4
Expected RegClass size = 4, align = 4

  The GlobalAddress for variable c is replaced by an ADD(HI(c), LO
(c)) during lowering. I assume the code-generator cant place values
in the address registers? All address-registers are elements in the
register sets IntRegs and AddrRegs.

/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
   def rr : F3_1<2, Op3Val,
                  (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
                  !strconcat(OpcStr, " $b, $c, $dst"),
                  [(set IntRegs:$dst, (OpNode IntRegs:$b, IntRegs:$c))]>;
   def ri : F3_2<2, Op3Val,
                  (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
                  !strconcat(OpcStr, " $b, $c, $dst"),
                  [(set IntRegs:$dst, (OpNode IntRegs:$b, simm13:$c))]>;
}

defm ADD : F3_12<"add", 0b000000, add>;

Instruction ADD output register class is IntRegs. It does not match AddrRegs. That's why you are getting the assertion.

What you need is to define a parallel set of instructions that target the address register class. Then you can tell the instruction selector to select to these instructions instead of the normal ADD instruction. Perhaps the solution is to custom lower load / store addresses to be "casted". Then write patterns that fold the cast and select to the address register class variant of ADD, etc. There hasn't been any publicly committed targets that require address register class so I haven't spent anytime thinking of a clean solution. For a hackish solution, please read the thread called "Q about instruction pattern matching" between Andreas Fredriksson and myself.

Evan

Hi!

  I'm writing a new back-end for a new architecture. First, I'll do
some "tests" with an existing back-end (I chose the Sparc back-end).
My architecture has special address-registers and I want to add such
new address-registers to my Sparc back-end.
....
  The GlobalAddress for variable c is replaced by an ADD(HI(c), LO
(c)) during lowering. I assume the code-generator cant place values
in the address registers? All address-registers are elements in the
register sets IntRegs and AddrRegs.

/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
....
}

defm ADD : F3_12<"add", 0b000000, add>;

Instruction ADD output register class is IntRegs. It does not match
AddrRegs. That's why you are getting the assertion.

  The address register set AddrRegs is a subset of IntRegs. Do you compare the register set identifiers instead of the register itself and if it is within a set?

What you need is to define a parallel set of instructions that target
the address register class.

  Every operand or or target of the 3 address-machine can be a data or address register. Then I had to write 8 (2^3) patterns per instruction. But register classes/sets are used to fold that. I do that since ~1996 (~11 years)! We used BEG as code-generator-generator.

There
hasn't been any publicly committed targets that require address
register class so I haven't spent anytime thinking of a clean
solution.

  This has nothing to do with address registers! This has to do with registers and their sets. Address registers are an obvious / famous example, but one can think of other cases. Free your mind! :wink:

  A register can be in multiple sets! If a value is written into a register r of class A, then a pattern with class B can match if register r is an element of class B. In Bottom Up Pattern Matchers we use "chain rules" to transform a non-terminal/register-class to another non-terminal/register-class.

  So, what should I do next? What do you suggest? Modify the register allocator?

Thanks,
Boris

Hi!

I'm writing a new back-end for a new architecture. First, I'll do
some "tests" with an existing back-end (I chose the Sparc back-end).
My architecture has special address-registers and I want to add such
new address-registers to my Sparc back-end.
....
The GlobalAddress for variable c is replaced by an ADD(HI(c), LO
(c)) during lowering. I assume the code-generator cant place values
in the address registers? All address-registers are elements in the
register sets IntRegs and AddrRegs.

/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
....
}

defm ADD : F3_12<"add", 0b000000, add>;

Instruction ADD output register class is IntRegs. It does not match
AddrRegs. That's why you are getting the assertion.

The address register set AddrRegs is a subset of IntRegs. Do you
compare the register set identifiers instead of the register itself
and if it is within a set?

So, what should I do next? What do you suggest? Modify the register
allocator?

This assertion is in ScheduleDAG.cpp. It's asserting while lowering the DAG into a sequence of machine instructions. Right now, it's pretty simple minded, excepting the register class of the virtual register to *exactly* match the register class of the instruction use operand definition. Changing the code to allow the case you've described, i.e. the definition RC is a subset of the use RC, sounds like a good approach. Patch is welcome.

Evan