[llvm-commits] [llvm] r127349 - in /llvm/trunk: lib/Target/Mips/MipsISelLowering.cpp test/CodeGen/Mips/o32_cc_vararg.ll

Bruno Cardoso Lopes bruno.cardoso at gmail.com
Wed Mar 9 11:22:23 PST 2011


Author: bruno
Date: Wed Mar  9 13:22:22 2011
New Revision: 127349

URL: http://llvm.org/viewvc/llvm-project?rev=127349&view=rev
Log:
Improve varags handling, with testcases. Patch by Sasa Stankovic

Added:
    llvm/trunk/test/CodeGen/Mips/o32_cc_vararg.ll
Modified:
    llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp

Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp?rev=127349&r1=127348&r2=127349&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp Wed Mar  9 13:22:22 2011
@@ -149,6 +149,10 @@
 
   setOperationAction(ISD::EH_LABEL,          MVT::Other, Expand);
 
+  setOperationAction(ISD::VAARG,             MVT::Other, Expand);
+  setOperationAction(ISD::VACOPY,            MVT::Other, Expand);
+  setOperationAction(ISD::VAEND,             MVT::Other, Expand);
+
   // Use the default for now
   setOperationAction(ISD::STACKSAVE,         MVT::Other, Expand);
   setOperationAction(ISD::STACKRESTORE,      MVT::Other, Expand);
@@ -1283,7 +1287,6 @@
   MachineFrameInfo *MFI = MF.getFrameInfo();
   MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
 
-  unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF);
   MipsFI->setVarArgsFrameIndex(0);
 
   // Used with vargs to acumulate store chains.
@@ -1303,9 +1306,9 @@
   else
     CCInfo.AnalyzeFormalArguments(Ins, CC_Mips);
 
-  SDValue StackPtr;
-
   unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
+  unsigned LastStackArgEndOffset;
+  EVT LastRegArgValVT;
 
   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
     CCValAssign &VA = ArgLocs[i];
@@ -1314,6 +1317,7 @@
     if (VA.isRegLoc()) {
       EVT RegVT = VA.getLocVT();
       ArgRegEnd = VA.getLocReg();
+      LastRegArgValVT = VA.getValVT();
       TargetRegisterClass *RC = 0;
 
       if (RegVT == MVT::i32)
@@ -1354,7 +1358,8 @@
           unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(),
                                     VA.getLocReg()+1, RC);
           SDValue ArgValue2 = DAG.getCopyFromReg(Chain, dl, Reg2, RegVT);
-          SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, ArgValue2, ArgValue);
+          SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, ArgValue, 
+                                       ArgValue2);
           ArgValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Pair);
         }
       }
@@ -1375,10 +1380,10 @@
       // used instead of a direct negative address (which is recorded to
       // be used on emitPrologue) to avoid mis-calc of the first stack
       // offset on PEI::calculateFrameObjectOffsets.
-      // Arguments are always 32-bit.
-      unsigned ArgSize = VA.getLocVT().getSizeInBits()/8;
+      unsigned ArgSize = VA.getValVT().getSizeInBits()/8;
+      LastStackArgEndOffset = FirstStackArgLoc + VA.getLocMemOffset() + ArgSize;
       int FI = MFI->CreateFixedObject(ArgSize, 0, true);
-      MipsFI->recordLoadArgsFI(FI, -(ArgSize+
+      MipsFI->recordLoadArgsFI(FI, -(4 +
         (FirstStackArgLoc + VA.getLocMemOffset())));
 
       // Create load nodes to retrieve arguments from the stack
@@ -1405,29 +1410,52 @@
   // To meet ABI, when VARARGS are passed on registers, the registers
   // must have their values written to the caller stack frame. If the last
   // argument was placed in the stack, there's no need to save any register.
-  if ((isVarArg) && (Subtarget->isABI_O32() && ArgRegEnd)) {
-    if (StackPtr.getNode() == 0)
-      StackPtr = DAG.getRegister(StackReg, getPointerTy());
-
-    // The last register argument that must be saved is Mips::A3
-    TargetRegisterClass *RC = Mips::CPURegsRegisterClass;
-    unsigned StackLoc = ArgLocs.size()-1;
-
-    for (++ArgRegEnd; ArgRegEnd <= Mips::A3; ++ArgRegEnd, ++StackLoc) {
-      unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC);
-      SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32);
-
-      int FI = MFI->CreateFixedObject(4, 0, true);
-      MipsFI->recordStoreVarArgsFI(FI, -(4+(StackLoc*4)));
-      SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy());
-      OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff,
-                                       MachinePointerInfo(),
-                                       false, false, 0));
-
-      // Record the frame index of the first variable argument
-      // which is a value necessary to VASTART.
-      if (!MipsFI->getVarArgsFrameIndex())
+  if (isVarArg && Subtarget->isABI_O32()) {
+    if (ArgRegEnd) {
+      // Last named formal argument is passed in register.
+
+      // The last register argument that must be saved is Mips::A3
+      TargetRegisterClass *RC = Mips::CPURegsRegisterClass;
+      if (LastRegArgValVT == MVT::f64)
+        ArgRegEnd++;
+
+      if (ArgRegEnd < Mips::A3) {
+        // Both the last named formal argument and the first variable
+        // argument are passed in registers.
+        for (++ArgRegEnd; ArgRegEnd <= Mips::A3; ++ArgRegEnd) {
+          unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegEnd, RC);
+          SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, MVT::i32);
+
+          int FI = MFI->CreateFixedObject(4, 0, true);
+          MipsFI->recordStoreVarArgsFI(FI, -(4+(ArgRegEnd-Mips::A0)*4));
+          SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy());
+          OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff,
+                                           MachinePointerInfo(),
+                                           false, false, 0));
+
+          // Record the frame index of the first variable argument
+          // which is a value necessary to VASTART.
+          if (!MipsFI->getVarArgsFrameIndex()) {
+            MFI->setObjectAlignment(FI, 4);
+            MipsFI->setVarArgsFrameIndex(FI);
+          }
+        }
+      } else {
+        // Last named formal argument is in register Mips::A3, and the first
+        // variable argument is on stack. Record the frame index of the first
+        // variable argument.
+        int FI = MFI->CreateFixedObject(4, 0, true);
+        MFI->setObjectAlignment(FI, 4);
+        MipsFI->recordStoreVarArgsFI(FI, -20);
         MipsFI->setVarArgsFrameIndex(FI);
+      }
+    } else {
+      // Last named formal argument and all the variable arguments are passed
+      // on stack. Record the frame index of the first variable argument.
+      int FI = MFI->CreateFixedObject(4, 0, true);
+      MFI->setObjectAlignment(FI, 4);
+      MipsFI->recordStoreVarArgsFI(FI, -(4+LastStackArgEndOffset));
+      MipsFI->setVarArgsFrameIndex(FI);
     }
   }
 

Added: llvm/trunk/test/CodeGen/Mips/o32_cc_vararg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/o32_cc_vararg.ll?rev=127349&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/o32_cc_vararg.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/o32_cc_vararg.ll Wed Mar  9 13:22:22 2011
@@ -0,0 +1,277 @@
+; RUN: llc -march=mipsel -mcpu=mips2 < %s | FileCheck %s
+
+
+; All test functions do the same thing - they return the first variable
+; argument.
+
+; All CHECK's do the same thing - they check whether variable arguments from 
+; registers are placed on correct stack locations, and whether the first 
+; variable argument is returned from the correct stack location.
+
+
+declare void @llvm.va_start(i8*) nounwind
+declare void @llvm.va_end(i8*) nounwind
+
+; return int
+define i32 @va1(i32 %a, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %b = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, i32
+  store i32 %0, i32* %b, align 4
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load i32* %b, align 4
+  ret i32 %tmp
+
+; CHECK: va1:
+; CHECK: addiu   $sp, $sp, -32
+; CHECK: sw      $5, 36($sp)
+; CHECK: sw      $6, 40($sp)
+; CHECK: sw      $7, 44($sp)
+; CHECK: lw      $2, 36($sp)
+}
+
+; check whether the variable double argument will be accessed from the 8-byte 
+; aligned location (i.e. whether the address is computed by adding 7 and 
+; clearing lower 3 bits)
+define double @va2(i32 %a, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %b = alloca double, align 8
+  store i32 %a, i32* %a.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, double
+  store double %0, double* %b, align 8
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load double* %b, align 8
+  ret double %tmp
+
+; CHECK: va2:
+; CHECK: addiu   $sp, $sp, -40
+; CHECK: addiu   $2, $sp, 44
+; CHECK: sw      $5, 44($sp)
+; CHECK: sw      $6, 48($sp)
+; CHECK: sw      $7, 52($sp)
+; CHECK: addiu   $3, $2, 7
+; CHECK: addiu   $5, $zero, -8
+; CHECK: and     $3, $3, $5
+; CHECK: ldc1    $f0, 0($3)
+}
+
+; int
+define i32 @va3(double %a, ...) nounwind {
+entry:
+  %a.addr = alloca double, align 8
+  %ap = alloca i8*, align 4
+  %b = alloca i32, align 4
+  store double %a, double* %a.addr, align 8
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, i32
+  store i32 %0, i32* %b, align 4
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load i32* %b, align 4
+  ret i32 %tmp
+
+; CHECK: va3:
+; CHECK: addiu   $sp, $sp, -40
+; CHECK: sw      $6, 48($sp)
+; CHECK: sw      $7, 52($sp)
+; CHECK: lw      $2, 48($sp)
+}
+
+; double
+define double @va4(double %a, ...) nounwind {
+entry:
+  %a.addr = alloca double, align 8
+  %ap = alloca i8*, align 4
+  %b = alloca double, align 8
+  store double %a, double* %a.addr, align 8
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, double
+  store double %0, double* %b, align 8
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load double* %b, align 8
+  ret double %tmp
+
+; CHECK: va4:
+; CHECK: addiu   $sp, $sp, -48
+; CHECK: sw      $6, 56($sp)
+; CHECK: sw      $7, 60($sp)
+; CHECK: addiu   $3, $sp, 56
+; CHECK: addiu   $6, $3, 7
+; CHECK: addiu   $7, $zero, -8
+; CHECK: and     $2, $6, $7
+; CHECK: ldc1    $f0, 0($2)
+}
+
+; int
+define i32 @va5(i32 %a, i32 %b, i32 %c, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %c.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %d = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  store i32 %b, i32* %b.addr, align 4
+  store i32 %c, i32* %c.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, i32
+  store i32 %0, i32* %d, align 4
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load i32* %d, align 4
+  ret i32 %tmp
+
+; CHECK: va5:
+; CHECK: addiu   $sp, $sp, -40
+; CHECK: sw      $7, 52($sp)
+; CHECK: lw      $2, 52($sp)
+}
+
+; double
+define double @va6(i32 %a, i32 %b, i32 %c, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %c.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %d = alloca double, align 8
+  store i32 %a, i32* %a.addr, align 4
+  store i32 %b, i32* %b.addr, align 4
+  store i32 %c, i32* %c.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, double
+  store double %0, double* %d, align 8
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load double* %d, align 8
+  ret double %tmp
+
+; CHECK: va6:
+; CHECK: addiu   $sp, $sp, -48
+; CHECK: sw      $7, 60($sp)
+; CHECK: addiu   $2, $sp, 60
+; CHECK: addiu   $3, $2, 7
+; CHECK: addiu   $4, $zero, -8
+; CHECK: and     $3, $3, $4
+; CHECK: ldc1    $f0, 0($3)
+}
+
+; int
+define i32 @va7(i32 %a, double %b, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca double, align 8
+  %ap = alloca i8*, align 4
+  %c = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  store double %b, double* %b.addr, align 8
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, i32
+  store i32 %0, i32* %c, align 4
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load i32* %c, align 4
+  ret i32 %tmp
+
+; CHECK: va7:
+; CHECK: addiu   $sp, $sp, -40
+; CHECK: lw      $2, 56($sp)
+}
+
+; double
+define double @va8(i32 %a, double %b, ...) nounwind {
+entry:
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca double, align 8
+  %ap = alloca i8*, align 4
+  %c = alloca double, align 8
+  store i32 %a, i32* %a.addr, align 4
+  store double %b, double* %b.addr, align 8
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, double
+  store double %0, double* %c, align 8
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load double* %c, align 8
+  ret double %tmp
+
+; CHECK: va8:
+; CHECK: addiu   $sp, $sp, -48
+; CHECK: addiu   $3, $sp, 64
+; CHECK: addiu   $4, $3, 7
+; CHECK: addiu   $5, $zero, -8
+; CHECK: and     $2, $4, $5
+; CHECK: ldc1    $f0, 0($2)
+}
+
+; int
+define i32 @va9(double %a, double %b, i32 %c, ...) nounwind {
+entry:
+  %a.addr = alloca double, align 8
+  %b.addr = alloca double, align 8
+  %c.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %d = alloca i32, align 4
+  store double %a, double* %a.addr, align 8
+  store double %b, double* %b.addr, align 8
+  store i32 %c, i32* %c.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, i32
+  store i32 %0, i32* %d, align 4
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load i32* %d, align 4
+  ret i32 %tmp
+
+; CHECK: va9:
+; CHECK: addiu   $sp, $sp, -56
+; CHECK: lw      $2, 76($sp)
+}
+
+; double
+define double @va10(double %a, double %b, i32 %c, ...) nounwind {
+entry:
+  %a.addr = alloca double, align 8
+  %b.addr = alloca double, align 8
+  %c.addr = alloca i32, align 4
+  %ap = alloca i8*, align 4
+  %d = alloca double, align 8
+  store double %a, double* %a.addr, align 8
+  store double %b, double* %b.addr, align 8
+  store i32 %c, i32* %c.addr, align 4
+  %ap1 = bitcast i8** %ap to i8*
+  call void @llvm.va_start(i8* %ap1)
+  %0 = va_arg i8** %ap, double
+  store double %0, double* %d, align 8
+  %ap2 = bitcast i8** %ap to i8*
+  call void @llvm.va_end(i8* %ap2)
+  %tmp = load double* %d, align 8
+  ret double %tmp
+
+; CHECK: va10:
+; CHECK: addiu   $sp, $sp, -56
+; CHECK: addiu   $3, $sp, 76
+; CHECK: addiu   $2, $3, 7
+; CHECK: addiu   $4, $zero, -8
+; CHECK: and     $2, $2, $4
+; CHECK: ldc1    $f0, 0($2)
+}





More information about the llvm-commits mailing list