aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Gohman <sunfish@google.com>2014-02-21 16:09:43 -0800
committerDan Gohman <sunfish@google.com>2014-02-24 17:32:54 -0800
commitf6e2fddff6294c1c2ec2f9602c30ff680359ed19 (patch)
tree2b0ff77983e789a89259ad66918b1248c7893ab6 /lib
parenta963b803407c9d1cac644cc425004e0ccd28fa45 (diff)
Introduce the asmjs-unknown-emscripten target triple.
Notable changes from le32-unknown-nacl so far include: - Set i32 as the legal integer set, to help the optimizer avoid creating needlessly inefficient code for asm.js. - We can use llvm.pow. - Don't predefine __ELF__ or __pnacl__ so that we don't need to undefine them later. - Do predefine asm.js and Emscripten macros, so that we don't need to define them later. - Don't provide __has_feature(pnacl).
Diffstat (limited to 'lib')
-rw-r--r--lib/Basic/Targets.cpp117
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp10
-rw-r--r--lib/CodeGen/TargetInfo.cpp59
3 files changed, 182 insertions, 4 deletions
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a622a11aa5..43a21f2734 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -239,6 +239,39 @@ public:
}
};
+// 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 std::string& 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 = "";
+ }
+};
+
// FreeBSD Target
template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
@@ -5042,6 +5075,82 @@ public:
} // end anonymous namespace.
namespace {
+class AsmJSTargetInfo : public TargetInfo {
+public:
+ explicit AsmJSTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ 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.
+ 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";
+ }
+
+ 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 std::string& triple) : TargetInfo(triple) {
@@ -5315,6 +5424,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new Mips64ELTargetInfo(T);
}
+ case llvm::Triple::asmjs:
+ switch (os) {
+ case llvm::Triple::Emscripten:
+ return new EmscriptenTargetInfo<AsmJSTargetInfo>(T);
+ default:
+ return NULL;
+ }
+
case llvm::Triple::le32:
switch (os) {
case llvm::Triple::NaCl:
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 8a7f551e68..3767e4f278 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -232,15 +232,17 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
/* UseARMGuardVarABI = */ true);
case TargetCXXABI::GenericItanium:
- if (CGM.getContext().getTargetInfo().getTriple().getArch()
- == llvm::Triple::le32) {
- // For PNaCl, use ARM-style method pointers so that PNaCl code
+ switch (CGM.getContext().getTargetInfo().getTriple().getArch()) {
+ case llvm::Triple::le32:
+ case llvm::Triple::asmjs:
+ // 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);
+ default:
+ return new ItaniumCXXABI(CGM);
}
- return new ItaniumCXXABI(CGM);
case TargetCXXABI::Microsoft:
llvm_unreachable("Microsoft ABI is not Itanium-based");
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 4fb888a767..5aa982e255 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -411,6 +411,62 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
}
//===----------------------------------------------------------------------===//
+// 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 RetTy) const;
+};
+
+class EmscriptenTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ explicit EmscriptenTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new EmscriptenABIInfo(CGT)) {}
+
+ // TODO: Re-evaluate whether these hacks, borrowed from PNaCl, are necessary.
+ bool addAsmMemoryAroundSyncSynchronize() const { return true; }
+ bool asmMemoryIsFence() const { return true; }
+};
+
+/// \brief Classify argument of given type \p Ty.
+ABIArgInfo EmscriptenABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+ return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // We can handle floating-point values directly.
+ if (Ty->isFloatingType())
+ return ABIArgInfo::getDirect();
+
+ // 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)));
+ }
+
+ // We can handle floating-point values directly.
+ if (RetTy->isFloatingType())
+ return ABIArgInfo::getDirect();
+
+ // 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
@@ -5101,6 +5157,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
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: