Instructions working on 64bit registers without true support for 64bit operations

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Instructions working on 64bit registers without true support for 64bit operations

Fabian Scheler
Hi LLVM-Folks,

at our department we have an in-house developed back-end for the
TriCore processor and we want to upgrade it to LLVM 3.1. However, we
have some troubles regarding some instructions that work on 64bit
registers:

The TriCore processor has 16 32bit registers that can be paired to
form 64bit registers. Except a few instructions all work on 32bit
registers, thus the TriCore processor does not truly support 64bit
operations. These exceptional operations are division and
multiplication, for instance. In the tablegen files these registers
and the corresponding register class are modelled accordingly and the
instruction selector also selects them.

The paired 64bit register class is however not added within the
constructor of the TriCoreTargetLowering class. So, at some point
GetCostForDef is called for a MVT::i64 in connection with a division
instruction and this call segfaults as there just is no matching
register class available for TriCore.

Unfortunately, just adding the register class for MVT::i64 does not
help either. In that case the code generation framework assumes that
the TriCore could deal with MVT::i64 values and no longer expands all
the MVT::i64-stuff to MVT::i32-stuff during type legalization. As the
interface to configure the TypeLegalizeActions is not open to the
particular target implementations, I just did a quick and dirty hack
to tell the TypeLegalizer to expand operations on MVT::i64 values.
Though, this triggers an assertion in
"SelectionDAGLegalize::LegalizeOp".

Before I am going to do more "unguided hacking and guessing", I want
to task if there is an "official way" to support the setup described
above, i.e. having instructions working an 64bit registers (composed
of pairs of 32bit registers) without true support for MVT::i64 values.

Ciao, Fabian
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Instructions working on 64bit registers without true support for 64bit operations

Villmow, Micah
Fabian,
 We have a very similar setup with the AMDIL backend(some operations support 64bit some don't).

What we do is we enable MVT::i64, set legal to all operands that are legal and then set everything else to expand.

Micah

> -----Original Message-----
> From: [hidden email] [mailto:[hidden email]]
> On Behalf Of Fabian Scheler
> Sent: Wednesday, June 13, 2012 4:05 AM
> To: LLVM Developers Mailing List
> Subject: [LLVMdev] Instructions working on 64bit registers without true
> support for 64bit operations
>
> Hi LLVM-Folks,
>
> at our department we have an in-house developed back-end for the
> TriCore processor and we want to upgrade it to LLVM 3.1. However, we
> have some troubles regarding some instructions that work on 64bit
> registers:
>
> The TriCore processor has 16 32bit registers that can be paired to
> form 64bit registers. Except a few instructions all work on 32bit
> registers, thus the TriCore processor does not truly support 64bit
> operations. These exceptional operations are division and
> multiplication, for instance. In the tablegen files these registers
> and the corresponding register class are modelled accordingly and the
> instruction selector also selects them.
>
> The paired 64bit register class is however not added within the
> constructor of the TriCoreTargetLowering class. So, at some point
> GetCostForDef is called for a MVT::i64 in connection with a division
> instruction and this call segfaults as there just is no matching
> register class available for TriCore.
>
> Unfortunately, just adding the register class for MVT::i64 does not
> help either. In that case the code generation framework assumes that
> the TriCore could deal with MVT::i64 values and no longer expands all
> the MVT::i64-stuff to MVT::i32-stuff during type legalization. As the
> interface to configure the TypeLegalizeActions is not open to the
> particular target implementations, I just did a quick and dirty hack
> to tell the TypeLegalizer to expand operations on MVT::i64 values.
> Though, this triggers an assertion in
> "SelectionDAGLegalize::LegalizeOp".
>
> Before I am going to do more "unguided hacking and guessing", I want
> to task if there is an "official way" to support the setup described
> above, i.e. having instructions working an 64bit registers (composed
> of pairs of 32bit registers) without true support for MVT::i64 values.
>
> Ciao, Fabian
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev



_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Instructions working on 64bit registers without true support for 64bit operations

Fabian Scheler
Hi Micah,

>  We have a very similar setup with the AMDIL backend(some operations support 64bit some don't).
>
> What we do is we enable MVT::i64, set legal to all operands that are legal and then set everything else to expand.

thanks for your hint. Unfortunately, I didn't find any time to work on
my problem in the meantime as I was busy preparing lectures. However,
the summer term is almost over now and I can get back to this.

I already tried what you suggested, however I still end up getting the
following error message:

LLVM ERROR: Cannot select: 0x2299fb0: i64 = Constant<1> [ORD=1] [ID=1]

Just setting the Action to Expand here via

 setOperationAction(ISD::Constant,MVT::i64,Expand);

does not solve the problem. I took a look into your AMDIL-patch and
found out that your target supports this operation. I have the feeling
that this has to be lowered manually or has to be handled by
ISelDAGtoDAG or similar.

Well, I guess I have to dig a little bit deeper. If you have any other
suggestion - I definitely am interested ;-)

Ciao, Fabian
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Instructions working on 64bit registers without true support for 64bit operations

Tom Stellard-2
On Thu, Jul 12, 2012 at 01:22:39PM +0200, Fabian Scheler wrote:

> Hi Micah,
>
> >  We have a very similar setup with the AMDIL backend(some operations support 64bit some don't).
> >
> > What we do is we enable MVT::i64, set legal to all operands that are legal and then set everything else to expand.
>
> thanks for your hint. Unfortunately, I didn't find any time to work on
> my problem in the meantime as I was busy preparing lectures. However,
> the summer term is almost over now and I can get back to this.
>
> I already tried what you suggested, however I still end up getting the
> following error message:
>
> LLVM ERROR: Cannot select: 0x2299fb0: i64 = Constant<1> [ORD=1] [ID=1]
>
> Just setting the Action to Expand here via
>
>  setOperationAction(ISD::Constant,MVT::i64,Expand);
>
> does not solve the problem. I took a look into your AMDIL-patch and
> found out that your target supports this operation. I have the feeling
> that this has to be lowered manually or has to be handled by
> ISelDAGtoDAG or similar.
>
> Well, I guess I have to dig a little bit deeper. If you have any other
> suggestion - I definitely am interested ;-)
>

I took a look at lib/CodeGen/SelectionDAG/LegalizeDAG.cpp and it
doesn't look like there is an Expand operation implemented for
ISD::Constant.  I think you'll either need implement Expand for
ISD::Constant or Custom lower it in your backend.

Also, why is your frontend generating 64-bit constants?


-Tom
> Ciao, Fabian
> _______________________________________________
> LLVM Developers mailing list
> [hidden email]         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Instructions working on 64bit registers without true support for 64bit operations

Fabian Scheler
Hello Tom,

> I took a look at lib/CodeGen/SelectionDAG/LegalizeDAG.cpp and it
> doesn't look like there is an Expand operation implemented for
> ISD::Constant.  I think you'll either need implement Expand for
> ISD::Constant or Custom lower it in your backend.

thank you for that information. This exactly is what I feared. Well I
did some more mostly unguided hacking and these are the opportunities
I found/was pointed to:

1. Implement custom lowering in the backend

(cf. eg. SDNode *PPCDAGToDAGISel::Select(SDNode *N))

It is not a big issue to split the constant in the 32 higher and lower
bits and to load these fragments separately. However, I don't know how
to ensure that these fragments are put into the proper subregisters of
the register pair forming the 64bit register. For the PPC-backend this
is no problem as it has true 64bit register, this however is not the
case for the TriCore. So I need to get the vritual register (pair)
that will be used to store the 64bit value to access its subregisters.

2. Use a pattern consisting of INSERT_SUBREG-nodes

A colleague of mine (who originally implemented the TriCore-backend)
suggested to use a pattern that replaces 64bit-constants by tow
INSERT_SUBREG-nodes. I ended up having the following pattern:

def : Pat<(i64 imm:$imm),
          (INSERT_SUBREG
            (INSERT_SUBREG
              (i64 (IMPLICIT_DEF)),
              (i32 (LO32 imm:$imm)),
              sub_even),
            (i32 (HI32 imm:$imm)),
            sub_odd)>;

OK, this leaves a DAG where all i64-Constant-nodes are replaced by to
nested INSERT_SUBREG-nodes, but how do I get rid of that
INSERT_SUBREG-stuff. Do I have to lower it separately? Should there be
some magic that eliminates those nodes for me?

Maybe, I just have to make clear that (LO32 imm:$imm) yields a
32bit-Constant (How can I do this?), as there is another pattern to
load a 32bit-Constant into a register.

Is there some documentation how all this INSERT_SUBREG-stuff should be
used and how it should work? I didn't find anything helpful here. Is
INSERT_SUBREG suitable to solve that kind of problem? In an older
post, INSERT_SUBREG was envisaged to load an i16-Value into a pair of
8bit-registers in the PIC-backend, however the outcome of this was not
mentioned. I also didn't not find any INSERT_SUBREG-stuff in the
PIC-backend in LLVM 2.7. Maybe, someone else knows something about it,
the post is here:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2008-October/017443.html

I really whish I could force TypeLegalization to expand i64 although
adding a 64bit-Register class ...

> Also, why is your frontend generating 64-bit constants?

Well, using clang to translate to following piece of code:

unsigned long long do_something(unsigned long long);

unsigned long long myfunc(unsigned long long param) {
  unsigned long long b = 4500000;
  unsigned long long c = b + param;
  return c + do_something(5);
}

yields an LLVM-assembly file containing 64bit constants as follows:

define i64 @myfunc(i64 %param) nounwind uwtable {
  %1 = alloca i64, align 8
  %b = alloca i64, align 8
  %c = alloca i64, align 8
  store i64 %param, i64* %1, align 8
  store i64 4500000, i64* %b, align 8
  %2 = load i64* %b, align 8
  %3 = load i64* %1, align 8
  %4 = add i64 %2, %3
  store i64 %4, i64* %c, align 8
  %5 = load i64* %c, align 8
  %6 = call i64 @do_something(i64 5)
  %7 = add i64 %5, %6
  ret i64 %7
}

declare i64 @do_something(i64)

Ciao, Fabian
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Instructions working on 64bit registers without true support for 64bit operations

Fabian Scheler
Hi LLVM-folks,

I just wanted to let you know, that I finally succeeded to load an
64-bit immediate value
using a pattern incorporating two INSERT_SUBREG-nodes.

> 2. Use a pattern consisting of INSERT_SUBREG-nodes
>
> A colleague of mine (who originally implemented the TriCore-backend)
> suggested to use a pattern that replaces 64bit-constants by tow
> INSERT_SUBREG-nodes. I ended up having the following pattern:
>
> def : Pat<(i64 imm:$imm),
>           (INSERT_SUBREG
>             (INSERT_SUBREG
>               (i64 (IMPLICIT_DEF)),
>               (i32 (LO32 imm:$imm)),
>               sub_even),
>             (i32 (HI32 imm:$imm)),
>             sub_odd)>;

The pattern I use for this purpose looks like this:

def : Pat<(i64 imm:$imm),
          (INSERT_SUBREG (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
                                             (ADDIrlc (MOVHrlc (HA16 (i32
(LO32 imm:$imm)))), (LO16 (i32 (LO32 imm:$imm)))),
                                             sub_even)),
                         (ADDIrlc (MOVHrlc (HA16 (i32 (HI32
imm:$imm)))), (LO16 (i32 (HI32 imm:$imm)))),
                         sub_odd)>;

here {HA,LO}16 {HI,LO} looks like this:

// Lower 16 bits of a 32-bit word
def LO16 : SDNodeXForm<imm, [{
  return getLo16(N);
}]>;

// Higher 16 bits (arithmetic) of a 32-bit word
def HA16 : SDNodeXForm<imm, [{
  return getHa16(N);
}]>;

// Lower 32 bits of a 64-bit word
def LO32 : SDNodeXForm<imm, [{
  return getConst((uint32_t) N->getZExtValue(), MVT::i32);;
}]>;

// Higher 32 bits (logical) of a 64-bit word
def HI32 : SDNodeXForm<imm, [{
  return getConst((uint32_t)(N->getZExtValue() >> 32), MVT::i32);
}]>;

The pattern posted first did not work for the following two reasons (I
guess, but I don't know):

1. My calling conventions were not set up properly, ie. 64-bit
parameter passing was not specified.

2. The expansion mentioned below was not carried out by tablegen :-( I
have another pattern
to load an 32-bit immediate constant:

def : Pat<(i32 imm:$imm), (ADDIrlc (MOVHrlc (HA16 imm:$imm)), (LO16 imm:$imm))>;

However, I was not able to specify that {HI,LO}32 yield 32-bit
immediates so the pattern above matches ....

> OK, this leaves a DAG where all i64-Constant-nodes are replaced by to
> nested INSERT_SUBREG-nodes, but how do I get rid of that
> INSERT_SUBREG-stuff. Do I have to lower it separately? Should there be
> some magic that eliminates those nodes for me?
>
> Maybe, I just have to make clear that (LO32 imm:$imm) yields a
> 32bit-Constant (How can I do this?), as there is another pattern to
> load a 32bit-Constant into a register.

Ciao, Fabian
_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev