aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang-c/Index.h1
-rw-r--r--include/clang/AST/Type.h17
-rw-r--r--include/clang/Basic/Attr.td4
-rw-r--r--include/clang/Basic/Specifiers.h23
-rw-r--r--lib/AST/DumpXML.cpp1
-rw-r--r--lib/AST/Type.cpp1
-rw-r--r--lib/AST/TypePrinter.cpp4
-rw-r--r--lib/Basic/Targets.cpp5
-rw-r--r--lib/CodeGen/CGCall.cpp3
-rw-r--r--lib/CodeGen/TargetInfo.cpp76
-rw-r--r--lib/Sema/SemaDeclAttr.cpp7
-rw-r--r--lib/Sema/SemaType.cpp5
-rw-r--r--test/CodeGen/arm-pnaclcall.c33
-rw-r--r--test/CodeGen/x86_64-arguments-nacl.c28
-rw-r--r--test/Sema/callingconv.c1
-rw-r--r--tools/libclang/CXType.cpp1
16 files changed, 189 insertions, 21 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 9d7fb5c795..b122faa443 100644
--- a/include/clang-c/Index.h
+++ b/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/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 4936026f64..6900a7d40a 100644
--- a/include/clang/AST/Type.h
+++ b/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/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 67ef8be8fb..738b460b5a 100644
--- a/include/clang/Basic/Attr.td
+++ b/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/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index a5ca521a20..c82b8cb918 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/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/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 9a5e303606..700769d021 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -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");
}
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 218e6e9a4d..580ec50ca1 100644
--- a/lib/AST/Type.cpp
+++ b/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/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index dc58cacd03..2c00246301 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/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/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 79239d0bcf..2e6678bb89 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -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.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index a8483d70b2..2ef5bd27a0 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -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;
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 4ee9b97843..ad59fd2c90 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/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<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));
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 0b8dec314a..df4757e4d2 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 0b1dbd1542..a5c809d9f4 100644
--- a/lib/Sema/SemaType.cpp
+++ b/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/test/CodeGen/arm-pnaclcall.c b/test/CodeGen/arm-pnaclcall.c
new file mode 100644
index 0000000000..50259957eb
--- /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 d864a7511b..8f756caba7 100644
--- a/test/CodeGen/x86_64-arguments-nacl.c
+++ b/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/test/Sema/callingconv.c b/test/Sema/callingconv.c
index 76b5f2d0b9..266242d4a3 100644
--- a/test/Sema/callingconv.c
+++ b/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/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index f1bea30a9d..4e031d2d55 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -464,6 +464,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86Pascal);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
+ TCALLINGCONV(PnaclCall);
}
#undef TCALLINGCONV
}