Inserting an assembly instruction in the calling sequence of the powerpc target

Hi all,

I'm currently implementing a linux/ppc target in llvm. The abis between Darwin/ppc and
linux/ppc are different and I'm running into problems with vararg calls.

Before a variadic method is called, an extra instruction must be executed (which is creqv 6, 6, 6). This
instruction is not necessary in Darwin/ppc.
I looked into the PowerPC target implementation and the code generation uses
Dags (lib/Target/PowerPC/PPCISelLowering.cpp, LowerCALL).

I need some help on how to insert the creqv instruction in the calling sequence.

After this is implemented, I will be able to send a patch for linux/ppc support.

I also need to know what is your preference for a linux/ppc target implementation? I can either
1) Use macros (#ifdef __MACH__ for darwin or #ifdef __PPC__ for linux)
2) Test the target in the code when needed
   if (os == linux && ppc32) then...
   else if (os == linux && ppc64) then ...
   else if (os == darwin && ppc32) then ...
   else if (os == darwin && ppc64) then ...
3) Create a new subtarget (but does it worth it? considering that the difference between the 2 abis is minor)

Thx for your help.

Cheers,
Nicolas

I'm currently implementing a linux/ppc target in llvm. The abis between

cool

Darwin/ppc and linux/ppc are different and I'm running into problems with vararg calls.

ok

Before a variadic method is called, an extra instruction must be executed (which is creqv 6, 6, 6). This instruction is not necessary in Darwin/ppc.
I looked into the PowerPC target implementation and the code generation uses
Dags (lib/Target/PowerPC/PPCISelLowering.cpp, LowerCALL).

right.

I need some help on how to insert the creqv instruction in the calling
sequence.

The basic approach you want to take:
1. Introduce a new target-specific dag node to represent "SETCR", which
    takes a single register operand (in this case, CR6).
2. At call lowering time, flag this into the call sequence.
3. At ISel time, turn this into creq reg,reg,reg

After this is implemented, I will be able to send a patch for linux/ppc
support.

Nice. This will also resolve ppc linux doesn't handle float parameter to varargs function · Issue #1436 · llvm/llvm-project · GitHub

I also need to know what is your preference for a linux/ppc target
implementation? I can either
1) Use macros (#ifdef __MACH__ for darwin or #ifdef __PPC__ for linux)

This won't work for cross compiles.

2) Test the target in the code when needed
  if (os == linux && ppc32) then...
  else if (os == linux && ppc64) then ...
  else if (os == darwin && ppc32) then ...
  else if (os == darwin && ppc64) then ...

This is inefficient :slight_smile:

3) Create a new subtarget (but does it worth it? considering that the
difference between the 2 abis is minor)

There is already a subtarget. In the call lowering code, just do something like:

if (!PPCSubTarget->isDarwin())
   ... insert creq here ...

-Chris

Hi Crhis,

Chris Lattner wrote:

The basic approach you want to take:
1. Introduce a new target-specific dag node to represent "SETCR", which
    takes a single register operand (in this case, CR6).
  

That I did. I introduced the creqv instruction in PPCInstrInfo.td and
inserted a SETCR in the PPCISD::NodeType enum, file PPCSelLowering.h.

2. At call lowering time, flag this into the call sequence.
  

I'm still confused on how flags operate into the call sequence. I tried
to do :

  if (isVarArg)
    {
      InFlag = DAG.getNode(PPCISD::SETCR, MVT::i32,
                                DAG.getRegister(PPC::CR6, MVT::i32));
    }

in PPCISelLowering.cpp after the copy-to-reg sequence (line 1462 in llvm-cvs), but it does not
work (I always get wrong assertions)

3. At ISel time, turn this into creq reg,reg,reg

If I understand correctly, all I have to do for this is to add in PPCISelDagToDag.cpp::Select a switch case where:

  case PPCISD::SETCR : {
    SDOperand InFlag = N->getOperand(0);
    return CurDAG->getTargetNode(PPC::CREQV, MVT::i32, InFlag, InFlag);
  }

2) Test the target in the code when needed
  if (os == linux && ppc32) then...
  else if (os == linux && ppc64) then ...
  else if (os == darwin && ppc32) then ...
  else if (os == darwin && ppc64) then ...
    
This is inefficient :slight_smile:
  
There is already a subtarget. In the call lowering code, just do something like:

if (!PPCSubTarget->isDarwin())
   ... insert creq here ...

OK, that's what I meant with my second proposition.

-Chris

Thx,
Nicolas