r182745 - Add a SparcV9ABIInfo class for handling the standard SPARC v9 ABI.

Jakob Stoklund Olesen stoklund at 2pi.dk
Mon May 27 14:48:26 PDT 2013


Author: stoklund
Date: Mon May 27 16:48:25 2013
New Revision: 182745

URL: http://llvm.org/viewvc/llvm-project?rev=182745&view=rev
Log:
Add a SparcV9ABIInfo class for handling the standard SPARC v9 ABI.

- All integer arguments smaller than 64 bits are extended.
- Large structs are passed indirectly, not using 'byval'.
- Structs up to 32 bytes in size are returned in registers.

Some things are not implemented yet:

- EmitVAArg can be implemented in terms of the va_arg instruction.
- When structs are passed in registers, float members require special
  handling because they are passed in the floating point registers.
- Structs are left-aligned when passed in registers. This may require
  padding.

Added:
    cfe/trunk/test/CodeGen/sparcv9-abi.c
Modified:
    cfe/trunk/lib/CodeGen/TargetInfo.cpp

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=182745&r1=182744&r2=182745&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Mon May 27 16:48:25 2013
@@ -5125,6 +5125,97 @@ llvm::Value *HexagonABIInfo::EmitVAArg(l
 }
 
 
+//===----------------------------------------------------------------------===//
+// SPARC v9 ABI Implementation.
+// Based on the SPARC Compliance Definition version 2.4.1.
+//
+// Function arguments a mapped to a nominal "parameter array" and promoted to
+// registers depending on their type. Each argument occupies 8 or 16 bytes in
+// the array, structs larger than 16 bytes are passed indirectly.
+//
+// One case requires special care:
+//
+//   struct mixed {
+//     int i;
+//     float f;
+//   };
+//
+// When a struct mixed is passed by value, it only occupies 8 bytes in the
+// parameter array, but the int is passed in an integer register, and the float
+// is passed in a floating point register. This is represented as two arguments
+// with the LLVM IR inreg attribute:
+//
+//   declare void f(i32 inreg %i, float inreg %f)
+//
+// The code generator will only allocate 4 bytes from the parameter array for
+// the inreg arguments. All other arguments are allocated a multiple of 8
+// bytes.
+//
+namespace {
+class SparcV9ABIInfo : public ABIInfo {
+public:
+  SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+private:
+  ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
+  virtual void computeInfo(CGFunctionInfo &FI) const;
+  virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                 CodeGenFunction &CGF) const;
+};
+} // end anonymous namespace
+
+ABIArgInfo
+SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
+  if (Ty->isVoidType())
+    return ABIArgInfo::getIgnore();
+
+  uint64_t Size = getContext().getTypeSize(Ty);
+
+  // Anything too big to fit in registers is passed with an explicit indirect
+  // pointer / sret pointer.
+  if (Size > SizeLimit)
+    return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+  // Treat an enum type as its underlying type.
+  if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+    Ty = EnumTy->getDecl()->getIntegerType();
+
+  // Integer types smaller than a register are extended.
+  if (Size < 64 && Ty->isIntegerType())
+    return ABIArgInfo::getExtend();
+
+  // Other non-aggregates go in registers.
+  if (!isAggregateTypeForABI(Ty))
+    return ABIArgInfo::getDirect();
+
+  // This is a small aggregate type that should be passed in registers.
+  // FIXME: Compute the correct coersion type.
+  // FIXME: Ensure any float members are passed in float registers.
+  return ABIArgInfo::getDirect();
+}
+
+llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                       CodeGenFunction &CGF) const {
+  // FIXME: Implement with va_arg.
+  return 0;
+}
+
+void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+  FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
+  for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+       it != ie; ++it)
+    it->info = classifyType(it->type, 16 * 8);
+}
+
+namespace {
+class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+  SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
+    : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
+};
+} // end anonymous namespace
+
+
 const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
   if (TheTargetCodeGenInfo)
     return *TheTargetCodeGenInfo;
@@ -5240,5 +5331,7 @@ const TargetCodeGenInfo &CodeGenModule::
   }
   case llvm::Triple::hexagon:
     return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
+  case llvm::Triple::sparcv9:
+    return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types));
   }
 }

Added: cfe/trunk/test/CodeGen/sparcv9-abi.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/sparcv9-abi.c?rev=182745&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/sparcv9-abi.c (added)
+++ cfe/trunk/test/CodeGen/sparcv9-abi.c Mon May 27 16:48:25 2013
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple sparcv9-unknown-linux -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define void @f_void()
+void f_void(void) {}
+
+// Arguments and return values smaller than the word size are extended.
+
+// CHECK: define signext i32 @f_int_1(i32 signext %x)
+int f_int_1(int x) { return x; }
+
+// CHECK: define zeroext i32 @f_int_2(i32 zeroext %x)
+unsigned f_int_2(unsigned x) { return x; }
+
+// CHECK: define i64 @f_int_3(i64 %x)
+long long f_int_3(long long x) { return x; }
+
+// CHECK: define signext i8 @f_int_4(i8 signext %x)
+char f_int_4(char x) { return x; }
+
+// Small structs are passed in registers.
+struct small {
+  int *a, *b;
+};
+
+// CHECK: define %struct.small @f_small(i32* %x.coerce0, i32* %x.coerce1)
+struct small f_small(struct small x) {
+  x.a += *x.b;
+  x.b = 0;
+  return x;
+}
+
+// Medium-sized structs are passed indirectly, but can be returned in registers.
+struct medium {
+  int *a, *b;
+  int *c, *d;
+};
+
+// CHECK: define %struct.medium @f_medium(%struct.medium* %x)
+struct medium f_medium(struct medium x) {
+  x.a += *x.b;
+  x.b = 0;
+  return x;
+}
+
+// Large structs are also returned indirectly.
+struct large {
+  int *a, *b;
+  int *c, *d;
+  int x;
+};
+
+// CHECK: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x)
+struct large f_large(struct large x) {
+  x.a += *x.b;
+  x.b = 0;
+  return x;
+}
+





More information about the cfe-commits mailing list