merge pnacl's clang 3.4 merge
diff --git a/emscripten-version.txt b/emscripten-version.txt
new file mode 100644
index 0000000..9f67c6b
--- /dev/null
+++ b/emscripten-version.txt
@@ -0,0 +1,2 @@
+1.26.1
+
diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
index 1590cca..40aef2c 100644
--- a/include/clang/Basic/TargetCXXABI.h
+++ b/include/clang/Basic/TargetCXXABI.h
@@ -71,6 +71,10 @@
/// - guard variables are smaller.
GenericAArch64,
+ /// Emscripten uses the Itanium C++, with the exception that it uses
+ /// ARM-style pointers to member functions.
+ Emscripten,
+
/// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
/// compatible compilers).
///
@@ -104,6 +108,7 @@
case GenericAArch64:
case GenericItanium:
case GenericARM:
+ case Emscripten:
case iOS:
return true;
@@ -119,6 +124,7 @@
case GenericAArch64:
case GenericItanium:
case GenericARM:
+ case Emscripten:
case iOS:
return false;
@@ -128,6 +134,24 @@
llvm_unreachable("bad ABI kind");
}
+ /// \brief Are pointers to member functions differently aligned?
+ bool arePointersToMemberFunctionsAligned() const {
+ switch (getKind()) {
+ case Emscripten:
+ case GenericARM:
+ case GenericAArch64:
+ // ARM-style pointers to member functions put the discriminator in the
+ // this adjustment, so they don't require functions to have any special
+ // alignment.
+ return false;
+ case GenericItanium:
+ case iOS:
+ case Microsoft:
+ return true;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+
/// \brief Is the default C++ member function calling convention
/// the same as the default calling convention?
bool isMemberFunctionCCDefault() const {
@@ -199,6 +223,7 @@
case GenericAArch64:
case GenericItanium:
+ case Emscripten:
case iOS: // old iOS compilers did not follow this rule
case Microsoft:
return true;
@@ -245,6 +270,7 @@
case GenericItanium:
case GenericAArch64:
case GenericARM:
+ case Emscripten:
case iOS:
return UseTailPaddingUnlessPOD03;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a03cf9e..4cca0c4 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -668,6 +668,7 @@
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
return CreateARMCXXABI(*this);
+ case TargetCXXABI::Emscripten: // Same as Itanium at this level
case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
@@ -8001,6 +8002,7 @@
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
+ case TargetCXXABI::Emscripten:
case TargetCXXABI::iOS:
return ItaniumMangleContext::create(*this, getDiagnostics());
case TargetCXXABI::Microsoft:
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f1a6947..49a77d3 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -238,6 +238,45 @@
}
};
+// Emscripten target
+template<typename Target>
+class EmscriptenTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ // A macro for the platform.
+ Builder.defineMacro("__EMSCRIPTEN__");
+ // Earlier versions of Emscripten defined this, so we continue to define it
+ // for compatibility, for now. Users should ideally prefer __EMSCRIPTEN__.
+ Builder.defineMacro("EMSCRIPTEN");
+ // A common platform macro.
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ // Follow g++ convention and predefine _GNU_SOURCE for C++.
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ // Emscripten's software environment and the asm.js runtime aren't really
+ // Unix per se, but they're perhaps more Unix-like than what software
+ // expects when "unix" is *not* defined.
+ DefineStd(Builder, "unix", Opts);
+ }
+public:
+ explicit EmscriptenTargetInfo(const llvm::Triple &Triple)
+ : OSTargetInfo<Target>(Triple) {
+ // Emcripten currently does prepend a prefix to user labels, but this is
+ // handled outside of clang. TODO: Handling this within clang may be
+ // beneficial.
+ this->UserLabelPrefix = "";
+ this->MaxAtomicPromoteWidth = this->MaxAtomicInlineWidth = 32;
+
+ // Emscripten uses the Itanium ABI mostly, but it uses ARM-style pointers
+ // to member functions so that it can avoid having to align function
+ // addresses.
+ this->TheCXXABI.set(TargetCXXABI::Emscripten);
+ }
+};
+
// FreeBSD Target
template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
@@ -5291,6 +5330,85 @@
} // end anonymous namespace.
namespace {
+class AsmJSTargetInfo : public TargetInfo {
+public:
+ explicit AsmJSTargetInfo(const llvm::Triple &T) : TargetInfo(T) {
+ BigEndian = false;
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->UIntMaxType = TargetInfo::UnsignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ this->RegParmMax = 0; // Disallow regparm
+
+ // Set the native integer widths set to just i32, since that's currently
+ // the only integer type we can do arithmetic on without masking or
+ // splitting.
+ //
+ // Set the required alignment for 128-bit vectors to just 4 bytes, based on
+ // the direction suggested here:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=904913#c21
+ // We can still set the preferred alignment to 16 bytes though.
+ //
+ // Set the natural stack alignment to 16 bytes to accomodate 128-bit
+ // aligned vectors.
+ 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:128-n32-S128";
+ }
+
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ }
+ virtual void getArchDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__asmjs__");
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ getArchDefines(Opts, Builder);
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ }
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ // Reuse PNaCl's va_list lowering.
+ return TargetInfo::PNaClABIBuiltinVaList;
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = NULL;
+ NumNames = 0;
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = NULL;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ return false;
+ }
+ virtual const char *getClobbers() const {
+ return "";
+ }
+ virtual bool isCLZForZeroUndef() const {
+ // Today we do clz in software, so we just do the right thing. With ES6,
+ // we'll get Math.clz32, which is to be defined to do the right thing:
+ // http://esdiscuss.org/topic/rename-number-prototype-clz-to-math-clz#content-36
+ return false;
+ }
+};
+} // end anonymous namespace.
+
+namespace {
class PNaClTargetInfo : public TargetInfo {
public:
PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
@@ -5629,6 +5747,14 @@
return new Mips64ELTargetInfo(Triple);
}
+ case llvm::Triple::asmjs:
+ switch (os) {
+ case llvm::Triple::Emscripten:
+ return new EmscriptenTargetInfo<AsmJSTargetInfo>(Triple);
+ default:
+ return NULL;
+ }
+
case llvm::Triple::le32:
switch (os) {
case llvm::Triple::NaCl:
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f5fdfdb..1d0f3d2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -59,6 +59,7 @@
switch (CGM.getTarget().getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericARM:
+ case TargetCXXABI::Emscripten:
case TargetCXXABI::iOS:
case TargetCXXABI::GenericItanium:
return *CreateItaniumCXXABI(CGM);
@@ -730,9 +731,11 @@
if (alignment)
F->setAlignment(alignment);
- // C++ ABI requires 2-byte alignment for member functions.
- if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
- F->setAlignment(2);
+ if (getTarget().getCXXABI().arePointersToMemberFunctionsAligned()) {
+ // C++ ABI requires 2-byte alignment for member functions.
+ if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
+ F->setAlignment(2);
+ }
}
void CodeGenModule::SetCommonAttributes(const Decl *D,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0e8f31a..c9e52a8 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -255,6 +255,13 @@
return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
/* UseARMGuardVarABI = */ true);
+ case TargetCXXABI::Emscripten:
+ // Use ARM-style method pointers so that generated code
+ // does not assume anything about the alignment of function
+ // pointers.
+ return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
+ /* UseARMGuardVarABI = */ false);
+
case TargetCXXABI::GenericItanium:
if (CGM.getContext().getTargetInfo().getTriple().getArch()
== llvm::Triple::le32) {
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 5ecf205..9ed0dc0 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -427,6 +427,60 @@
}
//===----------------------------------------------------------------------===//
+// Emscripten ABI Implementation
+//
+// This is a very simple ABI that relies a lot on DefaultABIInfo.
+//===----------------------------------------------------------------------===//
+
+class EmscriptenABIInfo : public DefaultABIInfo {
+ public:
+ explicit EmscriptenABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType Ty) const;
+
+ // DefaultABIInfo's classifyReturnType and classifyArgumentType are
+ // non-virtual, but computeInfo is virtual, so we overload that.
+ virtual void computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type);
+ }
+};
+
+class EmscriptenTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ explicit EmscriptenTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new EmscriptenABIInfo(CGT)) {}
+};
+
+/// \brief Classify argument of given type \p Ty.
+ABIArgInfo EmscriptenABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ unsigned TypeAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return ABIArgInfo::getIndirect(TypeAlign, RAA == CGCXXABI::RAA_DirectInMemory);
+ return ABIArgInfo::getIndirect(TypeAlign);
+ }
+
+ // Otherwise just do the default thing.
+ return DefaultABIInfo::classifyArgumentType(Ty);
+}
+
+ABIArgInfo EmscriptenABIInfo::classifyReturnType(QualType RetTy) const {
+ if (isAggregateTypeForABI(RetTy)) {
+ // As an optimization, lower single-element structs to just return a
+ // regular value.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+ return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
+ }
+
+ // Otherwise just do the default thing.
+ return DefaultABIInfo::classifyReturnType(RetTy);
+}
+
+//===----------------------------------------------------------------------===//
// le32/PNaCl bitcode ABI Implementation
//
// This is a simplified version of the x86_32 ABI. Arguments and return values
@@ -5506,6 +5560,9 @@
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
+ case llvm::Triple::asmjs:
+ return *(TheTargetCodeGenInfo = new EmscriptenTargetCodeGenInfo(Types));
+
case llvm::Triple::le32:
return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types));
case llvm::Triple::mips:
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 5307910..977efe7 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1964,6 +1964,9 @@
case llvm::Triple::Win32:
TC = new toolchains::Windows(*this, Target, Args);
break;
+ case llvm::Triple::Emscripten:
+ TC = new toolchains::EmscriptenToolChain(*this, Target, Args);
+ break;
case llvm::Triple::MinGW32:
// FIXME: We need a MinGW toolchain. Fallthrough for now.
default:
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d9f1e73..479f2cc 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -1856,6 +1856,36 @@
return false;
}
+/// EmscriptenToolChain - A tool chain for the Emscripten C/C++ to JS compiler.
+
+EmscriptenToolChain::EmscriptenToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+}
+
+EmscriptenToolChain::~EmscriptenToolChain() {
+}
+
+bool EmscriptenToolChain::IsMathErrnoDefault() const {
+ return false;
+}
+
+bool EmscriptenToolChain::IsObjCNonFragileABIDefault() const {
+ return true;
+}
+
+bool EmscriptenToolChain::isPICDefault() const {
+ return false;
+}
+
+bool EmscriptenToolChain::isPIEDefault() const {
+ return false;
+}
+
+bool EmscriptenToolChain::isPICDefaultForced() const {
+ return false;
+}
+
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 50d3700..f46e2f6 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -647,6 +647,20 @@
bool isPICDefaultForced() const;
};
+/// EmscriptenToolChain - A tool chain for the Emscripten C/C++ to JS compiler.
+class LLVM_LIBRARY_VISIBILITY EmscriptenToolChain : public ToolChain {
+public:
+ EmscriptenToolChain(const Driver &D, const llvm::Triple& Triple,
+ const llvm::opt::ArgList &Args);
+ ~EmscriptenToolChain();
+
+ bool IsMathErrnoDefault() const;
+ bool IsObjCNonFragileABIDefault() const;
+ bool isPICDefault() const;
+ bool isPIEDefault() const;
+ bool isPICDefaultForced() const;
+};
+
class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
public:
Windows(const Driver &D, const llvm::Triple &Triple,
diff --git a/test/CodeGen/emscripten-arguments.c b/test/CodeGen/emscripten-arguments.c
new file mode 100644
index 0000000..afa0d9c
--- /dev/null
+++ b/test/CodeGen/emscripten-arguments.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple asmjs-unknown-emscripten %s -emit-llvm -o - | FileCheck %s
+
+// Basic argument/attribute tests for asmjs/Emscripten
+
+// CHECK: define void @f0(i32 %i, i32 %j, double %k)
+void f0(int i, long j, double k) {}
+
+typedef struct {
+ int aa;
+ int bb;
+} s1;
+// Structs should be passed byval and not split up
+// CHECK: define void @f1(%struct.s1* byval %i)
+void f1(s1 i) {}
+
+typedef struct {
+ int cc;
+} s2;
+// Structs should be returned sret and not simplified by the frontend
+// CHECK: define void @f2(%struct.s2* noalias sret %agg.result)
+s2 f2() {
+ s2 foo;
+ return foo;
+}
+
+// CHECK: define void @f3(i64 %i)
+void f3(long long i) {}
+
+// i8/i16 should be signext, i32 and higher should not
+// CHECK: define void @f4(i8 signext %a, i16 signext %b)
+void f4(char a, short b) {}
+
+// CHECK: define void @f5(i8 zeroext %a, i16 zeroext %b)
+void f5(unsigned char a, unsigned short b) {}
+
+
+enum my_enum {
+ ENUM1,
+ ENUM2,
+ ENUM3,
+};
+// Enums should be treated as the underlying i32
+// CHECK: define void @f6(i32 %a)
+void f6(enum my_enum a) {}
+
+union simple_union {
+ int a;
+ char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f7(%union.simple_union* byval %s)
+void f7(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 @f8(%struct.bitfield1* byval %bf1)
+void f8(bitfield1 bf1) {}
diff --git a/test/CodeGen/emscripten-regparm.c b/test/CodeGen/emscripten-regparm.c
new file mode 100644
index 0000000..20ffc9d
--- /dev/null
+++ b/test/CodeGen/emscripten-regparm.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -triple asmjs-unknown-emscripten %s -fsyntax-only -verify
+
+void __attribute__((regparm(2))) fc_f1(int i, int j, int k) {} // expected-error{{'regparm' is not valid on this platform}}
+
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index fb06fa7..f786800 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -6,6 +6,8 @@
// PNaCl uses the same representation of method pointers as ARM.
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=le32-unknown-nacl | FileCheck -check-prefix GLOBAL-ARM %s
+// Emscripten uses the same representation of method pointers as ARM.
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=asmjs-unknown-emscripten | FileCheck -check-prefix GLOBAL-ARM %s
struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
struct B { int b; virtual void g(); };
diff --git a/test/CodeGenCXX/static-init-emscripten.cpp b/test/CodeGenCXX/static-init-emscripten.cpp
new file mode 100644
index 0000000..b9d0271
--- /dev/null
+++ b/test/CodeGenCXX/static-init-emscripten.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm -triple=asmjs-unknown-emscripten -o - %s | FileCheck %s
+
+int f();
+
+// Test that Emscripten uses the Itanium/x86 ABI in which the static
+// variable's guard variable is tested via "load i8 and compare with
+// zero" rather than the ARM ABI which uses "load i32 and test the
+// bottom bit".
+void g() {
+ static int a = f();
+}
+// CHECK: load atomic i8* bitcast (i64* @_ZGVZ1gvE1a to i8*) acquire
+// CHECK-NEXT: %guard.uninitialized = icmp eq i8 %0, 0
+// CHECK-NEXT: br i1 %guard.uninitialized, label %init.check, label %init.end
diff --git a/test/Driver/asmjs-unknown-emscripten.cpp b/test/Driver/asmjs-unknown-emscripten.cpp
new file mode 100644
index 0000000..bf37734
--- /dev/null
+++ b/test/Driver/asmjs-unknown-emscripten.cpp
@@ -0,0 +1,136 @@
+// RUN: %clang -target asmjs-unknown-emscripten -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target asmjs-unknown-emscripten %s -emit-llvm -S -c -o - | FileCheck %s
+// RUN: %clang -target asmjs-unknown-emscripten %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+
+// ECHO: {{.*}} -cc1 {{.*}}asmjs-unknown-emscripten.c
+
+// Check platform defines
+#include <stdarg.h>
+#include <stddef.h>
+
+extern "C" {
+
+// CHECK: @align_c = global i32 1
+int align_c = __alignof(char);
+
+// CHECK: @align_s = global i32 2
+int align_s = __alignof(short);
+
+// CHECK: @align_i = global i32 4
+int align_i = __alignof(int);
+
+// CHECK: @align_l = global i32 4
+int align_l = __alignof(long);
+
+// CHECK: @align_ll = global i32 8
+int align_ll = __alignof(long long);
+
+// CHECK: @align_p = global i32 4
+int align_p = __alignof(void*);
+
+// CHECK: @align_f = global i32 4
+int align_f = __alignof(float);
+
+// CHECK: @align_d = global i32 8
+int align_d = __alignof(double);
+
+// CHECK: @align_ld = global i32 8
+int align_ld = __alignof(long double);
+
+// CHECK: @align_vl = global i32 4
+int align_vl = __alignof(va_list);
+
+// CHECK: __LITTLE_ENDIAN__defined
+#ifdef __LITTLE_ENDIAN__
+void __LITTLE_ENDIAN__defined() {}
+#endif
+
+// CHECK: __asmjs__defined
+#ifdef __asmjs__
+void __asmjs__defined() {}
+#endif
+
+// CHECK: __EMSCRIPTEN__defined
+#ifdef __EMSCRIPTEN__
+void __EMSCRIPTEN__defined() {}
+#endif
+
+// CHECK: unixdefined
+#ifdef unix
+void unixdefined() {}
+#endif
+
+// CHECK: _GNU_SOURCEdefined
+#ifdef _GNU_SOURCE
+void _GNU_SOURCEdefined() {}
+#endif
+
+// THREADS: _REENTRANTdefined
+// CHECK: _REENTRANTundefined
+#ifdef _REENTRANT
+void _REENTRANTdefined() {}
+#else
+void _REENTRANTundefined() {}
+#endif
+
+// Check types
+
+// CHECK: signext i8 @check_char()
+char check_char() { return 0; }
+
+// CHECK: signext i16 @check_short()
+short check_short() { return 0; }
+
+// CHECK: i32 @check_int()
+int check_int() { return 0; }
+
+// CHECK: i32 @check_long()
+long check_long() { return 0; }
+
+// CHECK: i64 @check_longlong()
+long long check_longlong() { return 0; }
+
+// CHECK: zeroext i8 @check_uchar()
+unsigned char check_uchar() { return 0; }
+
+// CHECK: zeroext i16 @check_ushort()
+unsigned short check_ushort() { return 0; }
+
+// CHECK: i32 @check_uint()
+unsigned int check_uint() { return 0; }
+
+// CHECK: i32 @check_ulong()
+unsigned long check_ulong() { return 0; }
+
+// CHECK: i64 @check_ulonglong()
+unsigned long long check_ulonglong() { return 0; }
+
+// CHECK: i32 @check_size_t()
+size_t check_size_t() { return 0; }
+
+// CHECK: float @check_float()
+float check_float() { return 0; }
+
+// CHECK: double @check_double()
+double check_double() { return 0; }
+
+// CHECK: double @check_longdouble()
+long double check_longdouble() { return 0; }
+
+}
+
+template<int> void Switch();
+template<> void Switch<4>();
+template<> void Switch<8>();
+template<> void Switch<16>();
+
+void check_pointer_size() {
+ // CHECK: SwitchILi4
+ Switch<sizeof(void*)>();
+
+ // CHECK: SwitchILi8
+ Switch<sizeof(long long)>();
+
+ // CHECK: SwitchILi16
+ Switch<sizeof(va_list)>();
+}