Implementing a complicated VAARG

Hi everyone,

I'm implementing varags handling for PPC32 with the ELF ABI. It is largely more
complicated than the Macho ABI or x86 because it manipulates a struct
instead of a direct pointer in the stack. You can find the layout of the va_list struct
at the end of this mail.

A VAARG call requires a lot of computation. Typically the C code for va_arg(ap, int)
is:

int va_arg_gpr(ap_list ap) {
    int idx = ap->gpr;
    if (idx < 8) {
        ap->gpr = idx + 1;
        return ap->reg_save_area[idx];
    }
    else {
      int res = ap->overflow_arg_area[0];
      ap->gpr = idx + 1;
      ap->overflow_arg_area += 4;
      return res;
    }
}

Actually, all VAARG implementations for other backends use DAGs, but this may be
too complicated to do for ELF32.

What would you suggest to code the VAARG instruction efficiently?
Should I code va_arg_gpr with DAGs (many lines of code) or should I create a DAG that will
call the C method va_arg_gpr (Btw, i do not know how to do this ;))?

Thanks for your help!

Best,
Nicolas

  // For ELF 32 ABI we follow the layout of the va_list struct.
  // We suppose the given va_list is already allocated.
  //
  // typedef struct {
  // char gpr; /* index into the array of 8 GPRs
  // * stored in the register save area
  // * gpr=0 corresponds to r3,
  // * gpr=1 to r4, etc.
  // */
  // char fpr; /* index into the array of 8 FPRs
  // * stored in the register save area
  // * fpr=0 corresponds to f1,
  // * fpr=1 to f2, etc.
  // */
  // char *overflow_arg_area;
  // /* location on stack that holds
  // * the next overflow argument
  // */
  // char *reg_save_area;
  // /* where r3:r10 and f1:f8 (if saved)
  // * are stored
  // */
  // } va_list[1];

A VAARG call requires a lot of computation. Typically the C code for
va_arg(ap, int)

If you use va_arg in C, are you seeing llvm.vaarg in the output .ll file?

-Chris

is:

int va_arg_gpr(ap_list ap) {
   int idx = ap->gpr;
   if (idx < 8) {
       ap->gpr = idx + 1;
       return ap->reg_save_area[idx];
   }
   else {
     int res = ap->overflow_arg_area[0];
     ap->gpr = idx + 1;
     ap->overflow_arg_area += 4;
     return res;
   }
}

Actually, all VAARG implementations for other backends use DAGs, but
this may be
too complicated to do for ELF32.

What would you suggest to code the VAARG instruction efficiently?
Should I code va_arg_gpr with DAGs (many lines of code) or should I
create a DAG that will
call the C method va_arg_gpr (Btw, i do not know how to do this ;))?

Thanks for your help!

Best,
Nicolas

// For ELF 32 ABI we follow the layout of the va_list struct.
// We suppose the given va_list is already allocated.
//
// typedef struct {
// char gpr; /* index into the array of 8 GPRs
// * stored in the register save area
// * gpr=0 corresponds to r3,
// * gpr=1 to r4, etc.
// */
// char fpr; /* index into the array of 8 FPRs
// * stored in the register save area
// * fpr=0 corresponds to f1,
// * fpr=1 to f2, etc.
// */
// char *overflow_arg_area;
// /* location on stack that holds
// * the next overflow argument
// */
// char *reg_save_area;
// /* where r3:r10 and f1:f8 (if saved)
// * are stored
// */
// } va_list[1];
_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris

Hi Chris,

Chris Lattner wrote:

  

A VAARG call requires a lot of computation. Typically the C code for
va_arg(ap, int)
    
If you use va_arg in C, are you seeing llvm.vaarg in the output .ll file?
  

I'm guessing that if you're asking, then no llvm.vaarg is generated. I can not
test it on my box 'cause llvm-gcc does not compile on Linux/PPC, but the llvm.org
online demo does not indeed generate a llvvm.vaarg instruction.

But this is horribly not portable! The va_arg(ap, int) for Linux/PPC is really different
from Darwin/PPC (see my previous message). And the .ll file generated by llvm-gcc
can not be executed on Linux/PPC.

Btw, I'm using the JIT of llvm, not llvm-gcc, I do not code in C to generate llvm code, but
in "MyLanguage". And I want "MyLanguage" to have variadic functions and interoperate
with C code.

Cheers,
Nicolas

This isn't much more (any more?) complex than Alpha's vaargs. You can
do it without introducing any new branches with some selects and
generate DAG code directly.

Andrew

I'm guessing that if you're asking, then no llvm.vaarg is generated. I can not test it on my box 'cause llvm-gcc does not compile on Linux/PPC, but the llvm.org online demo does not indeed generate a llvvm.vaarg instruction.

ok

But this is horribly not portable! The va_arg(ap, int) for Linux/PPC is
really different
from Darwin/PPC (see my previous message).

I agree.

And the .ll file generated by
llvm-gcc
can not be executed on Linux/PPC.

Right.

Btw, I'm using the JIT of llvm, not llvm-gcc, I do not code in C to generate llvm code, but in "MyLanguage". And I want "MyLanguage" to have variadic functions and interoperate with C code.

Ok, if you have a non-C input, implementing llvm.vaarg is important. :slight_smile:

-Chris

Cheers,
Nicolas

-Chris

is:

int va_arg_gpr(ap_list ap) {
   int idx = ap->gpr;
   if (idx < 8) {
       ap->gpr = idx + 1;
       return ap->reg_save_area[idx];
   }
   else {
     int res = ap->overflow_arg_area[0];
     ap->gpr = idx + 1;
     ap->overflow_arg_area += 4;
     return res;
   }
}

Actually, all VAARG implementations for other backends use DAGs, but
this may be
too complicated to do for ELF32.

What would you suggest to code the VAARG instruction efficiently?
Should I code va_arg_gpr with DAGs (many lines of code) or should I
create a DAG that will
call the C method va_arg_gpr (Btw, i do not know how to do this ;))?

Thanks for your help!

Best,
Nicolas

// For ELF 32 ABI we follow the layout of the va_list struct.
// We suppose the given va_list is already allocated.
//
// typedef struct {
// char gpr; /* index into the array of 8 GPRs
// * stored in the register save area
// * gpr=0 corresponds to r3,
// * gpr=1 to r4, etc.
// */
// char fpr; /* index into the array of 8 FPRs
// * stored in the register save area
// * fpr=0 corresponds to f1,
// * fpr=1 to f2, etc.
// */
// char *overflow_arg_area;
// /* location on stack that holds
// * the next overflow argument
// */
// char *reg_save_area;
// /* where r3:r10 and f1:f8 (if saved)
// * are stored
// */
// } va_list[1];
_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris

_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-Chris