]> granicus.if.org Git - clang/commitdiff
Add pnaclcall convention to Native Client targets.
authorDerek Schuff <dschuff@google.com>
Tue, 16 Oct 2012 22:30:41 +0000 (22:30 +0000)
committerDerek Schuff <dschuff@google.com>
Tue, 16 Oct 2012 22:30:41 +0000 (22:30 +0000)
Because PNaCl bitcode must be target-independent, it uses some
different bitcode representations from other targets (e.g. byval and
sret for structures). This means that without additional type
information, it cannot meet some native ABI requirements for some
targets (e.g. passing structures containing unions by value on
x86-64). To allow generation of code which uses the correct native
ABIs, we also support triples such as x86_64-nacl, which uses
target-dependent IR (as opposed to le32-nacl, which uses byval and
sret).

To allow interoperation between the two types of code, this patch adds
a calling convention attribute to be used in code compiled with the
target-dependent triple, which will generate code using the le32-style
bitcode. This calling convention does not need to be explicitly
supported in the backend because it determines bitcode representation
rather than native conventions (the backend just needs to undersand
how to handle byval and sret for the Native Client OS).

This patch implements __attribute__((pnaclcall)) to generate calls in
bitcode according to the le32 bitcode conventions, an attribute which
is accepted by any Native Client target, but issues a warning
otherwise.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166065 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
include/clang-c/Index.h
include/clang/AST/Type.h
include/clang/Basic/Attr.td
include/clang/Basic/Specifiers.h
lib/AST/DumpXML.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/TargetInfo.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaType.cpp
test/CodeGen/arm-pnaclcall.c [new file with mode: 0644]
test/CodeGen/x86_64-arguments-nacl.c
test/Sema/callingconv.c
tools/libclang/CXType.cpp

index 9d7fb5c79575adce44ac37acbecccc70782b8096..b122faa4431bde015fe1148cb8c3168a462e07f3 100644 (file)
@@ -2597,6 +2597,7 @@ enum CXCallingConv {
   CXCallingConv_X86Pascal = 5,
   CXCallingConv_AAPCS = 6,
   CXCallingConv_AAPCS_VFP = 7,
+  CXCallingConv_PnaclCall = 8,
 
   CXCallingConv_Invalid = 100,
   CXCallingConv_Unexposed = 200
index 4936026f643ff5eab086512c2a50312a774e61db..6900a7d40af9d1b3e8d124652dc5893a3bfb9d3b 100644 (file)
@@ -1269,7 +1269,7 @@ protected:
 
     /// Extra information which affects how the function is called, like
     /// regparm and the calling convention.
-    unsigned ExtInfo : 8;
+    unsigned ExtInfo : 9;
 
     /// TypeQuals - Used only by FunctionProtoType, put here to pack with the
     /// other bitfields.
@@ -2598,19 +2598,19 @@ class FunctionType : public Type {
   // * AST read and write
   // * Codegen
   class ExtInfo {
-    // Feel free to rearrange or add bits, but if you go over 8,
+    // Feel free to rearrange or add bits, but if you go over 9,
     // you'll need to adjust both the Bits field below and
     // Type::FunctionTypeBitfields.
 
     //   |  CC  |noreturn|produces|regparm|
-    //   |0 .. 2|   3    |    4   | 5 .. 7|
+    //   |0 .. 3|   4    |    5   | 6 .. 8|
     //
     // regparm is either 0 (no regparm attribute) or the regparm value+1.
-    enum { CallConvMask = 0x7 };
-    enum { NoReturnMask = 0x8 };
-    enum { ProducesResultMask = 0x10 };
+    enum { CallConvMask = 0xF };
+    enum { NoReturnMask = 0x10 };
+    enum { ProducesResultMask = 0x20 };
     enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
-           RegParmOffset = 5 }; // Assumed to be the last field
+           RegParmOffset = 6 }; // Assumed to be the last field
 
     uint16_t Bits;
 
@@ -3322,7 +3322,8 @@ public:
     attr_fastcall,
     attr_stdcall,
     attr_thiscall,
-    attr_pascal
+    attr_pascal,
+    attr_pnaclcall
   };
 
 private:
index 67ef8be8fb587627541b3ea71978c4660aa54ff7..738b460b5a45ae3b31ca00cf678213d7544ee3e0 100644 (file)
@@ -561,6 +561,10 @@ def Packed : InheritableAttr {
   let Spellings = [GNU<"packed">];
 }
 
+def PnaclCall : InheritableAttr {
+  let Spellings = [GNU<"pnaclcall">];
+}
+
 def Pcs : InheritableAttr {
   let Spellings = [GNU<"pcs">];
   let Args = [EnumArgument<"PCS", "PCSType",
index a5ca521a200de44f47ec4901b8ca6d1187cabf9f..c82b8cb918879859424ab058cef593aa759247a9 100644 (file)
@@ -176,17 +176,18 @@ namespace clang {
     ICIS_ListInit  ///< Direct list-initialization.
   };
 
-  /// \brief CallingConv - Specifies the calling convention that a function uses.\r
-  enum CallingConv {\r
-    CC_Default,\r
-    CC_C,           // __attribute__((cdecl))\r
-    CC_X86StdCall,  // __attribute__((stdcall))\r
-    CC_X86FastCall, // __attribute__((fastcall))\r
-    CC_X86ThisCall, // __attribute__((thiscall))\r
-    CC_X86Pascal,   // __attribute__((pascal))\r
-    CC_AAPCS,       // __attribute__((pcs("aapcs")))\r
-    CC_AAPCS_VFP    // __attribute__((pcs("aapcs-vfp")))\r
-  };\r
+  /// \brief CallingConv - Specifies the calling convention that a function uses.
+  enum CallingConv {
+    CC_Default,
+    CC_C,           // __attribute__((cdecl))
+    CC_X86StdCall,  // __attribute__((stdcall))
+    CC_X86FastCall, // __attribute__((fastcall))
+    CC_X86ThisCall, // __attribute__((thiscall))
+    CC_X86Pascal,   // __attribute__((pascal))
+    CC_AAPCS,       // __attribute__((pcs("aapcs")))
+    CC_AAPCS_VFP,   // __attribute__((pcs("aapcs-vfp")))
+    CC_PnaclCall    // __attribute__((pnaclcall))
+  };
 
 } // end namespace clang
 
index 9a5e303606f04bcd07297fbf1e3cd72f7ddcf230..700769d0216d8557189afbbc0fc3df6ffae018be 100644 (file)
@@ -920,6 +920,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
     case CC_X86Pascal: return set("cc", "x86_pascal");
     case CC_AAPCS: return set("cc", "aapcs");
     case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
+    case CC_PnaclCall: return set("cc", "pnaclcall");
     }
   }
 
index 218e6e9a4d1bca3073861470f0c084517c68de49..580ec50ca1f8eb64c67e5a7b147ae17a4bbbfba2 100644 (file)
@@ -1542,6 +1542,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
   case CC_X86Pascal: return "pascal";
   case CC_AAPCS: return "aapcs";
   case CC_AAPCS_VFP: return "aapcs-vfp";
+  case CC_PnaclCall: return "pnaclcall";
   }
 
   llvm_unreachable("Invalid calling convention.");
index dc58cacd038475e02fe40fca77807b56b22d89ec..2c00246301800b2c7c5bd62bdac683714f7f5b97 100644 (file)
@@ -647,6 +647,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
   case CC_AAPCS_VFP:
     OS << " __attribute__((pcs(\"aapcs-vfp\")))";
     break;
+  case CC_PnaclCall:
+    OS << " __attribute__((pnaclcall))";
+    break;
   }
   if (Info.getNoReturn())
     OS << " __attribute__((noreturn))";
@@ -1166,6 +1169,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
    OS << ')';
    break;
   }
+  case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
   }
   OS << "))";
 }
index 79239d0bcf6967f82a58169f6b6b7cd738f548fb..2e6678bb898e05cc7b965c499a563a9dd71e982b 100644 (file)
@@ -626,6 +626,11 @@ class NaClTargetInfo : public OSTargetInfo<Target> {
     this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
                               "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
   }
+  virtual typename Target::CallingConvCheckResult checkCallingConvention(
+      CallingConv CC) const {
+    return CC == CC_PnaclCall ? Target::CCCR_OK :
+        Target::checkCallingConvention(CC);
+  }
 };
 } // end anonymous namespace.
 
index a8483d70b2c438f37041ea884229f31ed641e93a..2ef5bd27a0a24add4b853b03a2d53e720dd0a364 100644 (file)
@@ -148,6 +148,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
   if (PcsAttr *PCS = D->getAttr<PcsAttr>())
     return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
 
+  if (D->hasAttr<PnaclCallAttr>())
+    return CC_PnaclCall;
+
   return CC_C;
 }
 
index 4ee9b97843d1f84e193a45cb4359db8cca52a013..ad59fd2c90860619ff624e4555442351067aa955 100644 (file)
@@ -2536,6 +2536,39 @@ llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
   return AddrTyped;
 }
 
+class NaClX86_64ABIInfo : public ABIInfo {
+ public:
+  NaClX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+      : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, HasAVX) {}
+  virtual void computeInfo(CGFunctionInfo &FI) const;
+  virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                 CodeGenFunction &CGF) const;
+ private:
+  PNaClABIInfo PInfo;  // Used for generating calls with pnaclcall callingconv.
+  X86_64ABIInfo NInfo; // Used for everything else.
+};
+
+class NaClX86_64TargetCodeGenInfo : public TargetCodeGenInfo  {
+ public:
+  NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+      : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)) {}
+};
+
+void NaClX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+  if (FI.getASTCallingConvention() == CC_PnaclCall)
+    PInfo.computeInfo(FI);
+  else
+    NInfo.computeInfo(FI);
+}
+
+llvm::Value *NaClX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                          CodeGenFunction &CGF) const {
+  // Always use the native convention; calling pnacl-style varargs functions
+  // is unuspported.
+  return NInfo.EmitVAArg(VAListAddr, Ty, CGF);
+}
+
+
 // PowerPC-32
 
 namespace {
@@ -3268,6 +3301,38 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
   return AddrTyped;
 }
 
+class NaClARMABIInfo : public ABIInfo {
+ public:
+  NaClARMABIInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+      : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, Kind) {}
+  virtual void computeInfo(CGFunctionInfo &FI) const;
+  virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                 CodeGenFunction &CGF) const;
+ private:
+  PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
+  ARMABIInfo NInfo; // Used for everything else.
+};
+
+class NaClARMTargetCodeGenInfo : public TargetCodeGenInfo  {
+ public:
+  NaClARMTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+      : TargetCodeGenInfo(new NaClARMABIInfo(CGT, Kind)) {}
+};
+
+void NaClARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
+  if (FI.getASTCallingConvention() == CC_PnaclCall)
+    PInfo.computeInfo(FI);
+  else
+    static_cast<const ABIInfo&>(NInfo).computeInfo(FI);
+}
+
+llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                       CodeGenFunction &CGF) const {
+  // Always use the native convention; calling pnacl-style varargs functions
+  // is unsupported.
+  return static_cast<const ABIInfo&>(NInfo).EmitVAArg(VAListAddr, Ty, CGF);
+}
+
 //===----------------------------------------------------------------------===//
 // NVPTX ABI Implementation
 //===----------------------------------------------------------------------===//
@@ -4077,7 +4142,14 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
       else if (CodeGenOpts.FloatABI == "hard")
         Kind = ARMABIInfo::AAPCS_VFP;
 
-      return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind));
+      switch (Triple.getOS()) {
+        case llvm::Triple::NativeClient:
+          return *(TheTargetCodeGenInfo =
+                   new NaClARMTargetCodeGenInfo(Types, Kind));
+        default:
+          return *(TheTargetCodeGenInfo =
+                   new ARMTargetCodeGenInfo(Types, Kind));
+      }
     }
 
   case llvm::Triple::ppc:
@@ -4143,6 +4215,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
     case llvm::Triple::MinGW32:
     case llvm::Triple::Cygwin:
       return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
+    case llvm::Triple::NativeClient:
+      return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
     default:
       return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
                                                                   HasAVX));
index 0b8dec314a189260b71628b00ae22c38e98561c2..df4757e4d27b7e38d06561793209f11b220f413c 100644 (file)
@@ -3582,7 +3582,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
     }
 
     D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
+    return;
   }
+  case AttributeList::AT_PnaclCall:
+    D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context));
+    return;
+
   default:
     llvm_unreachable("unexpected attribute kind");
   }
@@ -3635,6 +3640,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
     Diag(attr.getLoc(), diag::err_invalid_pcs);
     return true;
   }
+  case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break;
   default: llvm_unreachable("unexpected attribute kind");
   }
 
@@ -4396,6 +4402,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
   case AttributeList::AT_ThisCall:
   case AttributeList::AT_Pascal:
   case AttributeList::AT_Pcs:
+  case AttributeList::AT_PnaclCall:
     handleCallConvAttr(S, D, Attr);
     break;
   case AttributeList::AT_OpenCLKernel:
index 0b1dbd1542ad02b05e473a39d6b170c0bdb66a5c..a5c809d9f486cdb361bb13852ef890d3cb5e60d7 100644 (file)
@@ -105,7 +105,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
     case AttributeList::AT_ThisCall: \
     case AttributeList::AT_Pascal: \
     case AttributeList::AT_Regparm: \
-    case AttributeList::AT_Pcs \
+    case AttributeList::AT_Pcs: \
+    case AttributeList::AT_PnaclCall \
 
 namespace {
   /// An object which stores processing state for the entire
@@ -3004,6 +3005,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
     return AttributeList::AT_Pascal;
   case AttributedType::attr_pcs:
     return AttributeList::AT_Pcs;
+  case AttributedType::attr_pnaclcall:
+    return AttributeList::AT_PnaclCall;
   }
   llvm_unreachable("unexpected attribute kind!");
 }
diff --git a/test/CodeGen/arm-pnaclcall.c b/test/CodeGen/arm-pnaclcall.c
new file mode 100644 (file)
index 0000000..5025995
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple armv7-unknown-nacl-gnueabi \
+// RUN:   -ffreestanding -mfloat-abi hard -target-cpu cortex-a8 \
+// RUN:   -emit-llvm -w -o - %s | FileCheck %s
+
+// Test that functions with pnaclcall attribute generate portable bitcode
+// like the le32 arch target
+
+typedef struct {
+  int a;
+  int b;
+} s1;
+// CHECK: define i32 @f48(%struct.s1* byval %s)
+int __attribute__((pnaclcall)) f48(s1 s) { return s.a; }
+
+// CHECK: define void @f49(%struct.s1* noalias sret %agg.result)
+s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
+
+union simple_union {
+  int a;
+  char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f50(%union.simple_union* byval %s)
+void __attribute__((pnaclcall)) f50(union simple_union s) {}
+
+typedef struct {
+  int b4 : 4;
+  int b3 : 3;
+  int b8 : 8;
+} bitfield1;
+// Bitfields should be passed as byval structs
+// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
index d864a7511b023d5bf39ed53a69a0f5a28e46ce0f..8f756caba7577cd64732ba1589f6d4315e9c2620 100644 (file)
@@ -90,3 +90,31 @@ void f9122143()
 {
   func(ss);
 }
+
+
+typedef struct {
+  int a;
+  int b;
+} s1;
+// CHECK: define i32 @f48(%struct.s1* byval %s)
+int __attribute__((pnaclcall)) f48(s1 s) { return s.a; }
+
+// CHECK: define void @f49(%struct.s1* noalias sret %agg.result)
+s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
+
+union simple_union {
+  int a;
+  char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f50(%union.simple_union* byval %s)
+void __attribute__((pnaclcall)) f50(union simple_union s) {}
+
+typedef struct {
+  int b4 : 4;
+  int b3 : 3;
+  int b8 : 8;
+} bitfield1;
+// Bitfields should be passed as byval structs
+// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
index 76b5f2d0b9b5263af8f85224a6b1eb38c1cc6ad7..266242d4a3a9a725498e20d24c391ba3ded3b9c6 100644 (file)
@@ -53,3 +53,4 @@ void __attribute__((cdecl)) ctest3() {}
 typedef __attribute__((stdcall)) void (*PROC)();
 PROC __attribute__((cdecl)) ctest4(const char *x) {}
 
+void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
index f1bea30a9d2bc9826cd38a06ac55e9d6393fc023..4e031d2d55069815341a58225ff4a3630da94c88 100644 (file)
@@ -464,6 +464,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
       TCALLINGCONV(X86Pascal);
       TCALLINGCONV(AAPCS);
       TCALLINGCONV(AAPCS_VFP);
+      TCALLINGCONV(PnaclCall);
     }
 #undef TCALLINGCONV
   }