[llvm] r206370 - [mips] Add calling convention tests covering O32, N32, and N64.

Daniel Sanders daniel.sanders at imgtec.com
Wed Apr 16 02:59:47 PDT 2014


Author: dsanders
Date: Wed Apr 16 04:59:46 2014
New Revision: 206370

URL: http://llvm.org/viewvc/llvm-project?rev=206370&view=rev
Log:
[mips] Add calling convention tests covering O32, N32, and N64.

Summary:
I had difficulty finding tests for the N32 and N64 ABI so I've added a
collection of calling convention tests based on the document MIPS ABIs
Described (MD00305), the MIPSpro N32 Handbook, and the SYSV ABI. Where the
documents/implementations disagree, I've used GCC to resolve the conflict.

A few interesting details:
* For N32, LLVM uses 64-bit pointers when saving $ra despite pointers being
  32-bit. I've yet to find a supporting statement in the ABI documentation but
  the current behaviour matches GCC.

* For O32, the non-variable portion of a varargs argument list is also subject
  to the rule that floating-point is passed via GPR's (on N32/N64 only the
  variable portion is subject to this rule). This agrees with GCC's behaviour
  and the SYSV ABI but contradicts part of the MIPSpro N32 Handbook which talks about O32's behaviour.

* The N32 implementation has the wrong callee-saved register list.
  (I already have a fix for this but will commit it as a follow-up).

I've left RUN-TODO lines in for O32 on MIPS64. I don't plan to support this case
for now but we should revisit it.

Reviewers: matheusalmeida, vmedic

Reviewed By: matheusalmeida

Differential Revision: http://reviews.llvm.org/D3339

Added:
    llvm/trunk/test/CodeGen/Mips/cconv/
    llvm/trunk/test/CodeGen/Mips/cconv/arguments-float.ll
    llvm/trunk/test/CodeGen/Mips/cconv/arguments-fp128.ll
    llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float-varargs.ll
    llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float.ll
    llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-fp128.ll
    llvm/trunk/test/CodeGen/Mips/cconv/arguments.ll
    llvm/trunk/test/CodeGen/Mips/cconv/callee-saved-float.ll
    llvm/trunk/test/CodeGen/Mips/cconv/callee-saved.ll
    llvm/trunk/test/CodeGen/Mips/cconv/memory-layout.ll
    llvm/trunk/test/CodeGen/Mips/cconv/reserved-space.ll
    llvm/trunk/test/CodeGen/Mips/cconv/return-float.ll
    llvm/trunk/test/CodeGen/Mips/cconv/return-hard-float.ll
    llvm/trunk/test/CodeGen/Mips/cconv/return-hard-fp128.ll
    llvm/trunk/test/CodeGen/Mips/cconv/return.ll
    llvm/trunk/test/CodeGen/Mips/cconv/stack-alignment.ll

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments-float.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments-float.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments-float.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,222 @@
+; RUN: llc -march=mips -relocation-model=static -soft-float < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32BE %s
+; RUN: llc -march=mipsel -relocation-model=static -soft-float < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32LE %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -soft-float -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -soft-float -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -soft-float -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -soft-float -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+
+; RUN: llc -march=mips64 -relocation-model=static -soft-float -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -soft-float -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+
+; Test the floating point arguments for all ABI's and byte orders as specified
+; by section 5 of MD00305 (MIPS ABIs Described).
+;
+; N32/N64 are identical in this area so their checks have been combined into
+; the 'NEW' prefix (the N stands for New).
+
+ at bytes = global [11 x i8] zeroinitializer
+ at dwords = global [11 x i64] zeroinitializer
+ at floats = global [11 x float] zeroinitializer
+ at doubles = global [11 x double] zeroinitializer
+
+define void @double_args(double %a, double %b, double %c, double %d, double %e,
+                         double %f, double %g, double %h, double %i) nounwind {
+entry:
+        %0 = getelementptr [11 x double]* @doubles, i32 0, i32 1
+        store volatile double %a, double* %0
+        %1 = getelementptr [11 x double]* @doubles, i32 0, i32 2
+        store volatile double %b, double* %1
+        %2 = getelementptr [11 x double]* @doubles, i32 0, i32 3
+        store volatile double %c, double* %2
+        %3 = getelementptr [11 x double]* @doubles, i32 0, i32 4
+        store volatile double %d, double* %3
+        %4 = getelementptr [11 x double]* @doubles, i32 0, i32 5
+        store volatile double %e, double* %4
+        %5 = getelementptr [11 x double]* @doubles, i32 0, i32 6
+        store volatile double %f, double* %5
+        %6 = getelementptr [11 x double]* @doubles, i32 0, i32 7
+        store volatile double %g, double* %6
+        %7 = getelementptr [11 x double]* @doubles, i32 0, i32 8
+        store volatile double %h, double* %7
+        %8 = getelementptr [11 x double]* @doubles, i32 0, i32 9
+        store volatile double %i, double* %8
+        ret void
+}
+
+; ALL-LABEL: double_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(doubles)(
+
+; The first four arguments are the same in O32/N32/N64.
+; The first argument is floating point but soft-float is enabled so floating
+; point registers are not used.
+; O32-DAG:           sw $4, 8([[R2]])
+; O32-DAG:           sw $5, 12([[R2]])
+; NEW-DAG:           sd $4, 8([[R2]])
+
+; O32-DAG:           sw $6, 16([[R2]])
+; O32-DAG:           sw $7, 20([[R2]])
+; NEW-DAG:           sd $5, 16([[R2]])
+
+; O32 has run out of argument registers and starts using the stack
+; O32-DAG:           lw [[R3:\$([0-9]+|gp)]], 24($sp)
+; O32-DAG:           lw [[R4:\$([0-9]+|gp)]], 28($sp)
+; O32-DAG:           sw [[R3]], 24([[R2]])
+; O32-DAG:           sw [[R4]], 28([[R2]])
+; NEW-DAG:           sd $6, 24([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 32($sp)
+; O32-DAG:           lw [[R4:\$[0-9]+]], 36($sp)
+; O32-DAG:           sw [[R3]], 32([[R2]])
+; O32-DAG:           sw [[R4]], 36([[R2]])
+; NEW-DAG:           sd $7, 32([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 40($sp)
+; O32-DAG:           lw [[R4:\$[0-9]+]], 44($sp)
+; O32-DAG:           sw [[R3]], 40([[R2]])
+; O32-DAG:           sw [[R4]], 44([[R2]])
+; NEW-DAG:           sd $8, 40([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 48($sp)
+; O32-DAG:           lw [[R4:\$[0-9]+]], 52($sp)
+; O32-DAG:           sw [[R3]], 48([[R2]])
+; O32-DAG:           sw [[R4]], 52([[R2]])
+; NEW-DAG:           sd $9, 48([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 56($sp)
+; O32-DAG:           lw [[R4:\$[0-9]+]], 60($sp)
+; O32-DAG:           sw [[R3]], 56([[R2]])
+; O32-DAG:           sw [[R4]], 60([[R2]])
+; NEW-DAG:           sd $10, 56([[R2]])
+
+; N32/N64 have run out of registers and starts using the stack too
+; O32-DAG:           lw [[R3:\$[0-9]+]], 64($sp)
+; O32-DAG:           lw [[R4:\$[0-9]+]], 68($sp)
+; O32-DAG:           sw [[R3]], 64([[R2]])
+; O32-DAG:           sw [[R4]], 68([[R2]])
+; NEW-DAG:           ld [[R3:\$[0-9]+]], 0($sp)
+; NEW-DAG:           sd $11, 64([[R2]])
+
+define void @float_args(float %a, float %b, float %c, float %d, float %e,
+                        float %f, float %g, float %h, float %i, float %j)
+                       nounwind {
+entry:
+        %0 = getelementptr [11 x float]* @floats, i32 0, i32 1
+        store volatile float %a, float* %0
+        %1 = getelementptr [11 x float]* @floats, i32 0, i32 2
+        store volatile float %b, float* %1
+        %2 = getelementptr [11 x float]* @floats, i32 0, i32 3
+        store volatile float %c, float* %2
+        %3 = getelementptr [11 x float]* @floats, i32 0, i32 4
+        store volatile float %d, float* %3
+        %4 = getelementptr [11 x float]* @floats, i32 0, i32 5
+        store volatile float %e, float* %4
+        %5 = getelementptr [11 x float]* @floats, i32 0, i32 6
+        store volatile float %f, float* %5
+        %6 = getelementptr [11 x float]* @floats, i32 0, i32 7
+        store volatile float %g, float* %6
+        %7 = getelementptr [11 x float]* @floats, i32 0, i32 8
+        store volatile float %h, float* %7
+        %8 = getelementptr [11 x float]* @floats, i32 0, i32 9
+        store volatile float %i, float* %8
+        %9 = getelementptr [11 x float]* @floats, i32 0, i32 10
+        store volatile float %j, float* %9
+        ret void
+}
+
+; ALL-LABEL: float_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(floats)(
+
+; The first four arguments are the same in O32/N32/N64.
+; The first argument isn't floating point so floating point registers are not
+; used.
+; MD00305 and GCC disagree on this one. MD00305 says that floats are treated
+; as 8-byte aligned and occupy two slots on O32. GCC is treating them as 4-byte
+; aligned and occupying one slot. We'll use GCC's definition.
+; ALL-DAG:           sw $4, 4([[R2]])
+; ALL-DAG:           sw $5, 8([[R2]])
+; ALL-DAG:           sw $6, 12([[R2]])
+; ALL-DAG:           sw $7, 16([[R2]])
+
+; O32 has run out of argument registers and starts using the stack
+; O32-DAG:           lw [[R3:\$[0-9]+]], 16($sp)
+; O32-DAG:           sw [[R3]], 20([[R2]])
+; NEW-DAG:           sw $8, 20([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 20($sp)
+; O32-DAG:           sw [[R3]], 24([[R2]])
+; NEW-DAG:           sw $9, 24([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 24($sp)
+; O32-DAG:           sw [[R3]], 28([[R2]])
+; NEW-DAG:           sw $10, 28([[R2]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 28($sp)
+; O32-DAG:           sw [[R3]], 32([[R2]])
+; NEW-DAG:           sw $11, 32([[R2]])
+
+; N32/N64 have run out of registers and start using the stack too
+; O32-DAG:           lw [[R3:\$[0-9]+]], 32($sp)
+; O32-DAG:           sw [[R3]], 36([[R2]])
+; NEW-DAG:           lw [[R3:\$[0-9]+]], 0($sp)
+; NEW-DAG:           sw [[R3]], 36([[R2]])
+
+define void @double_arg2(i8 %a, double %b) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x double]* @doubles, i32 0, i32 1
+        store volatile double %b, double* %1
+        ret void
+}
+
+; ALL-LABEL: double_arg2:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(doubles)(
+
+; The first four arguments are the same in O32/N32/N64.
+; The first argument isn't floating point so floating point registers are not
+; used.
+; The second slot is insufficiently aligned for double on O32 so it is skipped.
+; Also, double occupies two slots on O32 and only one for N32/N64.
+; ALL-DAG:           sb $4, 1([[R1]])
+; O32-DAG:           sw $6, 8([[R2]])
+; O32-DAG:           sw $7, 12([[R2]])
+; NEW-DAG:           sd $5, 8([[R2]])
+
+define void @float_arg2(i8 %a, float %b) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x float]* @floats, i32 0, i32 1
+        store volatile float %b, float* %1
+        ret void
+}
+
+; ALL-LABEL: float_arg2:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(floats)(
+
+; The first four arguments are the same in O32/N32/N64.
+; The first argument isn't floating point so floating point registers are not
+; used.
+; MD00305 and GCC disagree on this one. MD00305 says that floats are treated
+; as 8-byte aligned and occupy two slots on O32. GCC is treating them as 4-byte
+; aligned and occupying one slot. We'll use GCC's definition.
+; ALL-DAG:           sb $4, 1([[R1]])
+; ALL-DAG:           sw $5, 4([[R2]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments-fp128.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments-fp128.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments-fp128.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments-fp128.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,51 @@
+; RUN: llc -march=mips64 -relocation-model=static -soft-float -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 %s
+; RUN: llc -march=mips64el -relocation-model=static -soft-float -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -soft-float -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 %s
+; RUN: llc -march=mips64el -relocation-model=static -soft-float -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 %s
+
+; Test the fp128 arguments for all ABI's and byte orders as specified
+; by section 2 of the MIPSpro N32 Handbook.
+;
+; O32 is not tested because long double is the same as double on O32.
+
+ at ldoubles = global [11 x fp128] zeroinitializer
+
+define void @ldouble_args(fp128 %a, fp128 %b, fp128 %c, fp128 %d, fp128 %e) nounwind {
+entry:
+        %0 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 1
+        store volatile fp128 %a, fp128* %0
+        %1 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 2
+        store volatile fp128 %b, fp128* %1
+        %2 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 3
+        store volatile fp128 %c, fp128* %2
+        %3 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 4
+        store volatile fp128 %d, fp128* %3
+        %4 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 5
+        store volatile fp128 %e, fp128* %4
+        ret void
+}
+
+; ALL-LABEL: ldouble_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(ldoubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(ldoubles)(
+
+; The first four arguments are the same in N32/N64.
+; The first argument is floating point but soft-float is enabled so floating
+; point registers are not used.
+; ALL-DAG:           sd $4, 16([[R2]])
+; ALL-DAG:           sd $5, 24([[R2]])
+; ALL-DAG:           sd $6, 32([[R2]])
+; ALL-DAG:           sd $7, 40([[R2]])
+; ALL-DAG:           sd $8, 48([[R2]])
+; ALL-DAG:           sd $9, 56([[R2]])
+; ALL-DAG:           sd $10, 64([[R2]])
+; ALL-DAG:           sd $11, 72([[R2]])
+
+; N32/N64 have run out of registers and starts using the stack too
+; ALL-DAG:           ld [[R3:\$[0-9]+]], 0($sp)
+; ALL-DAG:           ld [[R4:\$[0-9]+]], 8($sp)
+; ALL-DAG:           sd [[R3]], 80([[R2]])
+; ALL-DAG:           sd [[R4]], 88([[R2]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float-varargs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float-varargs.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float-varargs.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float-varargs.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,157 @@
+; RUN: llc -march=mips -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32BE %s
+; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32LE %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=N32 --check-prefix=NEW %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=N64 --check-prefix=NEW %s
+
+; Test the effect of varargs on floating point types in the non-variable part
+; of the argument list as specified by section 2 of the MIPSpro N32 Handbook.
+;
+; N32/N64 are almost identical in this area so many of their checks have been
+; combined into the 'NEW' prefix (the N stands for New).
+;
+; On O32, varargs prevents all FPU argument register usage. This contradicts
+; the N32 handbook, but agrees with the SYSV ABI and GCC's behaviour.
+
+ at floats = global [11 x float] zeroinitializer
+ at doubles = global [11 x double] zeroinitializer
+
+define void @double_args(double %a, ...)
+                         nounwind {
+entry:
+        %0 = getelementptr [11 x double]* @doubles, i32 0, i32 1
+        store volatile double %a, double* %0
+
+        %ap = alloca i8*
+        %ap2 = bitcast i8** %ap to i8*
+        call void @llvm.va_start(i8* %ap2)
+        %b = va_arg i8** %ap, double
+        %1 = getelementptr [11 x double]* @doubles, i32 0, i32 2
+        store volatile double %b, double* %1
+        ret void
+}
+
+; ALL-LABEL: double_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:         addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
+; SYM64-DAG:         ld [[R2:\$[0-9]]], %got_disp(doubles)(
+
+; O32 forbids using floating point registers for the non-variable portion.
+; N32/N64 allow it.
+; O32BE-DAG:         mtc1 $5, [[FTMP1:\$f[0-9]*[02468]+]]
+; O32BE-DAG:         mtc1 $4, [[FTMP2:\$f[0-9]*[13579]+]]
+; O32LE-DAG:         mtc1 $4, [[FTMP1:\$f[0-9]*[02468]+]]
+; O32LE-DAG:         mtc1 $5, [[FTMP2:\$f[0-9]*[13579]+]]
+; O32-DAG:           sdc1 [[FTMP1]], 8([[R2]])
+; NEW-DAG:           sdc1 $f12, 8([[R2]])
+
+; The varargs portion is dumped to stack
+; O32-DAG:           sw $6, 16($sp)
+; O32-DAG:           sw $7, 20($sp)
+; NEW-DAG:           sd $5, 8($sp)
+; NEW-DAG:           sd $6, 16($sp)
+; NEW-DAG:           sd $7, 24($sp)
+; NEW-DAG:           sd $8, 32($sp)
+; NEW-DAG:           sd $9, 40($sp)
+; NEW-DAG:           sd $10, 48($sp)
+; NEW-DAG:           sd $11, 56($sp)
+
+; Get the varargs pointer
+; O32 has 4 bytes padding, 4 bytes for the varargs pointer, and 8 bytes reserved
+; for arguments 1 and 2.
+; N32/N64 has 8 bytes for the varargs pointer, and no reserved area.
+; O32-DAG:           addiu [[VAPTR:\$[0-9]+]], $sp, 16
+; O32-DAG:           sw [[VAPTR]], 4($sp)
+; N32-DAG:           addiu [[VAPTR:\$[0-9]+]], $sp, 8
+; N32-DAG:           sw [[VAPTR]], 4($sp)
+; N64-DAG:           daddiu [[VAPTR:\$[0-9]+]], $sp, 8
+; N64-DAG:           sd [[VAPTR]], 0($sp)
+
+; Increment the pointer then get the varargs arg
+; LLVM will rebind the load to the stack pointer instead of the varargs pointer
+; during lowering. This is fine and doesn't change the behaviour.
+; O32-DAG:           addiu [[VAPTR]], [[VAPTR]], 8
+; O32-DAG:           sw [[VAPTR]], 4($sp)
+; N32-DAG:           addiu [[VAPTR]], [[VAPTR]], 8
+; N32-DAG:           sw [[VAPTR]], 4($sp)
+; N64-DAG:           daddiu [[VAPTR]], [[VAPTR]], 8
+; N64-DAG:           sd [[VAPTR]], 0($sp)
+; O32-DAG:           ldc1 [[FTMP1:\$f[0-9]+]], 16($sp)
+; NEW-DAG:           ldc1 [[FTMP1:\$f[0-9]+]], 8($sp)
+; ALL-DAG:           sdc1 [[FTMP1]], 16([[R2]])
+
+define void @float_args(float %a, ...) nounwind {
+entry:
+        %0 = getelementptr [11 x float]* @floats, i32 0, i32 1
+        store volatile float %a, float* %0
+
+        %ap = alloca i8*
+        %ap2 = bitcast i8** %ap to i8*
+        call void @llvm.va_start(i8* %ap2)
+        %b = va_arg i8** %ap, float
+        %1 = getelementptr [11 x float]* @floats, i32 0, i32 2
+        store volatile float %b, float* %1
+        ret void
+}
+
+; ALL-LABEL: float_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:         addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
+; SYM64-DAG:         ld [[R2:\$[0-9]]], %got_disp(floats)(
+
+; The first four arguments are the same in O32/N32/N64.
+; The non-variable portion should be unaffected.
+; O32-DAG:           sw $4, 4([[R2]])
+; NEW-DAG:           swc1 $f12, 4([[R2]])
+
+; The varargs portion is dumped to stack
+; O32-DAG:           sw $5, 12($sp)
+; O32-DAG:           sw $6, 16($sp)
+; O32-DAG:           sw $7, 20($sp)
+; NEW-DAG:           sd $5, 8($sp)
+; NEW-DAG:           sd $6, 16($sp)
+; NEW-DAG:           sd $7, 24($sp)
+; NEW-DAG:           sd $8, 32($sp)
+; NEW-DAG:           sd $9, 40($sp)
+; NEW-DAG:           sd $10, 48($sp)
+; NEW-DAG:           sd $11, 56($sp)
+
+; Get the varargs pointer
+; O32 has 4 bytes padding, 4 bytes for the varargs pointer, and should have 8
+; bytes reserved for arguments 1 and 2 (the first float arg) but as discussed in
+; arguments-float.ll, GCC doesn't agree with MD00305 and treats floats as 4
+; bytes so we only have 12 bytes total.
+; N32/N64 has 8 bytes for the varargs pointer, and no reserved area.
+; O32-DAG:           addiu [[VAPTR:\$[0-9]+]], $sp, 12
+; O32-DAG:           sw [[VAPTR]], 4($sp)
+; N32-DAG:           addiu [[VAPTR:\$[0-9]+]], $sp, 8
+; N32-DAG:           sw [[VAPTR]], 4($sp)
+; N64-DAG:           daddiu [[VAPTR:\$[0-9]+]], $sp, 8
+; N64-DAG:           sd [[VAPTR]], 0($sp)
+
+; Increment the pointer then get the varargs arg
+; LLVM will rebind the load to the stack pointer instead of the varargs pointer
+; during lowering. This is fine and doesn't change the behaviour.
+; N32/N64 is using ori instead of addiu/daddiu but (although odd) this is fine
+; since the stack is always aligned.
+; O32-DAG:           addiu [[VAPTR]], [[VAPTR]], 4
+; O32-DAG:           sw [[VAPTR]], 4($sp)
+; N32-DAG:           ori [[VAPTR]], [[VAPTR]], 4
+; N32-DAG:           sw [[VAPTR]], 4($sp)
+; N64-DAG:           ori [[VAPTR]], [[VAPTR]], 4
+; N64-DAG:           sd [[VAPTR]], 0($sp)
+; O32-DAG:           lwc1 [[FTMP1:\$f[0-9]+]], 12($sp)
+; NEW-DAG:           lwc1 [[FTMP1:\$f[0-9]+]], 8($sp)
+; ALL-DAG:           swc1 [[FTMP1]], 8([[R2]])
+
+declare void @llvm.va_start(i8*)
+declare void @llvm.va_copy(i8*, i8*)
+declare void @llvm.va_end(i8*)

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-float.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,211 @@
+; RUN: llc -march=mips -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32BE %s
+; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32LE %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+
+; Test the floating point arguments for all ABI's and byte orders as specified
+; by section 5 of MD00305 (MIPS ABIs Described).
+;
+; N32/N64 are identical in this area so their checks have been combined into
+; the 'NEW' prefix (the N stands for New).
+
+ at bytes = global [11 x i8] zeroinitializer
+ at dwords = global [11 x i64] zeroinitializer
+ at floats = global [11 x float] zeroinitializer
+ at doubles = global [11 x double] zeroinitializer
+
+define void @double_args(double %a, double %b, double %c, double %d, double %e,
+                         double %f, double %g, double %h, double %i) nounwind {
+entry:
+        %0 = getelementptr [11 x double]* @doubles, i32 0, i32 1
+        store volatile double %a, double* %0
+        %1 = getelementptr [11 x double]* @doubles, i32 0, i32 2
+        store volatile double %b, double* %1
+        %2 = getelementptr [11 x double]* @doubles, i32 0, i32 3
+        store volatile double %c, double* %2
+        %3 = getelementptr [11 x double]* @doubles, i32 0, i32 4
+        store volatile double %d, double* %3
+        %4 = getelementptr [11 x double]* @doubles, i32 0, i32 5
+        store volatile double %e, double* %4
+        %5 = getelementptr [11 x double]* @doubles, i32 0, i32 6
+        store volatile double %f, double* %5
+        %6 = getelementptr [11 x double]* @doubles, i32 0, i32 7
+        store volatile double %g, double* %6
+        %7 = getelementptr [11 x double]* @doubles, i32 0, i32 8
+        store volatile double %h, double* %7
+        %8 = getelementptr [11 x double]* @doubles, i32 0, i32 9
+        store volatile double %i, double* %8
+        ret void
+}
+
+; ALL-LABEL: double_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(doubles)(
+
+; The first argument is floating point so floating point registers are used.
+; The first argument is the same for O32/N32/N64 but the second argument differs
+; by register
+; ALL-DAG:           sdc1 $f12, 8([[R2]])
+; O32-DAG:           sdc1 $f14, 16([[R2]])
+; NEW-DAG:           sdc1 $f13, 16([[R2]])
+
+; O32 has run out of argument registers and starts using the stack
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 16($sp)
+; O32-DAG:           sdc1 [[F1]], 24([[R2]])
+; NEW-DAG:           sdc1 $f14, 24([[R2]])
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 24($sp)
+; O32-DAG:           sdc1 [[F1]], 32([[R2]])
+; NEW-DAG:           sdc1 $f15, 32([[R2]])
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 32($sp)
+; O32-DAG:           sdc1 [[F1]], 40([[R2]])
+; NEW-DAG:           sdc1 $f16, 40([[R2]])
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 40($sp)
+; O32-DAG:           sdc1 [[F1]], 48([[R2]])
+; NEW-DAG:           sdc1 $f17, 48([[R2]])
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 48($sp)
+; O32-DAG:           sdc1 [[F1]], 56([[R2]])
+; NEW-DAG:           sdc1 $f18, 56([[R2]])
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 56($sp)
+; O32-DAG:           sdc1 [[F1]], 64([[R2]])
+; NEW-DAG:           sdc1 $f19, 64([[R2]])
+
+; N32/N64 have run out of registers and start using the stack too
+; O32-DAG:           ldc1 [[F1:\$f[0-9]+]], 64($sp)
+; O32-DAG:           sdc1 [[F1]], 72([[R2]])
+; NEW-DAG:           ldc1 [[F1:\$f[0-9]+]], 0($sp)
+; NEW-DAG:           sdc1 [[F1]], 72([[R2]])
+
+define void @float_args(float %a, float %b, float %c, float %d, float %e,
+                        float %f, float %g, float %h, float %i) nounwind {
+entry:
+        %0 = getelementptr [11 x float]* @floats, i32 0, i32 1
+        store volatile float %a, float* %0
+        %1 = getelementptr [11 x float]* @floats, i32 0, i32 2
+        store volatile float %b, float* %1
+        %2 = getelementptr [11 x float]* @floats, i32 0, i32 3
+        store volatile float %c, float* %2
+        %3 = getelementptr [11 x float]* @floats, i32 0, i32 4
+        store volatile float %d, float* %3
+        %4 = getelementptr [11 x float]* @floats, i32 0, i32 5
+        store volatile float %e, float* %4
+        %5 = getelementptr [11 x float]* @floats, i32 0, i32 6
+        store volatile float %f, float* %5
+        %6 = getelementptr [11 x float]* @floats, i32 0, i32 7
+        store volatile float %g, float* %6
+        %7 = getelementptr [11 x float]* @floats, i32 0, i32 8
+        store volatile float %h, float* %7
+        %8 = getelementptr [11 x float]* @floats, i32 0, i32 9
+        store volatile float %i, float* %8
+        ret void
+}
+
+; ALL-LABEL: float_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(floats)(
+
+; The first argument is floating point so floating point registers are used.
+; The first argument is the same for O32/N32/N64 but the second argument differs
+; by register
+; ALL-DAG:           swc1 $f12, 4([[R1]])
+; O32-DAG:           swc1 $f14, 8([[R1]])
+; NEW-DAG:           swc1 $f13, 8([[R1]])
+
+; O32 has run out of argument registers and (in theory) starts using the stack
+; I've yet to find a reference in the documentation about this but GCC uses up
+; the remaining two argument slots in the GPR's first. We'll do the same for
+; compatibility.
+; O32-DAG:           sw $6, 12([[R1]])
+; NEW-DAG:           swc1 $f14, 12([[R1]])
+; O32-DAG:           sw $7, 16([[R1]])
+; NEW-DAG:           swc1 $f15, 16([[R1]])
+
+; O32 is definitely out of registers now and switches to the stack.
+; O32-DAG:           lwc1 [[F1:\$f[0-9]+]], 16($sp)
+; O32-DAG:           swc1 [[F1]], 20([[R1]])
+; NEW-DAG:           swc1 $f16, 20([[R1]])
+; O32-DAG:           lwc1 [[F1:\$f[0-9]+]], 20($sp)
+; O32-DAG:           swc1 [[F1]], 24([[R1]])
+; NEW-DAG:           swc1 $f17, 24([[R1]])
+; O32-DAG:           lwc1 [[F1:\$f[0-9]+]], 24($sp)
+; O32-DAG:           swc1 [[F1]], 28([[R1]])
+; NEW-DAG:           swc1 $f18, 28([[R1]])
+; O32-DAG:           lwc1 [[F1:\$f[0-9]+]], 28($sp)
+; O32-DAG:           swc1 [[F1]], 32([[R1]])
+; NEW-DAG:           swc1 $f19, 32([[R1]])
+
+; N32/N64 have run out of registers and start using the stack too
+; O32-DAG:           lwc1 [[F1:\$f[0-9]+]], 32($sp)
+; O32-DAG:           swc1 [[F1]], 36([[R1]])
+; NEW-DAG:           lwc1 [[F1:\$f[0-9]+]], 0($sp)
+; NEW-DAG:           swc1 [[F1]], 36([[R1]])
+
+
+define void @double_arg2(i8 %a, double %b) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x double]* @doubles, i32 0, i32 1
+        store volatile double %b, double* %1
+        ret void
+}
+
+; ALL-LABEL: double_arg2:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(doubles)(
+
+; The first argument is the same in O32/N32/N64.
+; ALL-DAG:           sb $4, 1([[R1]])
+
+; The first argument isn't floating point so floating point registers are not
+; used in O32, but N32/N64 will still use them.
+; The second slot is insufficiently aligned for double on O32 so it is skipped.
+; Also, double occupies two slots on O32 and only one for N32/N64.
+; O32LE-DAG:           mtc1 $6, [[F1:\$f[0-9]*[02468]+]]
+; O32LE-DAG:           mtc1 $7, [[F2:\$f[0-9]*[13579]+]]
+; O32BE-DAG:           mtc1 $6, [[F2:\$f[0-9]*[13579]+]]
+; O32BE-DAG:           mtc1 $7, [[F1:\$f[0-9]*[02468]+]]
+; O32-DAG:           sdc1 [[F1]], 8([[R2]])
+; NEW-DAG:           sdc1 $f13, 8([[R2]])
+
+define void @float_arg2(i8 %a, float %b) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x float]* @floats, i32 0, i32 1
+        store volatile float %b, float* %1
+        ret void
+}
+
+; ALL-LABEL: float_arg2:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(floats)(
+
+; The first argument is the same in O32/N32/N64.
+; ALL-DAG:           sb $4, 1([[R1]])
+
+; The first argument isn't floating point so floating point registers are not
+; used in O32, but N32/N64 will still use them.
+; MD00305 and GCC disagree on this one. MD00305 says that floats are treated
+; as 8-byte aligned and occupy two slots on O32. GCC is treating them as 4-byte
+; aligned and occupying one slot. We'll use GCC's definition.
+; O32-DAG:           sw $5, 4([[R2]])
+; NEW-DAG:           swc1 $f13, 4([[R2]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-fp128.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-fp128.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-fp128.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments-hard-fp128.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,49 @@
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 %s
+
+; Test the fp128 arguments for all ABI's and byte orders as specified
+; by section 2 of the MIPSpro N32 Handbook.
+;
+; O32 is not tested because long double is the same as double on O32.
+
+ at ldoubles = global [11 x fp128] zeroinitializer
+
+define void @ldouble_args(fp128 %a, fp128 %b, fp128 %c, fp128 %d, fp128 %e) nounwind {
+entry:
+        %0 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 1
+        store volatile fp128 %a, fp128* %0
+        %1 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 2
+        store volatile fp128 %b, fp128* %1
+        %2 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 3
+        store volatile fp128 %c, fp128* %2
+        %3 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 4
+        store volatile fp128 %d, fp128* %3
+        %4 = getelementptr [11 x fp128]* @ldoubles, i32 0, i32 5
+        store volatile fp128 %e, fp128* %4
+        ret void
+}
+
+; ALL-LABEL: ldouble_args:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(ldoubles)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(ldoubles)(
+
+; The first four arguments are the same in N32/N64.
+; ALL-DAG:           sdc1 $f12, 16([[R2]])
+; ALL-DAG:           sdc1 $f13, 24([[R2]])
+; ALL-DAG:           sdc1 $f14, 32([[R2]])
+; ALL-DAG:           sdc1 $f15, 40([[R2]])
+; ALL-DAG:           sdc1 $f16, 48([[R2]])
+; ALL-DAG:           sdc1 $f17, 56([[R2]])
+; ALL-DAG:           sdc1 $f18, 64([[R2]])
+; ALL-DAG:           sdc1 $f19, 72([[R2]])
+
+; N32/N64 have run out of registers and starts using the stack too
+; ALL-DAG:           ld [[R3:\$[0-9]+]], 0($sp)
+; ALL-DAG:           ld [[R4:\$[0-9]+]], 8($sp)
+; ALL-DAG:           sd [[R3]], 80([[R2]])
+; ALL-DAG:           sd [[R4]], 88([[R2]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/arguments.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/arguments.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/arguments.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/arguments.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,170 @@
+; RUN: llc -march=mips -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32BE %s
+; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 --check-prefix=O32LE %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM32 --check-prefix=NEW %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=SYM64 --check-prefix=NEW %s
+
+; Test the integer arguments for all ABI's and byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+;
+; N32/N64 are identical in this area so their checks have been combined into
+; the 'NEW' prefix (the N stands for New).
+;
+; Varargs are covered in arguments-hard-float-varargs.ll.
+
+ at bytes = global [11 x i8] zeroinitializer
+ at dwords = global [11 x i64] zeroinitializer
+ at floats = global [11 x float] zeroinitializer
+ at doubles = global [11 x double] zeroinitializer
+
+define void @align_to_arg_slots(i8 %a, i8 %b, i8 %c, i8 %d, i8 %e, i8 %f, i8 %g,
+                                i8 %h, i8 %i, i8 %j) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x i8]* @bytes, i32 0, i32 2
+        store volatile i8 %b, i8* %1
+        %2 = getelementptr [11 x i8]* @bytes, i32 0, i32 3
+        store volatile i8 %c, i8* %2
+        %3 = getelementptr [11 x i8]* @bytes, i32 0, i32 4
+        store volatile i8 %d, i8* %3
+        %4 = getelementptr [11 x i8]* @bytes, i32 0, i32 5
+        store volatile i8 %e, i8* %4
+        %5 = getelementptr [11 x i8]* @bytes, i32 0, i32 6
+        store volatile i8 %f, i8* %5
+        %6 = getelementptr [11 x i8]* @bytes, i32 0, i32 7
+        store volatile i8 %g, i8* %6
+        %7 = getelementptr [11 x i8]* @bytes, i32 0, i32 8
+        store volatile i8 %h, i8* %7
+        %8 = getelementptr [11 x i8]* @bytes, i32 0, i32 9
+        store volatile i8 %i, i8* %8
+        %9 = getelementptr [11 x i8]* @bytes, i32 0, i32 10
+        store volatile i8 %j, i8* %9
+        ret void
+}
+
+; ALL-LABEL: align_to_arg_slots:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+
+; The first four arguments are the same in O32/N32/N64
+; ALL-DAG:           sb $4, 1([[R1]])
+; ALL-DAG:           sb $5, 2([[R1]])
+; ALL-DAG:           sb $6, 3([[R1]])
+; ALL-DAG:           sb $7, 4([[R1]])
+
+; N32/N64 get an extra four arguments in registers
+; O32 starts loading from the stack. The addresses start at 16 because space is
+; always reserved for the first four arguments.
+; O32-DAG:           lw [[R3:\$[0-9]+]], 16($sp)
+; O32-DAG:           sb [[R3]], 5([[R1]])
+; NEW-DAG:           sb $8, 5([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 20($sp)
+; O32-DAG:           sb [[R3]], 6([[R1]])
+; NEW-DAG:           sb $9, 6([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 24($sp)
+; O32-DAG:           sb [[R3]], 7([[R1]])
+; NEW-DAG:           sb $10, 7([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 28($sp)
+; O32-DAG:           sb [[R3]], 8([[R1]])
+; NEW-DAG:           sb $11, 8([[R1]])
+
+; O32/N32/N64 are accessing the stack at this point.
+; Unlike O32, N32/N64 do not reserve space for the arguments.
+; increase by 4 for O32 and 8 for N32/N64.
+; O32-DAG:           lw [[R3:\$[0-9]+]], 32($sp)
+; O32-DAG:           sb [[R3]], 9([[R1]])
+; NEW-DAG:           lw [[R3:\$[0-9]+]], 0($sp)
+; NEW-DAG:           sb [[R3]], 9([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 36($sp)
+; O32-DAG:           sb [[R3]], 10([[R1]])
+; NEW-DAG:           lw [[R3:\$[0-9]+]], 8($sp)
+; NEW-DAG:           sb [[R3]], 10([[R1]])
+
+define void @slot_skipping(i8 %a, i64 %b, i8 %c, i8 %d,
+                           i8 %e, i8 %f, i8 %g, i64 %i, i8 %j) nounwind {
+entry:
+        %0 = getelementptr [11 x i8]* @bytes, i32 0, i32 1
+        store volatile i8 %a, i8* %0
+        %1 = getelementptr [11 x i64]* @dwords, i32 0, i32 1
+        store volatile i64 %b, i64* %1
+        %2 = getelementptr [11 x i8]* @bytes, i32 0, i32 2
+        store volatile i8 %c, i8* %2
+        %3 = getelementptr [11 x i8]* @bytes, i32 0, i32 3
+        store volatile i8 %d, i8* %3
+        %4 = getelementptr [11 x i8]* @bytes, i32 0, i32 4
+        store volatile i8 %e, i8* %4
+        %5 = getelementptr [11 x i8]* @bytes, i32 0, i32 5
+        store volatile i8 %f, i8* %5
+        %6 = getelementptr [11 x i8]* @bytes, i32 0, i32 6
+        store volatile i8 %g, i8* %6
+        %7 = getelementptr [11 x i64]* @dwords, i32 0, i32 2
+        store volatile i64 %i, i64* %7
+        %8 = getelementptr [11 x i8]* @bytes, i32 0, i32 7
+        store volatile i8 %j, i8* %8
+        ret void
+}
+
+; ALL-LABEL: slot_skipping:
+; We won't test the way the global address is calculated in this test. This is
+; just to get the register number for the other checks.
+; SYM32-DAG:           addiu [[R1:\$[0-9]+]], ${{[0-9]+}}, %lo(bytes)
+; SYM64-DAG:           ld [[R1:\$[0-9]]], %got_disp(bytes)(
+; SYM32-DAG:           addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(dwords)
+; SYM64-DAG:           ld [[R2:\$[0-9]]], %got_disp(dwords)(
+
+; The first argument is the same in O32/N32/N64.
+; ALL-DAG:           sb $4, 1([[R1]])
+
+; The second slot is insufficiently aligned for i64 on O32 so it is skipped.
+; Also, i64 occupies two slots on O32 and only one for N32/N64.
+; O32-DAG:           sw $6, 8([[R2]])
+; O32-DAG:           sw $7, 12([[R2]])
+; NEW-DAG:           sd $5, 8([[R2]])
+
+; N32/N64 get an extra four arguments in registers and still have two left from
+; the first four.
+; O32 starts loading from the stack. The addresses start at 16 because space is
+; always reserved for the first four arguments.
+; It's not clear why O32 uses lbu for this argument, but it's not wrong so we'll
+; accept it for now. The only IR difference is that this argument has
+; anyext from i8 and align 8 on it.
+; O32LE-DAG:           lbu [[R3:\$[0-9]+]], 16($sp)
+; O32BE-DAG:           lbu [[R3:\$[0-9]+]], 19($sp)
+; O32-DAG:           sb [[R3]], 2([[R1]])
+; NEW-DAG:           sb $6, 2([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 20($sp)
+; O32-DAG:           sb [[R3]], 3([[R1]])
+; NEW-DAG:           sb $7, 3([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 24($sp)
+; O32-DAG:           sb [[R3]], 4([[R1]])
+; NEW-DAG:           sb $8, 4([[R1]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 28($sp)
+; O32-DAG:           sb [[R3]], 5([[R1]])
+; NEW-DAG:           sb $9, 5([[R1]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 32($sp)
+; O32-DAG:           sb [[R3]], 6([[R1]])
+; NEW-DAG:           sb $10, 6([[R1]])
+
+; O32-DAG:           lw [[R3:\$[0-9]+]], 40($sp)
+; O32-DAG:           sw [[R3]], 16([[R2]])
+; O32-DAG:           lw [[R3:\$[0-9]+]], 44($sp)
+; O32-DAG:           sw [[R3]], 20([[R2]])
+; NEW-DAG:           sd $11, 16([[R2]])
+
+; O32/N32/N64 are accessing the stack at this point.
+; Unlike O32, N32/N64 do not reserve space for the arguments.
+; increase by 4 for O32 and 8 for N32/N64.
+; O32-DAG:           lw [[R3:\$[0-9]+]], 48($sp)
+; O32-DAG:           sb [[R3]], 7([[R1]])
+; NEW-DAG:           lw [[R3:\$[0-9]+]], 0($sp)
+; NEW-DAG:           sb [[R3]], 7([[R1]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/callee-saved-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/callee-saved-float.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/callee-saved-float.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/callee-saved-float.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,112 @@
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=O32-INV %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=O32-INV %s
+
+; N32 should match O32 but currently matches N64
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=N32-INV %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=N32-INV %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=N64-INV %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=ALL-INV --check-prefix=N64-INV %s
+
+; Test the the callee-saved registers are callee-saved as specified by section
+; 2 of the MIPSpro N32 Handbook and section 3 of the SYSV ABI spec.
+
+define void @fpu_clobber() nounwind {
+entry:
+        call void asm "# Clobber", "~{$f0},~{$f1},~{$f2},~{$f3},~{$f4},~{$f5},~{$f6},~{$f7},~{$f8},~{$f9},~{$f10},~{$f11},~{$f12},~{$f13},~{$f14},~{$f15},~{$f16},~{$f17},~{$f18},~{$f19},~{$f20},~{$f21},~{$f22},~{$f23},~{$f24},~{$f25},~{$f26},~{$f27},~{$f28},~{$f29},~{$f30},~{$f31}"()
+        ret void
+}
+
+; ALL-LABEL: fpu_clobber:
+; ALL-INV-NOT:   sdc1 $f0,
+; ALL-INV-NOT:   sdc1 $f1,
+; ALL-INV-NOT:   sdc1 $f2,
+; ALL-INV-NOT:   sdc1 $f3,
+; ALL-INV-NOT:   sdc1 $f4,
+; ALL-INV-NOT:   sdc1 $f5,
+; ALL-INV-NOT:   sdc1 $f6,
+; ALL-INV-NOT:   sdc1 $f7,
+; ALL-INV-NOT:   sdc1 $f8,
+; ALL-INV-NOT:   sdc1 $f9,
+; ALL-INV-NOT:   sdc1 $f10,
+; ALL-INV-NOT:   sdc1 $f11,
+; ALL-INV-NOT:   sdc1 $f12,
+; ALL-INV-NOT:   sdc1 $f13,
+; ALL-INV-NOT:   sdc1 $f14,
+; ALL-INV-NOT:   sdc1 $f15,
+; ALL-INV-NOT:   sdc1 $f16,
+; ALL-INV-NOT:   sdc1 $f17,
+; ALL-INV-NOT:   sdc1 $f18,
+; ALL-INV-NOT:   sdc1 $f19,
+; ALL-INV-NOT:   sdc1 $f21,
+; ALL-INV-NOT:   sdc1 $f23,
+
+; O32:           addiu $sp, $sp, -48
+; O32-DAG:       sdc1 [[F20:\$f20]], [[OFF20:[0-9]+]]($sp)
+; O32-DAG:       sdc1 [[F22:\$f22]], [[OFF22:[0-9]+]]($sp)
+; O32-DAG:       sdc1 [[F24:\$f24]], [[OFF24:[0-9]+]]($sp)
+; O32-DAG:       sdc1 [[F26:\$f26]], [[OFF26:[0-9]+]]($sp)
+; O32-DAG:       sdc1 [[F28:\$f28]], [[OFF28:[0-9]+]]($sp)
+; O32-DAG:       sdc1 [[F30:\$f30]], [[OFF30:[0-9]+]]($sp)
+; O32-DAG:       ldc1 [[F20]], [[OFF20]]($sp)
+; O32-DAG:       ldc1 [[F22]], [[OFF22]]($sp)
+; O32-DAG:       ldc1 [[F24]], [[OFF24]]($sp)
+; O32-INV-NOT:   sdc1 $f25,
+; O32-DAG:       ldc1 [[F26]], [[OFF26]]($sp)
+; O32-INV-NOT:   sdc1 $f27,
+; O32-DAG:       ldc1 [[F28]], [[OFF28]]($sp)
+; O32-INV-NOT:   sdc1 $f29,
+; O32-DAG:       ldc1 [[F30]], [[OFF30]]($sp)
+; O32-INV-NOT:   sdc1 $f31,
+; O32:           addiu $sp, $sp, 48
+
+; N32:           addiu $sp, $sp, -48
+; N32-DAG:       sdc1 [[F20:\$f20]], [[OFF20:[0-9]+]]($sp)
+; N32-DAG:       sdc1 [[F22:\$f22]], [[OFF22:[0-9]+]]($sp)
+; N32-DAG:       sdc1 [[F24:\$f24]], [[OFF24:[0-9]+]]($sp)
+; N32-DAG:       sdc1 [[F26:\$f26]], [[OFF26:[0-9]+]]($sp)
+; N32-DAG:       sdc1 [[F28:\$f28]], [[OFF28:[0-9]+]]($sp)
+; N32-DAG:       sdc1 [[F30:\$f30]], [[OFF30:[0-9]+]]($sp)
+; N32-DAG:       ldc1 [[F20]], [[OFF20]]($sp)
+; N32-DAG:       ldc1 [[F22]], [[OFF22]]($sp)
+; N32-DAG:       ldc1 [[F24]], [[OFF24]]($sp)
+; N32-INV-NOT:   sdc1 $f25,
+; N32-DAG:       ldc1 [[F26]], [[OFF26]]($sp)
+; N32-INV-NOT:   sdc1 $f27,
+; N32-DAG:       ldc1 [[F28]], [[OFF28]]($sp)
+; N32-INV-NOT:   sdc1 $f29,
+; N32-DAG:       ldc1 [[F30]], [[OFF30]]($sp)
+; N32-INV-NOT:   sdc1 $f31,
+; N32:           addiu $sp, $sp, 48
+
+; N64:           addiu $sp, $sp, -64
+; N64-INV-NOT:   sdc1 $f20,
+; N64-INV-NOT:   sdc1 $f22,
+; N64-DAG:       sdc1 [[F24:\$f24]], [[OFF24:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F25:\$f25]], [[OFF25:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F26:\$f26]], [[OFF26:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F27:\$f27]], [[OFF27:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F28:\$f28]], [[OFF28:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F29:\$f29]], [[OFF29:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F30:\$f30]], [[OFF30:[0-9]+]]($sp)
+; N64-DAG:       sdc1 [[F31:\$f31]], [[OFF31:[0-9]+]]($sp)
+; N64-DAG:       ldc1 [[F24]], [[OFF24]]($sp)
+; N64-DAG:       ldc1 [[F25]], [[OFF25]]($sp)
+; N64-DAG:       ldc1 [[F26]], [[OFF26]]($sp)
+; N64-DAG:       ldc1 [[F27]], [[OFF27]]($sp)
+; N64-DAG:       ldc1 [[F28]], [[OFF28]]($sp)
+; N64-DAG:       ldc1 [[F29]], [[OFF29]]($sp)
+; N64-DAG:       ldc1 [[F30]], [[OFF30]]($sp)
+; N64-DAG:       ldc1 [[F31]], [[OFF31]]($sp)
+; N64:           addiu $sp, $sp, 64

Added: llvm/trunk/test/CodeGen/Mips/cconv/callee-saved.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/callee-saved.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/callee-saved.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/callee-saved.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,167 @@
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32-INV %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32-INV %s
+; RUN: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32-INV %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64-INV %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64-INV %s
+
+; Test the the callee-saved registers are callee-saved as specified by section
+; 2 of the MIPSpro N32 Handbook and section 3 of the SYSV ABI spec.
+
+define void @gpr_clobber() nounwind {
+entry:
+        ; Clobbering the stack pointer is a bad idea so we'll skip that one
+        call void asm "# Clobber", "~{$0},~{$1},~{$2},~{$3},~{$4},~{$5},~{$6},~{$7},~{$8},~{$9},~{$10},~{$11},~{$12},~{$13},~{$14},~{$15},~{$16},~{$17},~{$18},~{$19},~{$20},~{$21},~{$22},~{$23},~{$24},~{$25},~{$26},~{$27},~{$28},~{$30},~{$31}"()
+        ret void
+}
+
+; ALL-LABEL: gpr_clobber:
+; O32:           addiu $sp, $sp, -40
+; O32-INV-NOT:   sw $0,
+; O32-INV-NOT:   sw $1,
+; O32-INV-NOT:   sw $2,
+; O32-INV-NOT:   sw $3,
+; O32-INV-NOT:   sw $4,
+; O32-INV-NOT:   sw $5,
+; O32-INV-NOT:   sw $6,
+; O32-INV-NOT:   sw $7,
+; O32-INV-NOT:   sw $8,
+; O32-INV-NOT:   sw $9,
+; O32-INV-NOT:   sw $10,
+; O32-INV-NOT:   sw $11,
+; O32-INV-NOT:   sw $12,
+; O32-INV-NOT:   sw $13,
+; O32-INV-NOT:   sw $14,
+; O32-INV-NOT:   sw $15,
+; O32-DAG:       sw [[G16:\$16]], [[OFF16:[0-9]+]]($sp)
+; O32-DAG:       sw [[G17:\$17]], [[OFF17:[0-9]+]]($sp)
+; O32-DAG:       sw [[G18:\$18]], [[OFF18:[0-9]+]]($sp)
+; O32-DAG:       sw [[G19:\$19]], [[OFF19:[0-9]+]]($sp)
+; O32-DAG:       sw [[G20:\$20]], [[OFF20:[0-9]+]]($sp)
+; O32-DAG:       sw [[G21:\$21]], [[OFF21:[0-9]+]]($sp)
+; O32-DAG:       sw [[G22:\$22]], [[OFF22:[0-9]+]]($sp)
+; O32-DAG:       sw [[G23:\$23]], [[OFF23:[0-9]+]]($sp)
+; O32-INV-NOT:   sw $24,
+; O32-INV-NOT:   sw $25,
+; O32-INV-NOT:   sw $26,
+; O32-INV-NOT:   sw $27,
+; O32-INV-NOT:   sw $28,
+; O32-INV-NOT:   sw $29,
+; O32-DAG:       sw [[G30:\$fp]], [[OFF30:[0-9]+]]($sp)
+; O32-DAG:       sw [[G31:\$fp]], [[OFF31:[0-9]+]]($sp)
+; O32-DAG:       lw [[G16]], [[OFF16]]($sp)
+; O32-DAG:       lw [[G17]], [[OFF17]]($sp)
+; O32-DAG:       lw [[G18]], [[OFF18]]($sp)
+; O32-DAG:       lw [[G19]], [[OFF19]]($sp)
+; O32-DAG:       lw [[G20]], [[OFF20]]($sp)
+; O32-DAG:       lw [[G21]], [[OFF21]]($sp)
+; O32-DAG:       lw [[G22]], [[OFF22]]($sp)
+; O32-DAG:       lw [[G23]], [[OFF23]]($sp)
+; O32-DAG:       lw [[G30]], [[OFF30]]($sp)
+; O32-DAG:       lw [[G31]], [[OFF31]]($sp)
+; O32:           addiu $sp, $sp, 40
+
+; N32:           addiu $sp, $sp, -96
+; N32-INV-NOT:   sd $0,
+; N32-INV-NOT:   sd $1,
+; N32-INV-NOT:   sd $2,
+; N32-INV-NOT:   sd $3,
+; N32-INV-NOT:   sd $4,
+; N32-INV-NOT:   sd $5,
+; N32-INV-NOT:   sd $6,
+; N32-INV-NOT:   sd $7,
+; N32-INV-NOT:   sd $8,
+; N32-INV-NOT:   sd $9,
+; N32-INV-NOT:   sd $10,
+; N32-INV-NOT:   sd $11,
+; N32-INV-NOT:   sd $12,
+; N32-INV-NOT:   sd $13,
+; N32-INV-NOT:   sd $14,
+; N32-INV-NOT:   sd $15,
+; N32-DAG:       sd [[G16:\$16]], [[OFF16:[0-9]+]]($sp)
+; N32-DAG:       sd [[G17:\$17]], [[OFF17:[0-9]+]]($sp)
+; N32-DAG:       sd [[G18:\$18]], [[OFF18:[0-9]+]]($sp)
+; N32-DAG:       sd [[G19:\$19]], [[OFF19:[0-9]+]]($sp)
+; N32-DAG:       sd [[G20:\$20]], [[OFF20:[0-9]+]]($sp)
+; N32-DAG:       sd [[G21:\$21]], [[OFF21:[0-9]+]]($sp)
+; N32-DAG:       sd [[G22:\$22]], [[OFF22:[0-9]+]]($sp)
+; N32-DAG:       sd [[G23:\$23]], [[OFF23:[0-9]+]]($sp)
+; N32-INV-NOT:   sd $24,
+; N32-INV-NOT:   sd $25,
+; N32-INV-NOT:   sd $26,
+; N32-INV-NOT:   sd $27,
+; N32-DAG:       sd [[G28:\$gp]], [[OFF28:[0-9]+]]($sp)
+; N32-INV-NOT:   sd $29,
+; N32-DAG:       sd [[G30:\$fp]], [[OFF30:[0-9]+]]($sp)
+; N32-DAG:       sd [[G31:\$fp]], [[OFF31:[0-9]+]]($sp)
+; N32-DAG:       ld [[G16]], [[OFF16]]($sp)
+; N32-DAG:       ld [[G17]], [[OFF17]]($sp)
+; N32-DAG:       ld [[G18]], [[OFF18]]($sp)
+; N32-DAG:       ld [[G19]], [[OFF19]]($sp)
+; N32-DAG:       ld [[G20]], [[OFF20]]($sp)
+; N32-DAG:       ld [[G21]], [[OFF21]]($sp)
+; N32-DAG:       ld [[G22]], [[OFF22]]($sp)
+; N32-DAG:       ld [[G23]], [[OFF23]]($sp)
+; N32-DAG:       ld [[G28]], [[OFF28]]($sp)
+; N32-DAG:       ld [[G30]], [[OFF30]]($sp)
+; N32-DAG:       ld [[G31]], [[OFF31]]($sp)
+; N32:           addiu $sp, $sp, 96
+
+; N64:           daddiu $sp, $sp, -96
+; N64-INV-NOT:   sd $0,
+; N64-INV-NOT:   sd $1,
+; N64-INV-NOT:   sd $2,
+; N64-INV-NOT:   sd $3,
+; N64-INV-NOT:   sd $4,
+; N64-INV-NOT:   sd $5,
+; N64-INV-NOT:   sd $6,
+; N64-INV-NOT:   sd $7,
+; N64-INV-NOT:   sd $8,
+; N64-INV-NOT:   sd $9,
+; N64-INV-NOT:   sd $10,
+; N64-INV-NOT:   sd $11,
+; N64-INV-NOT:   sd $12,
+; N64-INV-NOT:   sd $13,
+; N64-INV-NOT:   sd $14,
+; N64-INV-NOT:   sd $15,
+; N64-DAG:       sd [[G16:\$16]], [[OFF16:[0-9]+]]($sp)
+; N64-DAG:       sd [[G17:\$17]], [[OFF17:[0-9]+]]($sp)
+; N64-DAG:       sd [[G18:\$18]], [[OFF18:[0-9]+]]($sp)
+; N64-DAG:       sd [[G19:\$19]], [[OFF19:[0-9]+]]($sp)
+; N64-DAG:       sd [[G20:\$20]], [[OFF20:[0-9]+]]($sp)
+; N64-DAG:       sd [[G21:\$21]], [[OFF21:[0-9]+]]($sp)
+; N64-DAG:       sd [[G22:\$22]], [[OFF22:[0-9]+]]($sp)
+; N64-DAG:       sd [[G23:\$23]], [[OFF23:[0-9]+]]($sp)
+; N64-DAG:       sd [[G30:\$fp]], [[OFF30:[0-9]+]]($sp)
+; N64-DAG:       sd [[G31:\$fp]], [[OFF31:[0-9]+]]($sp)
+; N64-INV-NOT:   sd $24,
+; N64-INV-NOT:   sd $25,
+; N64-INV-NOT:   sd $26,
+; N64-INV-NOT:   sd $27,
+; N64-DAG:       sd [[G28:\$gp]], [[OFF28:[0-9]+]]($sp)
+; N64-INV-NOT:   sd $29,
+; N64-DAG:       ld [[G16]], [[OFF16]]($sp)
+; N64-DAG:       ld [[G17]], [[OFF17]]($sp)
+; N64-DAG:       ld [[G18]], [[OFF18]]($sp)
+; N64-DAG:       ld [[G19]], [[OFF19]]($sp)
+; N64-DAG:       ld [[G20]], [[OFF20]]($sp)
+; N64-DAG:       ld [[G21]], [[OFF21]]($sp)
+; N64-DAG:       ld [[G22]], [[OFF22]]($sp)
+; N64-DAG:       ld [[G23]], [[OFF23]]($sp)
+; N64-DAG:       ld [[G28]], [[OFF28]]($sp)
+; N64-DAG:       ld [[G30]], [[OFF30]]($sp)
+; N64-DAG:       ld [[G31]], [[OFF31]]($sp)
+; N64:           daddiu $sp, $sp, 96

Added: llvm/trunk/test/CodeGen/Mips/cconv/memory-layout.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/memory-layout.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/memory-layout.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/memory-layout.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,140 @@
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the memory layout for all ABI's and byte orders as specified by section
+; 4 of MD00305 (MIPS ABIs Described).
+; Bitfields are not covered since they are not available as a type in LLVM IR.
+;
+; The assembly directives deal with endianness so we don't need to account for
+; that.
+
+; Deliberately request alignments that are too small for the target so we get
+; the minimum alignment instead of the preferred alignment.
+ at byte = global i8 1, align 1
+ at halfword = global i16 258, align 1
+ at word = global i32 16909060, align 1
+ at float = global float 1.0, align 1
+ at dword = global i64 283686952306183, align 1
+ at double = global double 1.0, align 1
+ at pointer = global i8* @byte
+
+; ALL-NOT:       .align
+; ALL-LABEL: byte:
+; ALL:           .byte 1
+; ALL:           .size byte, 1
+
+; ALL:           .align 1
+; ALL-LABEL: halfword:
+; ALL:           .2byte 258
+; ALL:           .size halfword, 2
+
+; ALL:           .align 2
+; ALL-LABEL: word:
+; ALL:           .4byte 16909060
+; ALL:           .size word, 4
+
+; ALL:           .align 2
+; ALL-LABEL: float:
+; ALL:           .4byte 1065353216
+; ALL:           .size float, 4
+
+; ALL:           .align 3
+; ALL-LABEL: dword:
+; ALL:           .8byte 283686952306183
+; ALL:           .size dword, 8
+
+; ALL:           .align 3
+; ALL-LABEL: double:
+; ALL:           .8byte 4607182418800017408
+; ALL:           .size double, 8
+
+; O32:           .align 2
+; N32:           .align 2
+; N64:           .align 3
+; ALL-LABEL: pointer:
+; O32:           .4byte byte
+; O32:           .size pointer, 4
+; N32:           .4byte byte
+; N32:           .size pointer, 4
+; N64:           .8byte byte
+; N64:           .size pointer, 8
+
+ at byte_array = global [2 x i8] [i8 1, i8 2], align 1
+ at halfword_array = global [2 x i16] [i16 1, i16 2], align 1
+ at word_array = global [2 x i32] [i32 1, i32 2], align 1
+ at float_array = global [2 x float] [float 1.0, float 2.0], align 1
+ at dword_array = global [2 x i64] [i64 1, i64 2], align 1
+ at double_array = global [2 x double] [double 1.0, double 2.0], align 1
+ at pointer_array = global [2 x i8*] [i8* @byte, i8* @byte]
+
+; ALL-NOT:       .align
+; ALL-LABEL: byte_array:
+; ALL:           .ascii "\001\002"
+; ALL:           .size byte_array, 2
+
+; ALL:           .align 1
+; ALL-LABEL: halfword_array:
+; ALL:           .2byte 1
+; ALL:           .2byte 2
+; ALL:           .size halfword_array, 4
+
+; ALL:           .align 2
+; ALL-LABEL: word_array:
+; ALL:           .4byte 1
+; ALL:           .4byte 2
+; ALL:           .size word_array, 8
+
+; ALL:           .align 2
+; ALL-LABEL: float_array:
+; ALL:           .4byte 1065353216
+; ALL:           .4byte 1073741824
+; ALL:           .size float_array, 8
+
+; ALL:           .align 3
+; ALL-LABEL: dword_array:
+; ALL:           .8byte 1
+; ALL:           .8byte 2
+; ALL:           .size dword_array, 16
+
+; ALL:           .align 3
+; ALL-LABEL: double_array:
+; ALL:           .8byte 4607182418800017408
+; ALL:           .8byte 4611686018427387904
+; ALL:           .size double_array, 16
+
+; O32:           .align 2
+; N32:           .align 2
+; N64:           .align 3
+; ALL-LABEL: pointer_array:
+; O32:           .4byte byte
+; O32:           .4byte byte
+; O32:           .size pointer_array, 8
+; N32:           .4byte byte
+; N32:           .4byte byte
+; N32:           .size pointer_array, 8
+; N64:           .8byte byte
+; N64:           .8byte byte
+; N64:           .size pointer_array, 16
+
+%mixed = type { i8, double, i16 }
+ at mixed = global %mixed { i8 1, double 1.0, i16 515 }, align 1
+
+; ALL:           .align 3
+; ALL-LABEL: mixed:
+; ALL:           .byte 1
+; ALL:           .space 7
+; ALL:           .8byte 4607182418800017408
+; ALL:           .2byte 515
+; ALL:           .space 6
+; ALL:           .size mixed, 24
+
+; Bitfields are not available in LLVM IR so we can't test them here.

Added: llvm/trunk/test/CodeGen/Mips/cconv/reserved-space.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/reserved-space.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/reserved-space.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/reserved-space.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,39 @@
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test that O32 correctly reserved space for the four arguments, even when
+; there aren't any as per section 5 of MD00305 (MIPS ABIs Described).
+
+declare void @foo() nounwind;
+
+define void @reserved_space() nounwind {
+entry:
+        tail call void @foo()
+        ret void
+}
+
+; ALL-LABEL: reserved_space:
+; O32:           addiu $sp, $sp, -24
+; O32:           sw $ra, 20($sp)
+; O32:           lw $ra, 20($sp)
+; O32:           addiu $sp, $sp, 24
+; Despite pointers being 32-bit wide on N32, the return pointer is saved as a
+; 64-bit pointer. I've yet to find a documentation reference for this quirk but
+; this behaviour matches GCC so I have considered it to be correct.
+; N32:           addiu $sp, $sp, -16
+; N32:           sd $ra, 8($sp)
+; N32:           ld $ra, 8($sp)
+; N32:           addiu $sp, $sp, 16
+; N64:           daddiu $sp, $sp, -16
+; N64:           sd $ra, 8($sp)
+; N64:           ld $ra, 8($sp)
+; N64:           daddiu $sp, $sp, 16

Added: llvm/trunk/test/CodeGen/Mips/cconv/return-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/return-float.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/return-float.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/return-float.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,45 @@
+; RUN: llc -march=mips -soft-float -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel -soft-float -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -soft-float -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -soft-float -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -soft-float -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -soft-float -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -soft-float -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -soft-float -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the float returns for all ABI's and byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+
+ at float = global float zeroinitializer
+ at double = global double zeroinitializer
+
+define float @retfloat() nounwind {
+entry:
+        %0 = load volatile float* @float
+        ret float %0
+}
+
+; ALL-LABEL: retfloat:
+; O32-DAG:           lui [[R1:\$[0-9]+]], %hi(float)
+; O32-DAG:           lw $2, %lo(float)([[R1]])
+; N32-DAG:           lui [[R1:\$[0-9]+]], %hi(float)
+; N32-DAG:           lw $2, %lo(float)([[R1]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(float)($1)
+; N64-DAG:           lw $2, 0([[R1]])
+
+define double @retdouble() nounwind {
+entry:
+        %0 = load volatile double* @double
+        ret double %0
+}
+
+; ALL-LABEL: retdouble:
+; O32-DAG:           lw $2, %lo(double)([[R1:\$[0-9]+]])
+; O32-DAG:           addiu [[R2:\$[0-9]+]], [[R1]], %lo(double)
+; O32-DAG:           lw $3, 4([[R2]])
+; N32-DAG:           ld $2, %lo(double)([[R1:\$[0-9]+]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(double)($1)
+; N64-DAG:           ld $2, 0([[R1]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/return-hard-float.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/return-hard-float.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/return-hard-float.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/return-hard-float.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,43 @@
+; RUN: llc -march=mips -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the float returns for all ABI's and byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+
+ at float = global float zeroinitializer
+ at double = global double zeroinitializer
+
+define float @retfloat() nounwind {
+entry:
+        %0 = load volatile float* @float
+        ret float %0
+}
+
+; ALL-LABEL: retfloat:
+; O32-DAG:           lui [[R1:\$[0-9]+]], %hi(float)
+; O32-DAG:           lwc1 $f0, %lo(float)([[R1]])
+; N32-DAG:           lui [[R1:\$[0-9]+]], %hi(float)
+; N32-DAG:           lwc1 $f0, %lo(float)([[R1]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(float)($1)
+; N64-DAG:           lwc1 $f0, 0([[R1]])
+
+define double @retdouble() nounwind {
+entry:
+        %0 = load volatile double* @double
+        ret double %0
+}
+
+; ALL-LABEL: retdouble:
+; O32-DAG:           ldc1 $f0, %lo(double)([[R1:\$[0-9]+]])
+; N32-DAG:           ldc1 $f0, %lo(double)([[R1:\$[0-9]+]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(double)($1)
+; N64-DAG:           ldc1 $f0, 0([[R1]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/return-hard-fp128.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/return-hard-fp128.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/return-hard-fp128.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/return-hard-fp128.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,31 @@
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the fp128 returns for N32/N64 and all byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+;
+; O32 is not tested because long double is the same as double on O32.
+;
+ at fp128 = global fp128 zeroinitializer
+
+define fp128 @retldouble() nounwind {
+entry:
+        %0 = load volatile fp128* @fp128
+        ret fp128 %0
+}
+
+; ALL-LABEL: retldouble:
+; N32-DAG:           ld [[R2:\$[0-9]+]], %lo(fp128)([[R1:\$[0-9]+]])
+; N32-DAG:           addiu [[R3:\$[0-9]+]], [[R1]], %lo(fp128)
+; N32-DAG:           ld [[R4:\$[0-9]+]], 8([[R3]])
+; N32-DAG:           dmtc1 [[R2]], $f0
+; N32-DAG:           dmtc1 [[R4]], $f2
+
+; N64-DAG:           ld [[R2:\$[0-9]+]], %got_disp(fp128)([[R1:\$[0-9]+]])
+; N64-DAG:           ld [[R3:\$[0-9]+]], 0([[R2]])
+; N64-DAG:           ld [[R4:\$[0-9]+]], 8([[R2]])
+; N64-DAG:           dmtc1 [[R3]], $f0
+; N64-DAG:           dmtc1 [[R4]], $f2

Added: llvm/trunk/test/CodeGen/Mips/cconv/return.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/return.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/return.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/return.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,63 @@
+; RUN: llc -march=mips -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel -relocation-model=static < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -relocation-model=static -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -relocation-model=static -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the integer returns for all ABI's and byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+;
+ at byte = global i8 zeroinitializer
+ at word = global i32 zeroinitializer
+ at dword = global i64 zeroinitializer
+ at float = global float zeroinitializer
+ at double = global double zeroinitializer
+
+define i8 @reti8() nounwind {
+entry:
+        %0 = load volatile i8* @byte
+        ret i8 %0
+}
+
+; ALL-LABEL: reti8:
+; O32-DAG:           lui [[R1:\$[0-9]+]], %hi(byte)
+; O32-DAG:           lbu $2, %lo(byte)([[R1]])
+; N32-DAG:           lui [[R1:\$[0-9]+]], %hi(byte)
+; N32-DAG:           lbu $2, %lo(byte)([[R1]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(byte)($1)
+; N64-DAG:           lbu $2, 0([[R1]])
+
+define i32 @reti32() nounwind {
+entry:
+        %0 = load volatile i32* @word
+        ret i32 %0
+}
+
+; ALL-LABEL: reti32:
+; O32-DAG:           lui [[R1:\$[0-9]+]], %hi(word)
+; O32-DAG:           lw $2, %lo(word)([[R1]])
+; N32-DAG:           lui [[R1:\$[0-9]+]], %hi(word)
+; N32-DAG:           lw $2, %lo(word)([[R1]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(word)($1)
+; N64-DAG:           lw $2, 0([[R1]])
+
+define i64 @reti64() nounwind {
+entry:
+        %0 = load volatile i64* @dword
+        ret i64 %0
+}
+
+; ALL-LABEL: reti64:
+; On O32, we must use v0 and v1 for the return value
+; O32-DAG:           lw $2, %lo(dword)([[R1:\$[0-9]+]])
+; O32-DAG:           addiu [[R2:\$[0-9]+]], [[R1]], %lo(dword)
+; O32-DAG:           lw $3, 4([[R2]])
+; N32-DAG:           ld $2, %lo(dword)([[R1:\$[0-9]+]])
+; N64-DAG:           ld  [[R1:\$[0-9]+]], %got_disp(dword)([[R1:\$[0-9]+]])
+; N64-DAG:           ld $2, 0([[R1]])

Added: llvm/trunk/test/CodeGen/Mips/cconv/stack-alignment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/cconv/stack-alignment.ll?rev=206370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/cconv/stack-alignment.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/cconv/stack-alignment.ll Wed Apr 16 04:59:46 2014
@@ -0,0 +1,28 @@
+; RUN: llc -march=mips < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN: llc -march=mipsel < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN-TODO: llc -march=mips64 -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+; RUN-TODO: llc -march=mips64el -mattr=-n64,+o32 < %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n32 < %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+
+; RUN: llc -march=mips64 -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+; RUN: llc -march=mips64el -mattr=-n64,+n64 < %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+; Test the stack alignment for all ABI's and byte orders as specified by
+; section 5 of MD00305 (MIPS ABIs Described).
+
+define void @local_bytes_1() nounwind {
+entry:
+        %0 = alloca i8
+        ret void
+}
+
+; ALL-LABEL: local_bytes_1:
+; O32:           addiu $sp, $sp, -8
+; O32:           addiu $sp, $sp, 8
+; N32:           addiu $sp, $sp, -16
+; N32:           addiu $sp, $sp, 16
+; N64:           addiu $sp, $sp, -16
+; N64:           addiu $sp, $sp, 16





More information about the llvm-commits mailing list