INSERT_SUBREG node.

What’s the value produced by an INSERT_SUBREG node? Is it a chain?

Can I use to set a superreg of i16 type with two i8 values, and use the supperreg as an operand somewhere else?

  • Sanjiv

What’s the value produced by an INSERT_SUBREG node? Is it a chain?

No, insert_subreg returns a value:

v1 = insert_subreg v2, v3, idx

v1 and v2 will have the same type, e.g. i16, and v3 must have a sub-register type, e.g. i8.

Can I use to set a superreg of i16 type with two i8 values, and use the supperreg as an operand somewhere else?

Suppose you want to use a pair of i8 v1, v2 to create a i16 v3. The way to do it is:

v4 = insert_subreg implicit_def, v1, 0
v3 = insert_subreg v4, v2, 1

Evan

> What’s the value produced by an INSERT_SUBREG node? Is it a chain?

No, insert_subreg returns a value:

v1 = insert_subreg v2, v3, idx

v1 and v2 will have the same type, e.g. i16, and v3 must have a
sub-register type, e.g. i8.

>
> Can I use to set a superreg of i16 type with two i8 values, and use
> the supperreg as an operand somewhere else?

Suppose you want to use a pair of i8 v1, v2 to create a i16 v3. The
way to do it is:

v4 = insert_subreg implicit_def, v1, 0
v3 = insert_subreg v4, v2, 1

Evan

This is how my register classes look like:
  
  def FSR0L : Register<"FSR0L">;
  def FSR0H : Register<"FSR0H">;
  def FSR1L : Register<"FSR1L">;
  def FSR1H : Register<"FSR1H">;

  def FSR0 : RegisterWithSubRegs<"FSR0", [FSR0H, FSR0L]>;
  def FSR1 : RegisterWithSubRegs<"FSR1", [FSR1H, FSR1L]>;

  def FSR8RC : RegisterClass<"PIC16", [i8], 8, [FSR0L, FSR0H, FSR0L,
FSR1H]>;

  def FSR16RC : RegisterClass<"PIC16", [i16], 8, [FSR0, FSR1]> {
    let SubRegClassList = [FSR8RC];
  }

in my case I want to insert two values, which are available in register
types of FSR8RC, into a register type of FSR16RC.

when I use and INSERT_SUBREG with an SubIdx = 0, as you mentioned in

v4= insert_subreg implicit_def, v1, 0

the following function returns an incorrect subregclass:

static const TargetRegisterClass*
getSubRegisterRegClass(const TargetRegisterClass *TRC, unsigned SubIdx)
{
  // Pick the register class of the subregister
  TargetRegisterInfo::regclass_iterator I =
    TRC->subregclasses_begin() + SubIdx-1;
  assert(I < TRC->subregclasses_end() &&
         "Invalid subregister index for register class");
  return *I;
}

what does -1 do while initializing I in the above fn?

TIA,
Sanjiv

You need to specify sub-register == super-register, idx relationship. See X86RegisterInfo.td:

def x86_subreg_8bit : PatLeaf<(i32 1)>;
def x86_subreg_16bit : PatLeaf<(i32 2)>;
def x86_subreg_32bit : PatLeaf<(i32 3)>;

def : SubRegSet<1, [AX, CX, DX, BX, SP, BP, SI, DI,
                     R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
                    [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
                     R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;

I admit the way it's specified is not very elegant. We'll clean it up some day.

Evan

Even in that case you can not have a 0 as a SubIdx.
e.g. the code below won't work

  def x86_subreg_8bit : PatLeaf<(i32 0)>;

def : SubRegSet<0, [AX, CX, DX, BX, SP, BP, SI, DI,
                     R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
                    [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
                     R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;

class GR16_ ..... {
  let SubRegClassList = [GR8];
}

Refer to below functions in ScheduleDAGEmit.cpp:

You need to specify sub-register == super-register, idx relationship.
See X86RegisterInfo.td:

def x86_subreg_8bit : PatLeaf<(i32 1)>;
def x86_subreg_16bit : PatLeaf<(i32 2)>;
def x86_subreg_32bit : PatLeaf<(i32 3)>;

def : SubRegSet<1, [AX, CX, DX, BX, SP, BP, SI, DI,
                    R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
                   [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
                    R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;

I admit the way it's specified is not very elegant. We'll clean it up
some day.

Evan

Even in that case you can not have a 0 as a SubIdx.
e.g. the code below won't work

def x86_subreg_8bit : PatLeaf<(i32 0)>;

def : SubRegSet<0, [AX, CX, DX, BX, SP, BP, SI, DI,
                    R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
                   [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
                    R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;

class GR16_ ..... {
let SubRegClassList = [GR8];
}

Right. Subreg index starts from 1. This ought to be fixed but it's not (yet).

The getSubRegisterRegClass uses SubIdx - 1;

so INSERT_SUBREG (IMPLICIT_DEF, AL, 0) will not work, because getSubRegisterRegClass will fail.(GR16_ does not have a SubRegClass at index -1.)

OTOH, if you use SubIdx as 1, both in SubRegSet and x86_subreg_8bit, the INSERT_SUBREG (IMPLICIT_DEF, AL, 1) will work.

Ok.

But then INSERT_SUBREG (AX, AH, 2) will not work because getSubRegisterRegClass will fail again. (GR16_ does not have a SubRegClass at index 1.)

Ok. The AX / AH super-reg and sub-reg relationship is not defined. In general x86 is not making good use of the high 8-bit sub-registers. We are leaving some performance on the table. We'll probably fix it one day. However, this doesn't apply to your target, right? There is nothing preventing you from specifying the sub-registers and making use of insert_subreg, no?

Evan

>> You need to specify sub-register == super-register, idx relationship.
>> See X86RegisterInfo.td:
>>
>> def x86_subreg_8bit : PatLeaf<(i32 1)>;
>> def x86_subreg_16bit : PatLeaf<(i32 2)>;
>> def x86_subreg_32bit : PatLeaf<(i32 3)>;
>>
>> def : SubRegSet<1, [AX, CX, DX, BX, SP, BP, SI, DI,
>> R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
>> [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
>> R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;
>>
>> I admit the way it's specified is not very elegant. We'll clean it up
>> some day.
>>
>> Evan
>>
> Even in that case you can not have a 0 as a SubIdx.
> e.g. the code below won't work
>
> def x86_subreg_8bit : PatLeaf<(i32 0)>;
>
>
> def : SubRegSet<0, [AX, CX, DX, BX, SP, BP, SI, DI,
> R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W],
> [AL, CL, DL, BL, SPL, BPL, SIL, DIL,
> R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>;
>
>
> class GR16_ ..... {
> let SubRegClassList = [GR8];
> }

Right. Subreg index starts from 1. This ought to be fixed but it's not
(yet).

>
>
> The getSubRegisterRegClass uses SubIdx - 1;
>
> so INSERT_SUBREG (IMPLICIT_DEF, AL, 0) will not work, because
> getSubRegisterRegClass will fail.(GR16_ does not have a SubRegClass
> at index -1.)
>
> OTOH, if you use SubIdx as 1, both in SubRegSet and x86_subreg_8bit,
> the INSERT_SUBREG (IMPLICIT_DEF, AL, 1) will work.

Ok.

>
>
> But then INSERT_SUBREG (AX, AH, 2) will not work because
> getSubRegisterRegClass will fail again. (GR16_ does not have a
> SubRegClass at index 1.)

Ok. The AX / AH super-reg and sub-reg relationship is not defined. In
general x86 is not making good use of the high 8-bit sub-registers. We
are leaving some performance on the table. We'll probably fix it one
day. However, this doesn't apply to your target, right? There is
nothing preventing you from specifying the sub-registers and making
use of insert_subreg, no?

Evan

it is, though we have a workaround.

We have 16-bit registers class and want to set both the lo and high
parts using INSERT_SUBREG.

The workaround is to declare the same SubRegClass twice while declaring
the SuperRegisterClass. i.e.

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
  let SubRegClassList = [FSR8, FSR8]; // HERE.
}

SubRegSet : <1, [FSR0, FSR1], [FSR0L, FSR0H]>;
SubRegSet : <2, [FSR0, FSR1], [FSR0H, FSR0L]>;

I think the fundamental problem we have there is that we are using
SubIdx for both purposes: 1. to enumerate over subregister classses, 2.
To enumerate subregs of the same type of a super reg.

- Sanjiv.

Ok. The AX / AH super-reg and sub-reg relationship is not defined. In
general x86 is not making good use of the high 8-bit sub-registers. We
are leaving some performance on the table. We'll probably fix it one
day. However, this doesn't apply to your target, right? There is
nothing preventing you from specifying the sub-registers and making
use of insert_subreg, no?

Evan

it is, though we have a workaround.

We have 16-bit registers class and want to set both the lo and high
parts using INSERT_SUBREG.

The workaround is to declare the same SubRegClass twice while declaring
the SuperRegisterClass. i.e.

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
let SubRegClassList = [FSR8, FSR8]; // HERE.
}

This is a bug, probably in tablegen. Unfortunately I don't have the time to fix it. But please file a bug about this. Hopefully someone will fix it soon.

Thanks,

Evan

PR2916 filed.
Though I did not quite understand why this could be a tablegen bug?

- Sanjiv

Ok. The AX / AH super-reg and sub-reg relationship is not defined. In

general x86 is not making good use of the high 8-bit sub-registers.

We

are leaving some performance on the table. We’ll probably fix it one

day. However, this doesn’t apply to your target, right? There is

nothing preventing you from specifying the sub-registers and making

use of insert_subreg, no?

Evan

it is, though we have a workaround.

We have 16-bit registers class and want to set both the lo and high

parts using INSERT_SUBREG.

The workaround is to declare the same SubRegClass twice while

declaring

the SuperRegisterClass. i.e.

def FSR16: RegisterClass <“PIC16”, [i16], 8, [FSR0, FSR1]> {

let SubRegClassList = [FSR8, FSR8]; // HERE.

}

This is a bug, probably in tablegen. Unfortunately I don’t have the

time to fix it. But please file a bug about this. Hopefully someone

will fix it soon.

Thanks,

Evan

PR2916 filed.
Though I did not quite understand why this could be a tablegen bug?

Based on your comments. :slight_smile: It should be possible to specify two FSR0 sub-registers (FSR0L, FSR0H of the same register class FSR8) with the workaround you described:

def FSR16: RegisterClass <“PIC16”, [i16], 8, [FSR0, FSR1]> {
let SubRegClassList = [FSR8, FSR8]; // HERE.
}

Evan

> >
> > > > >
> > > >
> > > > Ok. The AX / AH super-reg and sub-reg relationship is not
> > > > defined. In
> > > > general x86 is not making good use of the high 8-bit
> > > > sub-registers.
> > > > We
> > > > are leaving some performance on the table. We'll probably fix
> > > > it one
> > > > day. However, this doesn't apply to your target, right? There
> > > > is
> > > > nothing preventing you from specifying the sub-registers and
> > > > making
> > > > use of insert_subreg, no?
> > > >
> > > > Evan
> > > >
> > > it is, though we have a workaround.
> > >
> > > We have 16-bit registers class and want to set both the lo and
> > > high
> > > parts using INSERT_SUBREG.
> > >
> > > The workaround is to declare the same SubRegClass twice while
> > > declaring
> > > the SuperRegisterClass. i.e.
> > >
> > > def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
> > > let SubRegClassList = [FSR8, FSR8]; // HERE.
> > > }
> >
> > This is a bug, probably in tablegen. Unfortunately I don't have
> > the
> > time to fix it. But please file a bug about this. Hopefully
> > someone
> > will fix it soon.
> >
> > Thanks,
> >
> > Evan
> >
>
> PR2916 filed.
> Though I did not quite understand why this could be a tablegen bug?

Based on your comments. :slight_smile: It should be possible to specify two FSR0
sub-registers (FSR0L, FSR0H of the same register class FSR8) with the
workaround you described:

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
let SubRegClassList = [FSR8, FSR8]; // HERE.
}

It is currently possible.

- Sanjiv

PR2916 filed.
Though I did not quite understand why this could be a tablegen bug?

Based on your comments. :slight_smile: It should be possible to specify two FSR0
sub-registers (FSR0L, FSR0H of the same register class FSR8) with the
workaround you described:

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
let SubRegClassList = [FSR8, FSR8]; // HERE.
}

It is currently possible.

I am confused. Is what you described in PR2916 an issue or not?

Evan

>>>
>>> PR2916 filed.
>>> Though I did not quite understand why this could be a tablegen bug?
>>
>>
>> Based on your comments. :slight_smile: It should be possible to specify two FSR0
>> sub-registers (FSR0L, FSR0H of the same register class FSR8) with the
>> workaround you described:
>>
>>
>> def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
>> let SubRegClassList = [FSR8, FSR8]; // HERE.
>> }
>>
> It is currently possible.

I am confused. Is what you described in PR2916 an issue or not?

is specifying the same subregclass two times okay? or do we need to
cleanup the implementation so that you specify a SubRegClass only once.
The other related issue is that we can not use SubIdx starting from
Zero.

- Sanjiv

PR2916 filed.
Though I did not quite understand why this could be a tablegen bug?

Based on your comments. :slight_smile: It should be possible to specify two FSR0
sub-registers (FSR0L, FSR0H of the same register class FSR8) with the
workaround you described:

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
let SubRegClassList = [FSR8, FSR8]; // HERE.
}

It is currently possible.

I am confused. Is what you described in PR2916 an issue or not?

is specifying the same subregclass two times okay? or do we need to
cleanup the implementation so that you specify a SubRegClass only once.
The other related issue is that we can not use SubIdx starting from

Yep. Both should be (eventually) fixed, especially the first one.

Evan

Hi Sanjiv,

What you have below is the currently expected way of declaring sub registers, I agree that it's somewhat inelegant as well as poorly documented.

1) Yes, sub register sets start with enumeration number 1. I believe this has to do with the layout of some static data structures that reserve entry 0...

2) The "duplicate" class entries in SubRegClassList is not really a duplicate, but specifies for each SubRegSet the register class that is expected for the sub registers in that set. This is needed for registers that have sub registers of many different types. So for your architecture:

let SubRegClassList = [
  FSR8, // Type of SubRegSet 1
  FSR8 // Type of SubRegSet 2
];

Imagine you have a FSR32 register class, that contains both 16-bit and 8-bit sub registers, you may end up with a class list like:

let SubRegClassList = [
  FSR8, // Type of SubRegSet 1
  FSR8, // Type of SubRegSet 2
  FSR16, // Type of SubRegSet 3
  FSR16 // Type of SubRegSet 4
];

I think that there are definitely more clear ways of attaching SubRegSet's to the class of registers they belong to, as well as specifying the sub register type in the set. Perhaps syntax along the lines of this:

def FSR16: RegisterClass <"PIC16", [i16], 8, [FSR0, FSR1]> {
   let SubRegClassList = [
  <0, FSR8, [FSR0L, FSR0H]>,
  <1, FSR8, [FSR0H, FSR0L]>
    ];
}

Unfortunately I have little time for TableGen hacking at the moment. =)