diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 9d7fb5c79575..b122faa4431b 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -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 diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 4936026f643f..6900a7d40af9 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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: diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 67ef8be8fb58..738b460b5a45 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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", diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index a5ca521a200d..c82b8cb91887 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -176,17 +176,18 @@ namespace clang { 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/clang/lib/AST/DumpXML.cpp b/clang/lib/AST/DumpXML.cpp index 9a5e303606f0..700769d0216d 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/lib/AST/DumpXML.cpp @@ -920,6 +920,7 @@ struct XMLDumper : public XMLDeclVisitor, 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/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 218e6e9a4d1b..580ec50ca1f8 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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."); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index dc58cacd0384..2c0024630180 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -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 << "))"; } diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 79239d0bcf69..2e6678bb898e 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -626,6 +626,11 @@ class NaClTargetInfo : public OSTargetInfo { 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/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a8483d70b2c4..2ef5bd27a0a2 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -148,6 +148,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { if (PcsAttr *PCS = D->getAttr()) return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP); + if (D->hasAttr()) + return CC_PnaclCall; + return CC_C; } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 4ee9b97843d1..ad59fd2c9086 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -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(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(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)); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0b8dec314a18..df4757e4d27b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 0b1dbd1542ad..a5c809d9f486 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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/clang/test/CodeGen/arm-pnaclcall.c b/clang/test/CodeGen/arm-pnaclcall.c new file mode 100644 index 000000000000..50259957eb15 --- /dev/null +++ b/clang/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/clang/test/CodeGen/x86_64-arguments-nacl.c b/clang/test/CodeGen/x86_64-arguments-nacl.c index d864a7511b02..8f756caba757 100644 --- a/clang/test/CodeGen/x86_64-arguments-nacl.c +++ b/clang/test/CodeGen/x86_64-arguments-nacl.c @@ -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) {} diff --git a/clang/test/Sema/callingconv.c b/clang/test/Sema/callingconv.c index 76b5f2d0b9b5..266242d4a3a9 100644 --- a/clang/test/Sema/callingconv.c +++ b/clang/test/Sema/callingconv.c @@ -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}} diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index f1bea30a9d2b..4e031d2d5506 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -464,6 +464,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(X86Pascal); TCALLINGCONV(AAPCS); TCALLINGCONV(AAPCS_VFP); + TCALLINGCONV(PnaclCall); } #undef TCALLINGCONV }