17 changes: 17 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,9 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
return EmitNVPTXBuiltinExpr(BuiltinID, E);
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return EmitWebAssemblyBuiltinExpr(BuiltinID, E);
default:
return nullptr;
}
Expand Down Expand Up @@ -7032,3 +7035,17 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
return nullptr;
}
}

Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
switch (BuiltinID) {
case WebAssembly::BI__builtin_wasm_page_size: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_page_size, ResultType);
return Builder.CreateCall(Callee);
}

default:
return nullptr;
}
}
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2626,6 +2626,8 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
const CallExpr *E);

llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
case TargetCXXABI::iOS64:
case TargetCXXABI::GenericMIPS:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::WebAssembly:
return CreateItaniumCXXABI(CGM);
case TargetCXXABI::Microsoft:
return CreateMicrosoftCXXABI(CGM);
Expand Down Expand Up @@ -819,9 +820,14 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (alignment)
F->setAlignment(alignment);

// C++ ABI requires 2-byte alignment for member functions.
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
F->setAlignment(2);
// Some C++ ABIs require 2-byte alignment for member functions, in order to
// reserve a bit for differentiating between virtual and non-virtual member
// functions. If the current target's C++ ABI requires this and this is a
// member function, set its alignment accordingly.
if (getTarget().getCXXABI().areMemberFunctionsAligned()) {
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
F->setAlignment(2);
}
}

void CodeGenModule::SetCommonAttributes(const Decl *D,
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,20 @@ class iOS64CXXABI : public ARMCXXABI {
// ARM64 libraries are prepared for non-unique RTTI.
bool shouldRTTIBeUnique() const override { return false; }
};

class WebAssemblyCXXABI final : public ItaniumCXXABI {
public:
explicit WebAssemblyCXXABI(CodeGen::CodeGenModule &CGM)
: ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true,
/*UseARMGuardVarABI=*/true) {}

private:
bool HasThisReturn(GlobalDecl GD) const override {
return isa<CXXConstructorDecl>(GD.getDecl()) ||
(isa<CXXDestructorDecl>(GD.getDecl()) &&
GD.getDtorType() != Dtor_Deleting);
}
};
}

CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
Expand All @@ -377,6 +391,9 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
case TargetCXXABI::GenericMIPS:
return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true);

case TargetCXXABI::WebAssembly:
return new WebAssemblyCXXABI(CGM);

case TargetCXXABI::GenericItanium:
if (CGM.getContext().getTargetInfo().getTriple().getArch()
== llvm::Triple::le32) {
Expand Down
81 changes: 81 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,83 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}

//===----------------------------------------------------------------------===//
// WebAssembly ABI Implementation
//
// This is a very simple ABI that relies a lot on DefaultABIInfo.
//===----------------------------------------------------------------------===//

class WebAssemblyABIInfo final : public DefaultABIInfo {
public:
explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT)
: DefaultABIInfo(CGT) {}

private:
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 {
if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &Arg : FI.arguments())
Arg.info = classifyArgumentType(Arg.type);
}
};

class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
public:
explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: TargetCodeGenInfo(new WebAssemblyABIInfo(CGT)) {}
};

/// \brief Classify argument of given type \p Ty.
ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const {
Ty = useFirstFieldIfTransparentUnion(Ty);

if (isAggregateTypeForABI(Ty)) {
// Records with non-trivial destructors/copy-constructors should not be
// passed by value.
unsigned TypeAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(TypeAlign,
RAA == CGCXXABI::RAA_DirectInMemory);
// Ignore empty structs/unions.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
// Lower single-element structs to just pass a regular value. TODO: We
// could do reasonable-size multiple-element structs too, using getExpand(),
// though watch out for things like bitfields.
if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
return ABIArgInfo::getIndirect(TypeAlign);
}

// Otherwise just do the default thing.
return DefaultABIInfo::classifyArgumentType(Ty);
}

ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
if (isAggregateTypeForABI(RetTy)) {
// Records with non-trivial destructors/copy-constructors should not be
// returned by value.
if (!getRecordArgABI(RetTy, getCXXABI())) {
// Ignore empty structs/unions.
if (isEmptyRecord(getContext(), RetTy, true))
return ABIArgInfo::getIgnore();
// Lower single-element structs to just return a regular value. TODO: We
// could do reasonable-size multiple-element structs too, using
// ABIArgInfo::getDirect().
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
//
Expand Down Expand Up @@ -7155,6 +7232,10 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types, Kind));
}

case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return *(TheTargetCodeGenInfo = new WebAssemblyTargetCodeGenInfo(Types));

case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2265,6 +2265,10 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::shave:
TC = new toolchains::SHAVEToolChain(*this, Target, Args);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
TC = new toolchains::WebAssembly(*this, Target, Args);
break;
default:
if (Target.isOSBinFormatELF())
TC = new toolchains::Generic_ELF(*this, Target, Args);
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,13 @@ ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const {

bool ToolChain::isThreadModelSupported(const StringRef Model) const {
if (Model == "single") {
// FIXME: 'single' is only supported on ARM so far.
// FIXME: 'single' is only supported on ARM and WebAssembly so far.
return Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::armeb ||
Triple.getArch() == llvm::Triple::thumb ||
Triple.getArch() == llvm::Triple::thumbeb;
Triple.getArch() == llvm::Triple::thumbeb ||
Triple.getArch() == llvm::Triple::wasm32 ||
Triple.getArch() == llvm::Triple::wasm64;
} else if (Model == "posix")
return true;

Expand Down
29 changes: 29 additions & 0 deletions clang/lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3937,3 +3937,32 @@ Tool *SHAVEToolChain::buildAssembler() const {
// assembler to the driver, except not the way it expects.
llvm_unreachable("SHAVEToolChain can't buildAssembler");
}

bool WebAssembly::IsMathErrnoDefault() const { return false; }

bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }

bool WebAssembly::UseObjCMixedDispatch() const { return true; }

bool WebAssembly::isPICDefault() const { return false; }

bool WebAssembly::isPIEDefault() const { return false; }

bool WebAssembly::isPICDefaultForced() const { return false; }

bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }

// TODO: Support Objective C stuff.
bool WebAssembly::SupportsObjCGC() const { return false; }

bool WebAssembly::hasBlocksRuntime() const { return false; }

// TODO: Support profiling.
bool WebAssembly::SupportsProfiling() const { return false; }

void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array, true))
CC1Args.push_back("-fuse-init-array");
}
21 changes: 21 additions & 0 deletions clang/lib/Driver/ToolChains.h
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,27 @@ class LLVM_LIBRARY_VISIBILITY SHAVEToolChain : public Generic_GCC {
mutable std::unique_ptr<Tool> Assembler;
};

class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain {
public:
WebAssembly(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args)
: ToolChain(D, Triple, Args) {}

private:
bool IsMathErrnoDefault() const override;
bool IsObjCNonFragileABIDefault() const override;
bool UseObjCMixedDispatch() const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
bool IsIntegratedAssemblerDefault() const override;
bool hasBlocksRuntime() const override;
bool SupportsObjCGC() const override;
bool SupportsProfiling() const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
};

} // end namespace toolchains
} // end namespace driver
} // end namespace clang
Expand Down
57 changes: 55 additions & 2 deletions clang/lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) {
return false;

case llvm::Triple::xcore:
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return true;
}
}
Expand Down Expand Up @@ -1553,6 +1555,25 @@ static const char *getX86TargetCPU(const ArgList &Args,
}
}

/// Get the (LLVM) name of the WebAssembly cpu we are targeting.
static StringRef getWebAssemblyTargetCPU(const ArgList &Args) {
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef CPU = A->getValue();

#ifdef __wasm__
// Handle "native" by examining the host. "native" isn't meaningful when
// cross compiling, so only support this when the host is also WebAssembly.
if (CPU == "native")
return llvm::sys::getHostCPUName();
#endif

return CPU;
}

return "generic";
}

static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
bool FromAs = false) {
switch (T.getArch()) {
Expand Down Expand Up @@ -1625,6 +1646,10 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
case llvm::Triple::r600:
case llvm::Triple::amdgcn:
return getR600TargetGPU(Args);

case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return getWebAssemblyTargetCPU(Args);
}
}

Expand Down Expand Up @@ -2074,6 +2099,24 @@ static void getAArch64TargetFeatures(const Driver &D,
Features.push_back("+reserve-x18");
}

static void getWebAssemblyTargetFeatures(const ArgList &Args,
std::vector<const char *> &Features) {
for (const Arg *A : Args.filtered(options::OPT_m_wasm_Features_Group)) {
StringRef Name = A->getOption().getName();
A->claim();

// Skip over "-m".
assert(Name.startswith("m") && "Invalid feature name.");
Name = Name.substr(1);

bool IsNegative = Name.startswith("no-");
if (IsNegative)
Name = Name.substr(3);

Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
}

static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args, ArgStringList &CmdArgs,
bool ForAS) {
Expand Down Expand Up @@ -2111,6 +2154,10 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case llvm::Triple::x86_64:
getX86TargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
getWebAssemblyTargetFeatures(Args, Features);
break;
}

// Find the last of each feature.
Expand Down Expand Up @@ -2590,9 +2637,15 @@ static bool areOptimizationsEnabled(const ArgList &Args) {

static bool shouldUseFramePointerForTarget(const ArgList &Args,
const llvm::Triple &Triple) {
// XCore never wants frame pointers, regardless of OS.
if (Triple.getArch() == llvm::Triple::xcore) {
switch (Triple.getArch()) {
case llvm::Triple::xcore:
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
// XCore never wants frame pointers, regardless of OS.
// WebAssembly never wants frame pointers.
return false;
default:
break;
}

if (Triple.isOSLinux()) {
Expand Down
13 changes: 13 additions & 0 deletions clang/test/CodeGen/align-wasm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -emit-llvm %s -o - \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -emit-llvm %s -o - \
// RUN: | FileCheck %s

void test1_f(void *);

void test1_g(void) {
float x[4];
test1_f(x);
}
// CHECK: @test1_g
// CHECK: alloca [4 x float], align 16
10 changes: 10 additions & 0 deletions clang/test/CodeGen/builtins-wasm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -O3 -emit-llvm -o - %s \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY32
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -O3 -emit-llvm -o - %s \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY64

__SIZE_TYPE__ f0(void) {
return __builtin_wasm_page_size();
// WEBASSEMBLY32: call {{i.*}} @llvm.wasm.page.size.i32()
// WEBASSEMBLY64: call {{i.*}} @llvm.wasm.page.size.i64()
}
8 changes: 8 additions & 0 deletions clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@
// RUN: FileCheck %s -check-prefix=LE32-NACL
// LE32-NACL: target datalayout = "e-p:32:32-i64:64"

// RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY32
// WEBASSEMBLY32: target datalayout = "e-p:32:32-i64:64-n32:64-S128"

// RUN: %clang_cc1 -triple wasm64-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY64
// WEBASSEMBLY64: target datalayout = "e-p:64:64-i64:64-n32:64-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"
Expand Down
93 changes: 93 additions & 0 deletions clang/test/CodeGen/wasm-arguments.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -emit-llvm -o - \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY32
// RUN: %clang_cc1 -triple wasm64-unknown-unknown %s -emit-llvm -o - \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY64

// Basic argument/attribute tests for WebAssembly

// WEBASSEMBLY32: define void @f0(i32 %i, i32 %j, i64 %k, double %l, double %m)
// WEBASSEMBLY64: define void @f0(i32 %i, i64 %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.
// WEBASSEMBLY32: define void @f1(%struct.s1* byval align 4 %i)
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define i32 @f2()
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define void @f3(%struct.s3* noalias sret %agg.result)
// WEBASSEMBLY64: define void @f3(%struct.s3* noalias sret %agg.result)
s3 f3() {
s3 foo;
return foo;
}

// WEBASSEMBLY32: define void @f4(i64 %i)
// WEBASSEMBLY64: define void @f4(i64 %i)
void f4(long long i) {}

// i8/i16 should be signext, i32 and higher should not.
// WEBASSEMBLY32: define void @f5(i8 signext %a, i16 signext %b)
// WEBASSEMBLY64: define void @f5(i8 signext %a, i16 signext %b)
void f5(char a, short b) {}

// WEBASSEMBLY32: define void @f6(i8 zeroext %a, i16 zeroext %b)
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define void @f7(i32 %a)
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define void @f8(i64 %a)
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define void @f9(%union.simple_union* byval align 4 %s)
// WEBASSEMBLY64: 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.
// WEBASSEMBLY32: define void @f10(%struct.bitfield1* byval align 4 %bf1)
// WEBASSEMBLY64: define void @f10(%struct.bitfield1* byval align 4 %bf1)
void f10(bitfield1 bf1) {}
4 changes: 4 additions & 0 deletions clang/test/CodeGen/wasm-regparm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -fsyntax-only -verify
// RUN: %clang_cc1 -triple wasm64-unknown-unknown %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}}
2 changes: 2 additions & 0 deletions clang/test/CodeGenCXX/constructor-destructor-return-this.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios6.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios5.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKIOS5 %s
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=wasm32-unknown-unknown \
//RUN: | FileCheck --check-prefix=CHECKARM %s
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-pc-win32 -fno-rtti | FileCheck --check-prefix=CHECKMS %s
// FIXME: these tests crash on the bots when run with -triple=x86_64-pc-win32

Expand Down
15 changes: 12 additions & 3 deletions clang/test/CodeGenCXX/member-alignment.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - | \
// RUN: FileCheck -check-prefix CHECK-ITANIUM %s
// RUN: %clang_cc1 -emit-llvm -triple wasm32-unknown-unknown %s -o - | \
// RUN: FileCheck -check-prefix CHECK-WEBASSEMBLY32 %s
// RUN: %clang_cc1 -emit-llvm -triple wasm64-unknown-unknown %s -o - | \
// RUN: FileCheck -check-prefix CHECK-WEBASSEMBLY64 %s

// rdar://7268289

Expand All @@ -10,10 +15,14 @@ class t {

void
t::bar(void) {
// CHECK: _ZN1t3barEv{{.*}} align 2
// CHECK-ITANIUM: @_ZN1t3barEv({{.*}}) #0 align 2 {
// CHECK-WEBASSEMBLY32: @_ZN1t3barEv({{.*}}) #0 {
// CHECK-WEBASSEMBLY64: @_ZN1t3barEv({{.*}}) #0 {
}

void
t::foo(void) {
// CHECK: _ZN1t3fooEv{{.*}} align 2
// CHECK-ITANIUM: @_ZN1t3fooEv({{.*}}) unnamed_addr #0 align 2 {
// CHECK-WEBASSEMBLY32: @_ZN1t3fooEv({{.*}}) unnamed_addr #0 {
// CHECK-WEBASSEMBLY64: @_ZN1t3fooEv({{.*}}) unnamed_addr #0 {
}
2 changes: 2 additions & 0 deletions clang/test/CodeGenCXX/member-function-pointers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=le32-unknown-nacl | FileCheck -check-prefix GLOBAL-ARM %s
// MIPS uses the same representation of method pointers as ARM.
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=mips-unknown-linux-gnu | FileCheck -check-prefix GLOBAL-ARM %s
// WebAssembly uses the same representation of method pointers as ARM.
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=wasm32-unknown-unknown | 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(); };
Expand Down
54 changes: 54 additions & 0 deletions clang/test/CodeGenCXX/static-init-wasm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// RUN: %clang_cc1 -emit-llvm -triple=wasm32-unknown-unknown -o - %s \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY32
// RUN: %clang_cc1 -emit-llvm -triple=wasm64-unknown-unknown -o - %s \
// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY64

// Test that we don't create common blocks.
int tentative;
// WEBASSEMBLY32: @tentative = global i32 0, align 4
// WEBASSEMBLY64: @tentative = global i32 0, align 4

// Test that WebAssembly uses the ARM-style ABI in which the static
// variable's guard variable is tested via "load i8 and test the
// bottom bit" rather than the Itanium/x86 ABI which uses "load i8
// and compare with zero".
int f();
void g() {
static int a = f();
}
// WEBASSEMBLY32-LABEL: @_Z1gv()
// WEBASSEMBLY32: %[[R0:.+]] = load atomic i8, i8* bitcast (i32* @_ZGVZ1gvE1a to i8*) acquire, align 1
// WEBASSEMBLY32-NEXT: %[[R1:.+]] = and i8 %[[R0]], 1
// WEBASSEMBLY32-NEXT: %[[R2:.+]] = icmp eq i8 %[[R1]], 0
// WEBASSEMBLY32-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]]
// WEBASSEMBLY32: [[CHECK]]
// WEBASSEMBLY32: call i32 @__cxa_guard_acquire
// WEBASSEMBLY32: [[END]]
// WEBASSEMBLY32: call void @__cxa_guard_release
//
// WEBASSEMBLY64-LABEL: @_Z1gv()
// WEBASSEMBLY64: %[[R0:.+]] = load atomic i8, i8* bitcast (i64* @_ZGVZ1gvE1a to i8*) acquire, align 1
// WEBASSEMBLY64-NEXT: %[[R1:.+]] = and i8 %[[R0]], 1
// WEBASSEMBLY64-NEXT: %[[R2:.+]] = icmp eq i8 %[[R1]], 0
// WEBASSEMBLY64-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]]
// WEBASSEMBLY64: [[CHECK]]
// WEBASSEMBLY64: call i32 @__cxa_guard_acquire
// WEBASSEMBLY64: [[END]]
// WEBASSEMBLY64: call void @__cxa_guard_release

// Test various aspects of static constructor calls.
struct A {
A();
};

A theA;

// WEBASSEMBLY32: define internal void @__cxx_global_var_init() #0 section ".text.__startup" {
// WEBASSEMBLY32: call %struct.A* @_ZN1AC1Ev(%struct.A* @theA)
// WEBASSEMBLY32: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #0 section ".text.__startup" {
// WEBASSEMBLY32: call void @__cxx_global_var_init()
//
// WEBASSEMBLY64: define internal void @__cxx_global_var_init() #0 section ".text.__startup" {
// WEBASSEMBLY64: call %struct.A* @_ZN1AC1Ev(%struct.A* @theA)
// WEBASSEMBLY64: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #0 section ".text.__startup" {
// WEBASSEMBLY64: call void @__cxx_global_var_init()
100 changes: 100 additions & 0 deletions clang/test/CodeGenCXX/wasm-args-returns.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// RUN: %clang_cc1 -O1 -triple wasm32-unknown-unknown -emit-llvm -o - %s \
// RUN: | FileCheck %s
// RUN: %clang_cc1 -O1 -triple wasm64-unknown-unknown -emit-llvm -o - %s \
// RUN: | FileCheck %s

#define concat_(x, y) x ## y
#define concat(x, y) concat_(x, y)

#define test(T) \
T forward(T x) { return x; } \
void use(T x); \
T concat(def_, T)(void); \
void concat(test_, T)(void) { use(concat(def_, T)()); }

struct one_field { double d; };
test(one_field);
// CHECK: define double @_Z7forward9one_field(double %{{.*}})
//
// CHECK: define void @_Z14test_one_fieldv()
// CHECK: %[[call:.*]] = tail call double @_Z13def_one_fieldv()
// CHECK: tail call void @_Z3use9one_field(double %[[call]])
// CHECK: ret void
//
// CHECK: declare void @_Z3use9one_field(double)
// CHECK: declare double @_Z13def_one_fieldv()

struct two_fields { double d, e; };
test(two_fields);
// CHECK: define void @_Z7forward10two_fields(%struct.two_fields* noalias nocapture sret %{{.*}}, %struct.two_fields* byval nocapture readonly align 8 %{{.*}})
//
// CHECK: define void @_Z15test_two_fieldsv()
// CHECK: %[[tmp:.*]] = alloca %struct.two_fields, align 8
// CHECK: call void @_Z14def_two_fieldsv(%struct.two_fields* nonnull sret %[[tmp]])
// CHECK: call void @_Z3use10two_fields(%struct.two_fields* byval nonnull align 8 %[[tmp]])
// CHECK: ret void
//
// CHECK: declare void @_Z3use10two_fields(%struct.two_fields* byval align 8)
// CHECK: declare void @_Z14def_two_fieldsv(%struct.two_fields* sret)

struct copy_ctor {
double d;
copy_ctor(copy_ctor const&);
};
test(copy_ctor);
// CHECK: define void @_Z7forward9copy_ctor(%struct.copy_ctor* noalias sret %{{.*}}, %struct.copy_ctor* align 8 %{{.*}})
//
// CHECK: declare %struct.copy_ctor* @_ZN9copy_ctorC1ERKS_(%struct.copy_ctor* returned, %struct.copy_ctor* dereferenceable(8))
//
// CHECK: define void @_Z14test_copy_ctorv()
// CHECK: %[[tmp:.*]] = alloca %struct.copy_ctor, align 8
// CHECK: call void @_Z13def_copy_ctorv(%struct.copy_ctor* nonnull sret %[[tmp]])
// CHECK: call void @_Z3use9copy_ctor(%struct.copy_ctor* nonnull align 8 %[[tmp]])
// CHECK: ret void
//
// CHECK: declare void @_Z3use9copy_ctor(%struct.copy_ctor* align 8)
// CHECK: declare void @_Z13def_copy_ctorv(%struct.copy_ctor* sret)

struct __attribute__((aligned(16))) aligned_copy_ctor {
double d, e;
aligned_copy_ctor(aligned_copy_ctor const&);
};
test(aligned_copy_ctor);
// CHECK: define void @_Z7forward17aligned_copy_ctor(%struct.aligned_copy_ctor* noalias sret %{{.*}}, %struct.aligned_copy_ctor* align 16 %{{.*}})
//
// CHECK: declare %struct.aligned_copy_ctor* @_ZN17aligned_copy_ctorC1ERKS_(%struct.aligned_copy_ctor* returned, %struct.aligned_copy_ctor* dereferenceable(16))
//
// CHECK: define void @_Z22test_aligned_copy_ctorv()
// CHECK: %[[tmp:.*]] = alloca %struct.aligned_copy_ctor, align 16
// CHECK: call void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* nonnull sret %[[tmp]])
// CHECK: call void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor* nonnull align 16 %[[tmp]])
// CHECK: ret void
//
// CHECK: declare void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor* align 16)
// CHECK: declare void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* sret)

struct empty {};
test(empty);
// CHECK: define void @_Z7forward5empty()
//
// CHECK: define void @_Z10test_emptyv()
// CHECK: tail call void @_Z9def_emptyv()
// CHECK: tail call void @_Z3use5empty()
// CHECK: ret void
//
// CHECK: declare void @_Z3use5empty()
// CHECK: declare void @_Z9def_emptyv()

struct one_bitfield {
int d:3;
};
test(one_bitfield);
// CHECK: define i32 @_Z7forward12one_bitfield(i32 %{{.*}})
//
// CHECK: define void @_Z17test_one_bitfieldv()
// CHECK: %[[call:.*]] = tail call i32 @_Z16def_one_bitfieldv()
// CHECK: tail call void @_Z3use12one_bitfield(i32 %[[call]])
// CHECK: ret void
//
// CHECK: declare void @_Z3use12one_bitfield(i32)
// CHECK: declare i32 @_Z16def_one_bitfieldv()
16 changes: 16 additions & 0 deletions clang/test/Driver/thread-model.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,19 @@
// CHECK-LINUX-SINGLE: Thread model: single
// CHECK-LINUX-SINGLE: "-mthread-model" "single"
// CHECK-LINUX-INVALID-NOT: Thread model:

// RUN: %clang -### -target wasm32-unknown-linux-gnu -c %s -v 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-DEFAULT %s
// RUN: %clang -### -target wasm32-unknown-linux-gnu -c %s -v -mthread-model single 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-SINGLE %s
// RUN: %clang -### -target wasm32-unknown-linux-gnu -c %s -v -mthread-model posix 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-POSIX %s
// RUN: %clang -### -target wasm32-unknown-linux-gnu -c %s -v -mthread-model silly 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-INVALID %s
// RUN: %clang -### -target wasm64-unknown-linux-gnu -c %s -v 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-DEFAULT %s
// RUN: %clang -### -target wasm64-unknown-linux-gnu -c %s -v -mthread-model single 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-SINGLE %s
// RUN: %clang -### -target wasm64-unknown-linux-gnu -c %s -v -mthread-model posix 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-POSIX %s
// RUN: %clang -### -target wasm64-unknown-linux-gnu -c %s -v -mthread-model silly 2>&1 | FileCheck -check-prefix=CHECK-WEBASSEMBLY-INVALID %s
// CHECK-WEBASSEMBLY-DEFAULT: Thread model: posix
// CHECK-WEBASSEMBLY-DEFAULT: "-mthread-model" "posix"
// CHECK-WEBASSEMBLY-SINGLE: Thread model: single
// CHECK-WEBASSEMBLY-SINGLE: "-mthread-model" "single"
// CHECK-WEBASSEMBLY-POSIX: Thread model: posix
// CHECK-WEBASSEMBLY-POSIX: "-mthread-model" "posix"
// CHECK-WEBASSEMBLY-INVALID-NOT: Thread model:
119 changes: 119 additions & 0 deletions clang/test/Driver/wasm32-unknown-unknown.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// RUN: %clang -target wasm32-unknown-unknown -### %s -emit-llvm-only -c 2>&1 \
// RUN: | FileCheck %s -check-prefix=ECHO
// RUN: %clang -target wasm32-unknown-unknown %s -emit-llvm -S -o - \
// RUN: | FileCheck %s
// RUN: %clang -target wasm32-unknown-unknown %s -emit-llvm -S -pthread -o - \
// RUN: | FileCheck %s -check-prefix=THREADS

// ECHO: {{.*}} "-cc1" {{.*}}wasm32-unknown-unknown.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: _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: SwitchILi4
Switch<sizeof(va_list)>();
}
119 changes: 119 additions & 0 deletions clang/test/Driver/wasm64-unknown-unknown.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// RUN: %clang -target wasm64-unknown-unknown -### %s -emit-llvm-only -c 2>&1 \
// RUN: | FileCheck %s -check-prefix=ECHO
// RUN: %clang -target wasm64-unknown-unknown %s -emit-llvm -S -o - \
// RUN: | FileCheck %s
// RUN: %clang -target wasm64-unknown-unknown %s -emit-llvm -S -pthread -o - \
// RUN: | FileCheck %s -check-prefix=THREADS

// ECHO: {{.*}} "-cc1" {{.*}}wasm64-unknown-unknown.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 8
int align_l = __alignof(long);

// CHECK: @align_ll = global i32 8
int align_ll = __alignof(long long);

// CHECK: @align_p = global i32 8
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 8
int align_vl = __alignof(va_list);

// 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: i64 @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: i64 @check_ulong()
unsigned long check_ulong() { return 0; }

// CHECK: i64 @check_ulonglong()
unsigned long long check_ulonglong() { return 0; }

// CHECK: i64 @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: SwitchILi8
Switch<sizeof(void*)>();

// CHECK: SwitchILi8
Switch<sizeof(long long)>();

// CHECK: SwitchILi8
Switch<sizeof(va_list)>();
}
632 changes: 632 additions & 0 deletions clang/test/Preprocessor/init.c

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions clang/test/Preprocessor/wasm-target-features.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -msimd128 \
// RUN: | FileCheck %s -check-prefix=SIMD128
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm64-unknown-unknown -msimd128 \
// RUN: | FileCheck %s -check-prefix=SIMD128
//
// SIMD128:#define __wasm_simd128__ 1{{$}}
//
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mcpu=mvp \
// RUN: | FileCheck %s -check-prefix=MVP
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm64-unknown-unknown -mcpu=mvp \
// RUN: | FileCheck %s -check-prefix=MVP
//
// MVP-NOT:#define __wasm_simd128__
//
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge \
// RUN: | FileCheck %s -check-prefix=BLEEDING_EDGE
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm64-unknown-unknown -mcpu=bleeding-edge \
// RUN: | FileCheck %s -check-prefix=BLEEDING_EDGE
//
// BLEEDING_EDGE:#define __wasm_simd128__ 1{{$}}
//
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge -mno-simd128 \
// RUN: | FileCheck %s -check-prefix=BLEEDING_EDGE_NO_SIMD128
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm64-unknown-unknown -mcpu=bleeding-edge -mno-simd128 \
// RUN: | FileCheck %s -check-prefix=BLEEDING_EDGE_NO_SIMD128
//
// BLEEDING_EDGE_NO_SIMD128-NOT:#define __wasm_simd128__