[cfe-commits] r159676 - in /cfe/trunk: lib/CodeGen/TargetInfo.cpp test/CodeGen/mips-vector-arg.c test/CodeGen/mips-vector-return.c

Akira Hatanaka ahatanaka at mips.com
Tue Jul 3 12:24:06 PDT 2012


Author: ahatanak
Date: Tue Jul  3 14:24:06 2012
New Revision: 159676

URL: http://llvm.org/viewvc/llvm-project?rev=159676&view=rev
Log:
Make the following changes in the way Mips handles vector arguments and return
values:

- Return integer vectors in integer registers.
- Pass vector arguments in integer registers.
- Set an upper bound for argument alignment. The largest alignment is 8-byte
  for O32 and 16-byte for N32/64.


Added:
    cfe/trunk/test/CodeGen/mips-vector-arg.c
Modified:
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/test/CodeGen/mips-vector-return.c

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=159676&r1=159675&r2=159676&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Jul  3 14:24:06 2012
@@ -3166,14 +3166,16 @@
 namespace {
 class MipsABIInfo : public ABIInfo {
   bool IsO32;
-  unsigned MinABIStackAlignInBytes;
-  llvm::Type* CoerceToIntArgs(uint64_t TySize) const;
+  unsigned MinABIStackAlignInBytes, StackAlignInBytes;
+  void CoerceToIntArgs(uint64_t TySize,
+                       SmallVector<llvm::Type*, 8> &ArgList) const;
   llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;
   llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
   llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
 public:
   MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) :
-    ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {}
+    ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8),
+    StackAlignInBytes(IsO32 ? 8 : 16) {}
 
   ABIArgInfo classifyReturnType(QualType RetTy) const;
   ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
@@ -3202,10 +3204,10 @@
 };
 }
 
-llvm::Type* MipsABIInfo::CoerceToIntArgs(uint64_t TySize) const {
-  SmallVector<llvm::Type*, 8> ArgList;
-  llvm::IntegerType *IntTy = llvm::IntegerType::get(getVMContext(),
-                                                    MinABIStackAlignInBytes * 8);
+void MipsABIInfo::CoerceToIntArgs(uint64_t TySize,
+                                  SmallVector<llvm::Type*, 8> &ArgList) const {
+  llvm::IntegerType *IntTy =
+    llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8);
 
   // Add (TySize / MinABIStackAlignInBytes) args of IntTy.
   for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N)
@@ -3216,24 +3218,28 @@
 
   if (R)
     ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));
-
-  return llvm::StructType::get(getVMContext(), ArgList);
 }
 
 // In N32/64, an aligned double precision floating point field is passed in
 // a register.
 llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
-  if (IsO32)
-    return CoerceToIntArgs(TySize);
+  SmallVector<llvm::Type*, 8> ArgList, IntArgList;
+
+  if (IsO32) {
+    CoerceToIntArgs(TySize, ArgList);
+    return llvm::StructType::get(getVMContext(), ArgList);
+  }
 
   if (Ty->isComplexType())
     return CGT.ConvertType(Ty);
 
   const RecordType *RT = Ty->getAs<RecordType>();
 
-  // Unions are passed in integer registers.
-  if (!RT || !RT->isStructureOrClassType())
-    return CoerceToIntArgs(TySize);
+  // Unions/vectors are passed in integer registers.
+  if (!RT || !RT->isStructureOrClassType()) {
+    CoerceToIntArgs(TySize, ArgList);
+    return llvm::StructType::get(getVMContext(), ArgList);
+  }
 
   const RecordDecl *RD = RT->getDecl();
   const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
@@ -3242,7 +3248,6 @@
   uint64_t LastOffset = 0;
   unsigned idx = 0;
   llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64);
-  SmallVector<llvm::Type*, 8> ArgList;
 
   // Iterate over fields in the struct/class and check if there are any aligned
   // double fields.
@@ -3267,15 +3272,8 @@
     LastOffset = Offset + 64;
   }
 
-  // Add ((TySize - LastOffset) / 64) args of type i64.
-  for (unsigned N = (TySize - LastOffset) / 64; N; --N)
-    ArgList.push_back(I64);
-
-  // If the size of the remainder is not zero, add one more integer type to
-  // ArgList.
-  unsigned R = (TySize - LastOffset) % 64;
-  if (R)
-    ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));
+  CoerceToIntArgs(TySize - LastOffset, IntArgList);
+  ArgList.append(IntArgList.begin(), IntArgList.end());
 
   return llvm::StructType::get(getVMContext(), ArgList);
 }
@@ -3295,11 +3293,12 @@
   uint64_t TySize = getContext().getTypeSize(Ty);
   uint64_t Align = getContext().getTypeAlign(Ty) / 8;
 
-  Align = std::max(Align, (uint64_t)MinABIStackAlignInBytes);
+  Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes),
+                   (uint64_t)StackAlignInBytes);
   Offset = llvm::RoundUpToAlignment(Offset, Align);
   Offset += llvm::RoundUpToAlignment(TySize, Align * 8) / 8;
 
-  if (isAggregateTypeForABI(Ty)) {
+  if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) {
     // Ignore empty aggregates.
     if (TySize == 0)
       return ABIArgInfo::getIgnore();
@@ -3331,7 +3330,7 @@
 llvm::Type*
 MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {
   const RecordType *RT = RetTy->getAs<RecordType>();
-  SmallVector<llvm::Type*, 2> RTList;
+  SmallVector<llvm::Type*, 8> RTList;
 
   if (RT && RT->isStructureOrClassType()) {
     const RecordDecl *RD = RT->getDecl();
@@ -3366,11 +3365,7 @@
     }
   }
 
-  RTList.push_back(llvm::IntegerType::get(getVMContext(),
-                                          std::min(Size, (uint64_t)64)));
-  if (Size > 64)
-    RTList.push_back(llvm::IntegerType::get(getVMContext(), Size - 64));
-
+  CoerceToIntArgs(Size, RTList);
   return llvm::StructType::get(getVMContext(), RTList);
 }
 
@@ -3385,6 +3380,10 @@
       if (RetTy->isAnyComplexType())
         return ABIArgInfo::getDirect();
 
+      // O32 returns integer vectors in registers.
+      if (IsO32 && RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())
+        return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size));
+
       if (!IsO32 && !isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy))
         return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size));
     }

Added: cfe/trunk/test/CodeGen/mips-vector-arg.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mips-vector-arg.c?rev=159676&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/mips-vector-arg.c (added)
+++ cfe/trunk/test/CodeGen/mips-vector-arg.c Tue Jul  3 14:24:06 2012
@@ -0,0 +1,28 @@
+// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
+// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64
+
+// check that
+// 1. vector arguments are passed in integer registers
+// 2. argument alignment is no larger than 8-byte for O32 and 16-byte for N64.
+
+typedef float  v4sf __attribute__ ((__vector_size__ (16)));
+typedef int v4i32 __attribute__ ((__vector_size__ (16)));
+
+// O32: define void @test_v4sf(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind 
+// O32: declare i32 @test_v4sf_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)
+// N64: define void @test_v4sf(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind
+// N64: declare i32 @test_v4sf_2(i64, i64, i32, i64, i64, i64)
+extern test_v4sf_2(v4sf, int, v4sf);
+void test_v4sf(v4sf a1, int a2, v4sf a3) {
+  test_v4sf_2(a3, a2, a1);
+}
+
+// O32: define void @test_v4i32(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind 
+// O32: declare i32 @test_v4i32_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)
+// N64: define void @test_v4i32(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind
+// N64: declare i32 @test_v4i32_2(i64, i64, i32, i64, i64, i64)
+extern test_v4i32_2(v4i32, int, v4i32);
+void test_v4i32(v4i32 a1, int a2, v4i32 a3) {
+  test_v4i32_2(a3, a2, a1);
+}
+

Modified: cfe/trunk/test/CodeGen/mips-vector-return.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mips-vector-return.c?rev=159676&r1=159675&r2=159676&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/mips-vector-return.c (original)
+++ cfe/trunk/test/CodeGen/mips-vector-return.c Tue Jul  3 14:24:06 2012
@@ -6,6 +6,7 @@
 // integer registers. 
 typedef float  v4sf __attribute__ ((__vector_size__ (16)));
 typedef double v4df __attribute__ ((__vector_size__ (32)));
+typedef int v4i32 __attribute__ ((__vector_size__ (16)));
 
 // O32: define void @test_v4sf(<4 x float>* noalias nocapture sret
 // N64: define { i64, i64 } @test_v4sf
@@ -19,3 +20,12 @@
   return (v4df){0.0, a, 0.0, 0.0};
 }
 
+// O32 returns integer vectors whose size is equal to or smaller than 16-bytes
+// in integer registers.
+//
+// O32: define { i32, i32, i32, i32 } @test_v4i32
+// N64: define { i64, i64 } @test_v4i32
+v4i32 test_v4i32(int a) {
+  return (v4i32){0, a, 0, 0};
+}
+





More information about the cfe-commits mailing list