Add pnaclcall convention to Native Client targets.

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
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 9d7fb5c..b122faa 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -2597,6 +2597,7 @@
   CXCallingConv_X86Pascal = 5,
   CXCallingConv_AAPCS = 6,
   CXCallingConv_AAPCS_VFP = 7,
+  CXCallingConv_PnaclCall = 8,
 
   CXCallingConv_Invalid = 100,
   CXCallingConv_Unexposed = 200
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 4936026..6900a7d 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1269,7 +1269,7 @@
 
     /// 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 @@
   // * 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 @@
     attr_fastcall,
     attr_stdcall,
     attr_thiscall,
-    attr_pascal
+    attr_pascal,
+    attr_pnaclcall
   };
 
 private:
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 67ef8be..738b460 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -561,6 +561,10 @@
   let Spellings = [GNU<"packed">];
 }
 
+def PnaclCall : InheritableAttr {
+  let Spellings = [GNU<"pnaclcall">];
+}
+
 def Pcs : InheritableAttr {
   let Spellings = [GNU<"pcs">];
   let Args = [EnumArgument<"PCS", "PCSType",
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index a5ca521..c82b8cb 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -176,17 +176,18 @@
     ICIS_ListInit  ///< Direct list-initialization.
   };
 
-  /// \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")))

-  };

+  /// \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
 
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 9a5e303..700769d 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -920,6 +920,7 @@
     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");
     }
   }
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 218e6e9..580ec50 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1542,6 +1542,7 @@
   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.");
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index dc58cac..2c00246 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -647,6 +647,9 @@
   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 @@
    OS << ')';
    break;
   }
+  case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
   }
   OS << "))";
 }
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 79239d0..2e6678b 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -626,6 +626,11 @@
     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.
 
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index a8483d7..2ef5bd2 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -148,6 +148,9 @@
   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;
 }
 
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 4ee9b97..ad59fd2 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -2536,6 +2536,39 @@
   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 @@
   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 @@
       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 @@
     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));
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 0b8dec3..df4757e 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -3582,7 +3582,12 @@
     }
 
     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 @@
     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 @@
   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:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 0b1dbd1..a5c809d 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -105,7 +105,8 @@
     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 @@
     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
index 0000000..5025995
--- /dev/null
+++ b/test/CodeGen/arm-pnaclcall.c
@@ -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) {}
diff --git a/test/CodeGen/x86_64-arguments-nacl.c b/test/CodeGen/x86_64-arguments-nacl.c
index d864a75..8f756ca 100644
--- a/test/CodeGen/x86_64-arguments-nacl.c
+++ b/test/CodeGen/x86_64-arguments-nacl.c
@@ -90,3 +90,31 @@
 {
   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) {}
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index 76b5f2d..266242d 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -53,3 +53,4 @@
 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}}
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index f1bea30..4e031d2 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -464,6 +464,7 @@
       TCALLINGCONV(X86Pascal);
       TCALLINGCONV(AAPCS);
       TCALLINGCONV(AAPCS_VFP);
+      TCALLINGCONV(PnaclCall);
     }
 #undef TCALLINGCONV
   }