Merge remote-tracking branch 'origin/master' into bradnelson/pnacl-in-pnacl
diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
index 5669d2a..caf3b0f 100644
--- a/include/clang/Basic/TargetCXXABI.h
+++ b/include/clang/Basic/TargetCXXABI.h
@@ -79,6 +79,12 @@
     ///   - guard variables  are smaller.
     GenericAArch64,
 
+    // @LOCALMOD-START Emscripten
+    /// Emscripten uses the Itanium C++, with the exception that it uses
+    /// ARM-style pointers to member functions.
+    Emscripten,
+    // @LOCALMOD-END Emscripten
+
     /// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
     /// compatible compilers).
     ///
@@ -112,6 +118,7 @@
     case GenericAArch64:
     case GenericItanium:
     case GenericARM:
+    case Emscripten: // @LOCALMOD Emscripten
     case iOS:
     case iOS64:
       return true;
@@ -128,6 +135,7 @@
     case GenericAArch64:
     case GenericItanium:
     case GenericARM:
+    case Emscripten: // @LOCALMOD Emscripten
     case iOS:
     case iOS64:
       return false;
@@ -138,6 +146,29 @@
     llvm_unreachable("bad ABI kind");
   }
 
+  // @LOCALMOD-START Emscripten
+  /// \brief Are pointers to member functions differently aligned?
+  bool arePointersToMemberFunctionsAligned() const {
+    switch (getKind()) {
+    case Emscripten:
+      // Emscripten uses table indices for function pointers and therefore
+      // doesn't require alignment.
+      return false;
+    case GenericARM:
+    case GenericAArch64:
+      // TODO: ARM-style pointers to member functions put the discriminator in
+      //       the this adjustment, so they don't require functions to have any
+      //       special alignment and could therefore also return false.
+    case GenericItanium:
+    case iOS:
+    case iOS64:
+    case Microsoft:
+      return true;
+    }
+    llvm_unreachable("bad ABI kind");
+  }
+  // @LOCALMOD-END Emscripten
+
   /// \brief Is the default C++ member function calling convention
   /// the same as the default calling convention?
   bool isMemberFunctionCCDefault() const {
@@ -210,6 +241,7 @@
 
     case GenericAArch64:
     case GenericItanium:
+    case Emscripten: // @LOCALMOD Emscripten
     case iOS:   // old iOS compilers did not follow this rule
     case Microsoft:
       return true;
@@ -256,6 +288,7 @@
     case GenericItanium:
     case GenericAArch64:
     case GenericARM:
+    case Emscripten: // @LOCALMOD Emscripten
     case iOS:
       return UseTailPaddingUnlessPOD03;
 
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a0b8017..8894683 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -681,6 +681,7 @@
   case TargetCXXABI::GenericARM: // Same as Itanium at this level
   case TargetCXXABI::iOS:
   case TargetCXXABI::iOS64:
+  case TargetCXXABI::Emscripten: // @LOCALMOD Emscripten
   case TargetCXXABI::GenericAArch64:
   case TargetCXXABI::GenericItanium:
     return CreateItaniumCXXABI(*this);
@@ -8064,6 +8065,7 @@
   case TargetCXXABI::GenericAArch64:
   case TargetCXXABI::GenericItanium:
   case TargetCXXABI::GenericARM:
+  case TargetCXXABI::Emscripten: // @LOCALMOD Emscripten
   case TargetCXXABI::iOS:
   case TargetCXXABI::iOS64:
     return ItaniumMangleContext::create(*this, getDiagnostics());
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 3c4aa75..e71819a 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -252,6 +252,48 @@
   }
 };
 
+// @LOCALMOD-START Emscripten
+// Emscripten target
+template <typename Target>
+class EmscriptenTargetInfo : public OSTargetInfo<Target> {
+protected:
+  void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+                    MacroBuilder &Builder) const override {
+    // 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);
+  }
+};
+// @LOCALMOD-END Emscripten
+
 // FreeBSD Target
 template<typename Target>
 class FreeBSDTargetInfo : public OSTargetInfo<Target> {
@@ -5988,6 +6030,72 @@
 };
 } // end anonymous namespace.
 
+// @LOCALMOD-START Emscripten
+namespace {
+class AsmJSTargetInfo : public TargetInfo {
+public:
+  explicit AsmJSTargetInfo(const llvm::Triple &T) : TargetInfo(T) {
+    BigEndian = false;
+    NoAsmVariants = true;
+    LongAlign = LongWidth = 32;
+    PointerAlign = PointerWidth = 32;
+    IntMaxType = Int64Type = TargetInfo::SignedLongLong;
+    DoubleAlign = 64;
+    LongDoubleWidth = LongDoubleAlign = 64;
+    SizeType = TargetInfo::UnsignedInt;
+    PtrDiffType = TargetInfo::SignedInt;
+    IntPtrType = TargetInfo::SignedInt;
+    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-p:32:32-i64:64-v128:32:128-n32-S128";
+  }
+
+  void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {}
+  void getTargetDefines(const LangOptions &Opts,
+                        MacroBuilder &Builder) const override {
+    defineCPUMacros(Builder, "asmjs", /*Tuning=*/false);
+  }
+  void getTargetBuiltins(const Builtin::Info *&Records,
+                         unsigned &NumRecords) const override {}
+  BuiltinVaListKind getBuiltinVaListKind() const override {
+    // Reuse PNaCl's va_list lowering.
+    return TargetInfo::PNaClABIBuiltinVaList;
+  }
+  void getGCCRegNames(const char *const *&Names,
+                      unsigned &NumNames) const override {
+    Names = nullptr;
+    NumNames = 0;
+  }
+  void getGCCRegAliases(const GCCRegAlias *&Aliases,
+                        unsigned &NumAliases) const override {
+    Aliases = nullptr;
+    NumAliases = 0;
+  }
+  bool validateAsmConstraint(const char *&Name,
+                             TargetInfo::ConstraintInfo &Info) const override {
+    return false;
+  }
+  const char *getClobbers() const override { return ""; }
+  bool isCLZForZeroUndef() const override {
+    // 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.
+// @LOCALMOD-END Emscripten
+
 namespace {
 class PNaClTargetInfo : public TargetInfo {
 public:
@@ -6428,6 +6536,16 @@
       return new Mips64ELTargetInfo(Triple);
     }
 
+  // @LOCALMOD-START Emscripten
+  case llvm::Triple::asmjs:
+    switch (os) {
+      case llvm::Triple::Emscripten:
+        return new EmscriptenTargetInfo<AsmJSTargetInfo>(Triple);
+      default:
+        return nullptr;
+    }
+  // @LOCALMOD-END Emscripten
+
   case llvm::Triple::le32:
     switch (os) {
       case llvm::Triple::NaCl:
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index b6f1f4c..dea71c8 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -62,6 +62,7 @@
   switch (CGM.getTarget().getCXXABI().getKind()) {
   case TargetCXXABI::GenericAArch64:
   case TargetCXXABI::GenericARM:
+  case TargetCXXABI::Emscripten: // @LOCALMOD Emscripten
   case TargetCXXABI::iOS:
   case TargetCXXABI::iOS64:
   case TargetCXXABI::GenericItanium:
@@ -787,9 +788,13 @@
   if (alignment)
     F->setAlignment(alignment);
 
-  // C++ ABI requires 2-byte alignment for member functions.
-  if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
-    F->setAlignment(2);
+  // @LOCALMOD-START Emscripten
+  if (getTarget().getCXXABI().arePointersToMemberFunctionsAligned()) {
+    // C++ ABI requires 2-byte alignment for member functions.
+    if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
+      F->setAlignment(2);
+  }
+  // @LOCALMOD-END Emscripten
 }
 
 void CodeGenModule::SetCommonAttributes(const Decl *D,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index fd299d1..66743d2 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -339,6 +339,14 @@
     return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
                              /* UseARMGuardVarABI = */ true);
 
+  // @LOCALMOD-START Emscripten
+  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);
+  // @LOCALMOD-END Emscripten
+
   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 e37648e..487887f 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -425,6 +425,63 @@
           ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
 }
 
+// @LOCALMOD-START Emscripten
+//===----------------------------------------------------------------------===//
+// 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.
+  void computeInfo(CGFunctionInfo &FI) const override {
+    FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+    for (auto &Arg : FI.arguments())
+      Arg.info = classifyArgumentType(Arg.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 (auto 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);
+}
+// @LOCALMOD-END Emscripten
+
 //===----------------------------------------------------------------------===//
 // le32/PNaCl bitcode ABI Implementation
 //
@@ -7028,6 +7085,11 @@
   default:
     return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
 
+  // @LOCALMOD-START Emscripten
+  case llvm::Triple::asmjs:
+    return *(TheTargetCodeGenInfo = new EmscriptenTargetCodeGenInfo(Types));
+  // @LOCALMOD-END Emscripten
+
   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 251f8ac..a7a183d 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -2014,6 +2014,11 @@
       else
         TC = new toolchains::Linux(*this, Target, Args);
       break;
+    // @LOCALMOD-START Emscripten
+    case llvm::Triple::Emscripten:
+      TC = new toolchains::EmscriptenToolChain(*this, Target, Args);
+      break;
+    // @LOCALMOD-END Emscripten
     // @LOCALMOD-START
     case llvm::Triple::NaCl:
       TC = new toolchains::NaCl_TC(*this, Target, Args);
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 467072e..7e2be4a 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -715,6 +715,23 @@
   static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
 };
 
+// @LOCALMOD-START Emscripten
+/// EmscriptenToolChain - A toolchain 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)
+      : ToolChain(D, Triple, Args) {}
+  ~EmscriptenToolChain() override {}
+
+  bool IsMathErrnoDefault() const override { return false; }
+  bool IsObjCNonFragileABIDefault() const override { return true; }
+  bool isPICDefault() const override { return false; }
+  bool isPIEDefault() const override { return false; }
+  bool isPICDefaultForced() const override { return false; }
+};
+// @LOCALMOD-END Emscripten
+
 // @LOCALMOD-START
 class LLVM_LIBRARY_VISIBILITY NaCl_TC : public Generic_ELF {
 public:
diff --git a/test/CodeGen/emscripten-arguments.c b/test/CodeGen/emscripten-arguments.c
new file mode 100644
index 0000000..b90164b
--- /dev/null
+++ b/test/CodeGen/emscripten-arguments.c
@@ -0,0 +1,79 @@
+// 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, i64 %k, double %l, double %m)
+void f0(int i, long j, long long k, double l, long double m) {}
+
+typedef struct {
+  int aa;
+  int bb;
+} s1;
+// Structs should be passed byval and not split up.
+// CHECK: define void @f1(%struct.s1* byval align 4 %i)
+void f1(s1 i) {}
+
+typedef struct {
+  int cc;
+} s2;
+// Single-element structs should be returned as the one element.
+// CHECK: define i32 @f2()
+s2 f2() {
+  s2 foo;
+  return foo;
+}
+
+typedef struct {
+  int cc;
+  int dd;
+} s3;
+// Structs should be returned sret and not simplified by the frontend.
+// CHECK: define void @f3(%struct.s3* noalias sret %agg.result)
+s3 f3() {
+  s3 foo;
+  return foo;
+}
+
+// CHECK: define void @f4(i64 %i)
+void f4(long long i) {}
+
+// i8/i16 should be signext, i32 and higher should not.
+// CHECK: define void @f5(i8 signext %a, i16 signext %b)
+void f5(char a, short b) {}
+
+// CHECK: define void @f6(i8 zeroext %a, i16 zeroext %b)
+void f6(unsigned char a, unsigned short b) {}
+
+
+enum my_enum {
+  ENUM1,
+  ENUM2,
+  ENUM3,
+};
+// Enums should be treated as the underlying i32.
+// CHECK: define void @f7(i32 %a)
+void f7(enum my_enum a) {}
+
+enum my_big_enum {
+  ENUM4 = 0xFFFFFFFFFFFFFFFF,
+};
+// Big enums should be treated as the underlying i64.
+// CHECK: define void @f8(i64 %a)
+void f8(enum my_big_enum a) {}
+
+union simple_union {
+  int a;
+  char b;
+};
+// Unions should be passed as byval structs.
+// CHECK: define void @f9(%union.simple_union* byval align 4 %s)
+void f9(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 @f10(%struct.bitfield1* byval align 4 %bf1)
+void f10(bitfield1 bf1) {}
diff --git a/test/CodeGen/emscripten-regparm.c b/test/CodeGen/emscripten-regparm.c
new file mode 100644
index 0000000..14c3ae5
--- /dev/null
+++ b/test/CodeGen/emscripten-regparm.c
@@ -0,0 +1,3 @@
+// 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/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 242fded..32ea9a7 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -78,6 +78,10 @@
 // RUN: FileCheck %s -check-prefix=LE32-NACL
 // LE32-NACL: target datalayout = "e-p:32:32-i64:64-n32"
 
+// RUN: %clang_cc1 -triple asmjs-emscripten -o - -emit-llvm %s | \
+// RUN: FileCheck %s -check-prefix=ASMJS-EMSCRIPTEN
+// ASMJS-EMSCRIPTEN: target datalayout = "e-p:32:32-i64:64-v128:32:128-n32-S128"
+
 // RUN: %clang_cc1 -triple powerpc-unknown -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=PPC
 // PPC: target datalayout = "E-m:e-p:32:32-i64:64-n32"
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..8a8df4c
--- /dev/null
+++ b/test/Driver/asmjs-unknown-emscripten.cpp
@@ -0,0 +1,141 @@
+// RUN: %clang -target asmjs-unknown-emscripten -### %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
+
+typedef __builtin_va_list va_list;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+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: EMSCRIPTENdefined
+#ifdef EMSCRIPTEN
+void EMSCRIPTENdefined() {}
+#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)>();
+}