From 1bdd6a06e26f75a4c2a3a017775e5af9bead6be9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 15 Sep 2014 13:28:06 -0700 Subject: [PATCH 1/9] support ConstantVector, which can appear instead of ConstantDataVector when it contains an undef --- lib/Target/JSBackend/JSBackend.cpp | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index cfadcdc0757..320b9df3968 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -405,6 +405,7 @@ namespace { std::string getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer=true); std::string getPtrUse(const Value* Ptr); std::string getConstant(const Constant*, AsmCast sign=ASM_SIGNED); + std::string getConstantVector(Type *ElementType, std::string x, std::string y, std::string z, std::string w); std::string getValueAsStr(const Value*, AsmCast sign=ASM_SIGNED); std::string getValueAsCastStr(const Value*, AsmCast sign=ASM_SIGNED); std::string getValueAsParenStr(const Value*); @@ -1047,18 +1048,18 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { return "0"; } } else if (const ConstantDataVector *DV = dyn_cast(CV)) { - const VectorType *VT = cast(CV->getType()); - if (VT->getElementType()->isIntegerTy()) { - return "SIMD.int32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + - getConstant(DV->getElementAsConstant(1)) + ',' + - getConstant(DV->getElementAsConstant(2)) + ',' + - getConstant(DV->getElementAsConstant(3)) + ')'; - } else { - return "SIMD.float32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + - getConstant(DV->getElementAsConstant(1)) + ',' + - getConstant(DV->getElementAsConstant(2)) + ',' + - getConstant(DV->getElementAsConstant(3)) + ')'; - } + return getConstantVector(cast(CV->getType())->getElementType(), + getConstant(DV->getElementAsConstant(0)), + getConstant(DV->getElementAsConstant(1)), + getConstant(DV->getElementAsConstant(2)), + getConstant(DV->getElementAsConstant(3))); + } else if (const ConstantVector *V = dyn_cast(CV)) { + assert(V->getNumOperands() == 4); + return getConstantVector(cast(V->getType())->getElementType(), + getConstant(V->getOperand(0)), + getConstant(V->getOperand(1)), + getConstant(V->getOperand(2)), + getConstant(V->getOperand(3))); } else if (const ConstantArray *CA = dyn_cast(CV)) { // handle things like [i8* bitcast (<{ i32, i32, i32 }>* @_ZTISt9bad_alloc to i8*)] which clang can emit for landingpads assert(CA->getNumOperands() == 1); @@ -1081,6 +1082,14 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { } } +std::string JSWriter::getConstantVector(Type *ElementType, std::string x, std::string y, std::string z, std::string w) { + if (ElementType->isIntegerTy()) { + return "SIMD.int32x4(" + x + ',' + y + ',' + z + ',' + w + ')'; + } else { + return "SIMD.float32x4(" + x + ',' + y + ',' + z + ',' + w + ')'; + } +} + std::string JSWriter::getValueAsStr(const Value* V, AsmCast sign) { // Skip past no-op bitcasts and zero-index geps. V = V->stripPointerCasts(); From ef11165168f62b4990ab5602d6416a3bf3663a3a Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 Sep 2014 11:40:30 -0700 Subject: [PATCH 2/9] emit I,F as signatures of vector types --- lib/Target/JSBackend/JSBackend.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 320b9df3968..1ee684b64e5 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -260,7 +260,16 @@ namespace { } else { return 'd'; } - } else return 'i'; + } else if (VectorType *VT = dyn_cast(T)) { + checkVectorType(VT); + if (VT->getElementType()->isIntegerTy()) { + return 'I'; + } else { + return 'F'; + } + } else { + return 'i'; + } } std::string getFunctionSignature(const FunctionType *F, const std::string *Name=NULL) { std::string Ret; From c3fea7d67cac79a8345bc435e045948cb780cfde Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 22 Sep 2014 18:02:20 -0700 Subject: [PATCH 3/9] SIMD fixes Implement emscripten_float32x4_select, and prepare the UsedVars map in anticipation of SIMD coercive calls which will need to know the full type. --- lib/Target/JSBackend/CallHandlers.h | 28 ++++++++++++++++------------ lib/Target/JSBackend/JSBackend.cpp | 17 +++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 8ef21bd6ef6..8f2a138da9c 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -314,7 +314,7 @@ DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, { } } else { // emit a loop - UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext())->getTypeID(); + UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext()); Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; src=" + Src + "+" + utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))"; } Pos += CurrLen; @@ -368,7 +368,7 @@ DEF_CALL_HANDLER(llvm_memset_p0i8_i32, { } } else { // emit a loop - UsedVars["dest"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext())->getTypeID(); + UsedVars["dest"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext()); Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + utostr(FullVal) + "|0; dest=dest+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))"; } Pos += CurrLen; @@ -477,24 +477,24 @@ DEF_CALL_HANDLER(emscripten_float32x4_greaterThan, { return CH___default__(CI, "SIMD.float32x4.greaterThan"); }) DEF_CALL_HANDLER(emscripten_float32x4_and, { - return getAssign(CI) + "SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.and(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + "))"; + return getAssign(CI) + "SIMD.float32x4.and(" + + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_float32x4_andNot, { - return getAssign(CI) + "SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.and(SIMD.float32x4.not(" + - getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + "))"; + return getAssign(CI) + "SIMD.float32x4.and(SIMD.float32x4.not(" + + getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_float32x4_or, { - return getAssign(CI) + "SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.or(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + "))"; + return getAssign(CI) + "SIMD.float32x4.or(" + + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_float32x4_xor, { - return getAssign(CI) + "SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.xor(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + "))"; + return getAssign(CI) + "SIMD.float32x4.xor(" + + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_float32x4_not, { - return getAssign(CI) + "SIMD.float32x4.fromInt32x4Bits(SIMD.float32x4.not(" + - getValueAsStr(CI->getOperand(0)) + "))"; + return getAssign(CI) + "SIMD.float32x4.not(" + + getValueAsStr(CI->getOperand(0)) + ")"; }) DEF_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits, { return CH___default__(CI, "SIMD.float32x4.fromInt32x4Bits"); @@ -508,6 +508,9 @@ DEF_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits, { DEF_CALL_HANDLER(emscripten_int32x4_fromFloat32x4, { return CH___default__(CI, "SIMD.int32x4.fromFloat32x4"); }) +DEF_CALL_HANDLER(emscripten_float32x4_select, { + return CH___default__(CI, "SIMD.float32x4.select"); +}) #define DEF_BUILTIN_HANDLER(name, to) \ DEF_CALL_HANDLER(name, { \ @@ -636,6 +639,7 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_float32x4_or); SETUP_CALL_HANDLER(emscripten_float32x4_xor); SETUP_CALL_HANDLER(emscripten_float32x4_not); + SETUP_CALL_HANDLER(emscripten_float32x4_select); SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits); SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4); SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits); diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 1ee684b64e5..766f6c361b1 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -114,7 +114,7 @@ namespace { typedef std::set NameSet; typedef std::vector HeapData; typedef std::pair Address; - typedef std::map VarMap; + typedef std::map VarMap; typedef std::map GlobalAddressMap; typedef std::vector FunctionTable; typedef std::map FunctionTableMap; @@ -660,7 +660,7 @@ const std::string &JSWriter::getJSName(const Value* val) { } std::string JSWriter::getAdHocAssign(const StringRef &s, Type *t) { - UsedVars[s] = t->getTypeID(); + UsedVars[s] = t; return (s + " = ").str(); } @@ -1547,7 +1547,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { if (NativizedVars.count(AI)) { // nativized stack variable, we just need a 'var' definition - UsedVars[getJSName(AI)] = AI->getType()->getElementType()->getTypeID(); + UsedVars[getJSName(AI)] = AI->getType()->getElementType(); return; } @@ -1927,12 +1927,12 @@ void JSWriter::printFunctionBody(const Function *F) { R.Render(); // Emit local variables - UsedVars["sp"] = Type::IntegerTyID; + UsedVars["sp"] = Type::getInt32Ty(F->getContext()); unsigned MaxAlignment = Allocas.getMaxAlignment(); if (MaxAlignment > STACK_ALIGN) { - UsedVars["sp_a"] = Type::IntegerTyID; + UsedVars["sp_a"] = Type::getInt32Ty(F->getContext()); } - UsedVars["label"] = Type::IntegerTyID; + UsedVars["label"] = Type::getInt32Ty(F->getContext()); if (!UsedVars.empty()) { unsigned Count = 0; for (VarMap::const_iterator VI = UsedVars.begin(); VI != UsedVars.end(); ++VI) { @@ -1946,7 +1946,7 @@ void JSWriter::printFunctionBody(const Function *F) { } Count++; Out << VI->first << " = "; - switch (VI->second) { + switch (VI->second->getTypeID()) { default: llvm_unreachable("unsupported variable initializer type"); case Type::PointerTyID: @@ -1963,7 +1963,8 @@ void JSWriter::printFunctionBody(const Function *F) { Out << "+0"; break; case Type::VectorTyID: - Out << "0"; // best we can do for now + // TODO: When ecmascript_simd issue #54 is implemented, we'll do a coercive call here. + Out << "0"; break; } } From eb92becfd9bf3a12bb757ed0372e395f34a2f9f6 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 24 Sep 2014 08:21:47 -0700 Subject: [PATCH 4/9] Asm.js validation fixes for SIMD --- lib/Target/JSBackend/CallHandlers.h | 90 +++++++++-------------------- lib/Target/JSBackend/JSBackend.cpp | 80 ++++++++++++++----------- 2 files changed, 75 insertions(+), 95 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 8f2a138da9c..e2f0cd4a1db 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -452,65 +452,6 @@ DEF_CALL_HANDLER(llvm_cttz_i32, { DEF_CALL_HANDLER(emscripten_float32x4_signmask, { return getAssign(CI) + getValueAsStr(CI->getOperand(0)) + ".signMask"; }) -DEF_CALL_HANDLER(emscripten_float32x4_min, { - return CH___default__(CI, "SIMD.float32x4.min"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_max, { - return CH___default__(CI, "SIMD.float32x4.max"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_sqrt, { - return CH___default__(CI, "SIMD.float32x4.sqrt"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_lessThan, { - return CH___default__(CI, "SIMD.float32x4.lessThan"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual, { - return CH___default__(CI, "SIMD.float32x4.lessThanOrEqual"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_equal, { - return CH___default__(CI, "SIMD.float32x4.equal"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual, { - return CH___default__(CI, "SIMD.float32x4.greaterThanOrEqual"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_greaterThan, { - return CH___default__(CI, "SIMD.float32x4.greaterThan"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_and, { - return getAssign(CI) + "SIMD.float32x4.and(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_float32x4_andNot, { - return getAssign(CI) + "SIMD.float32x4.and(SIMD.float32x4.not(" + - getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_float32x4_or, { - return getAssign(CI) + "SIMD.float32x4.or(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_float32x4_xor, { - return getAssign(CI) + "SIMD.float32x4.xor(" + - getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_float32x4_not, { - return getAssign(CI) + "SIMD.float32x4.not(" + - getValueAsStr(CI->getOperand(0)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits, { - return CH___default__(CI, "SIMD.float32x4.fromInt32x4Bits"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_fromInt32x4, { - return CH___default__(CI, "SIMD.float32x4.fromInt32x4"); -}) -DEF_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits, { - return CH___default__(CI, "SIMD.int32x4.fromFloat32x4Bits"); -}) -DEF_CALL_HANDLER(emscripten_int32x4_fromFloat32x4, { - return CH___default__(CI, "SIMD.int32x4.fromFloat32x4"); -}) -DEF_CALL_HANDLER(emscripten_float32x4_select, { - return CH___default__(CI, "SIMD.float32x4.select"); -}) #define DEF_BUILTIN_HANDLER(name, to) \ DEF_CALL_HANDLER(name, { \ @@ -570,6 +511,31 @@ DEF_BUILTIN_HANDLER(llvm_log_f32, Math_log); DEF_BUILTIN_HANDLER(llvm_log_f64, Math_log); DEF_BUILTIN_HANDLER(llvm_exp_f32, Math_exp); DEF_BUILTIN_HANDLER(llvm_exp_f64, Math_exp); +DEF_BUILTIN_HANDLER(emscripten_float32x4_equal, SIMD_float32x4_equal); +DEF_BUILTIN_HANDLER(emscripten_float32x4_notEqual, SIMD_float32x4_notEqual); +DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThan, SIMD_float32x4_lessThan); +DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThanOrEqual, SIMD_float32x4_lessThanOrEqual); +DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThan, SIMD_float32x4_greaterThan); +DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThanOrEqual, SIMD_float32x4_greaterThanOrEqual); +DEF_BUILTIN_HANDLER(emscripten_float32x4_select, SIMD_float32x4_select); +DEF_BUILTIN_HANDLER(emscripten_float32x4_min, SIMD_float32x4_min); +DEF_BUILTIN_HANDLER(emscripten_float32x4_max, SIMD.float32x4_max); +DEF_BUILTIN_HANDLER(emscripten_float32x4_sqrt, SIMD_float32x4_sqrt); +DEF_BUILTIN_HANDLER(emscripten_float32x4_and, SIMD_float32x4_and); +DEF_BUILTIN_HANDLER(emscripten_float32x4_or, SIMD_float32x4_or); +DEF_BUILTIN_HANDLER(emscripten_float32x4_xor, SIMD_float32x4_xor); +DEF_BUILTIN_HANDLER(emscripten_float32x4_not, SIMD_float32x4_not); +DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4Bits, SIMD_float32x4_fromInt32x4Bits); +DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4, SIMD_float32x4_fromInt32x4); +DEF_BUILTIN_HANDLER(emscripten_int32x4_equal, SIMD_int32x4_equal); +DEF_BUILTIN_HANDLER(emscripten_int32x4_notEqual, SIMD_int32x4_notEqual); +DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThan, SIMD_int32x4_lessThan); +DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThanOrEqual, SIMD_int32x4_lessThanOrEqual); +DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThan, SIMD_int32x4_greaterThan); +DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThanOrEqual, SIMD_int32x4_greaterThanOrEqual); +DEF_BUILTIN_HANDLER(emscripten_int32x4_select, SIMD_int32x4_select); +DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4Bits, SIMD_int32x4_fromFloat32x4Bits); +DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4, SIMD_int32x4_fromFloat32x4); // Setups @@ -629,13 +595,13 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_float32x4_min); SETUP_CALL_HANDLER(emscripten_float32x4_max); SETUP_CALL_HANDLER(emscripten_float32x4_sqrt); + SETUP_CALL_HANDLER(emscripten_float32x4_equal); + SETUP_CALL_HANDLER(emscripten_float32x4_notEqual); SETUP_CALL_HANDLER(emscripten_float32x4_lessThan); SETUP_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual); - SETUP_CALL_HANDLER(emscripten_float32x4_equal); - SETUP_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual); SETUP_CALL_HANDLER(emscripten_float32x4_greaterThan); + SETUP_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual); SETUP_CALL_HANDLER(emscripten_float32x4_and); - SETUP_CALL_HANDLER(emscripten_float32x4_andNot); SETUP_CALL_HANDLER(emscripten_float32x4_or); SETUP_CALL_HANDLER(emscripten_float32x4_xor); SETUP_CALL_HANDLER(emscripten_float32x4_not); diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 766f6c361b1..ae0e292db66 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1034,9 +1034,9 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { std::string S; if (VectorType *VT = dyn_cast(CV->getType())) { if (VT->getElementType()->isIntegerTy()) { - S = "SIMD.int32x4.splat(0)"; + S = "SIMD_int32x4_splat(0)"; } else { - S = "SIMD.float32x4.splat(0.0)"; + S = "SIMD_float32x4_splat(Math_fround(0))"; } } else { S = CV->getType()->isFloatingPointTy() ? "+0" : "0"; // XXX refactor this @@ -1048,9 +1048,9 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { } else if (isa(CV)) { if (VectorType *VT = dyn_cast(CV->getType())) { if (VT->getElementType()->isIntegerTy()) { - return "SIMD.int32x4.splat(0)"; + return "SIMD_int32x4_splat(0)"; } else { - return "SIMD.float32x4.splat(0)"; + return "SIMD_float32x4_splat(Math_fround(0))"; } } else { // something like [0 x i8*] zeroinitializer, which clang can emit for landingpads @@ -1093,9 +1093,9 @@ std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { std::string JSWriter::getConstantVector(Type *ElementType, std::string x, std::string y, std::string z, std::string w) { if (ElementType->isIntegerTy()) { - return "SIMD.int32x4(" + x + ',' + y + ',' + z + ',' + w + ')'; + return "SIMD_int32x4(" + x + ',' + y + ',' + z + ',' + w + ')'; } else { - return "SIMD.float32x4(" + x + ',' + y + ',' + z + ',' + w + ')'; + return "SIMD_float32x4(Math_fround(" + x + "),Math_fround(" + y + "),Math_fround(" + z + "),Math_fround(" + w + "))"; } } @@ -1155,30 +1155,38 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { return false; case Instruction::PHI: // handled separately - we push them back into the relooper branchings break; - case Instruction::FAdd: Code << getAssignIfNeeded(I) << "SIMD.float32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::FMul: Code << getAssignIfNeeded(I) << "SIMD.float32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::FDiv: Code << getAssignIfNeeded(I) << "SIMD.float32x4.div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Add: Code << getAssignIfNeeded(I) << "SIMD.int32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Sub: Code << getAssignIfNeeded(I) << "SIMD.int32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Mul: Code << getAssignIfNeeded(I) << "SIMD.int32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::And: Code << getAssignIfNeeded(I) << "SIMD.int32x4.and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Or: Code << getAssignIfNeeded(I) << "SIMD.int32x4.or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Xor: Code << getAssignIfNeeded(I) << "SIMD.int32x4.xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FAdd: Code << getAssignIfNeeded(I) << "SIMD_float32x4_add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FMul: Code << getAssignIfNeeded(I) << "SIMD_float32x4_mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FDiv: Code << getAssignIfNeeded(I) << "SIMD_float32x4_div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Add: Code << getAssignIfNeeded(I) << "SIMD_int32x4_add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Sub: Code << getAssignIfNeeded(I) << "SIMD_int32x4_sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Mul: Code << getAssignIfNeeded(I) << "SIMD_int32x4_mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::And: Code << getAssignIfNeeded(I) << "SIMD_int32x4_and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Or: Code << getAssignIfNeeded(I) << "SIMD_int32x4_or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Xor: + // LLVM represents a not(x) as -1 ^ x + Code << getAssignIfNeeded(I); + if (BinaryOperator::isNot(I)) { + Code << "SIMD_int32x4_not(" << getValueAsStr(BinaryOperator::getNotArgument(I)) << ")"; break; + } else { + Code << "SIMD_int32x4_xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + } + break; case Instruction::FSub: // LLVM represents an fneg(x) as -0.0 - x. Code << getAssignIfNeeded(I); if (BinaryOperator::isFNeg(I)) { - Code << "SIMD.float32x4.neg(" << getValueAsStr(BinaryOperator::getFNegArgument(I)) << ")"; + Code << "SIMD_float32x4_neg(" << getValueAsStr(BinaryOperator::getFNegArgument(I)) << ")"; } else { - Code << "SIMD.float32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; + Code << "SIMD_float32x4_sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; } break; case Instruction::BitCast: { Code << getAssignIfNeeded(I); if (cast(I->getType())->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4.fromFloat32x4Bits(" << getValueAsStr(I->getOperand(0)) << ')'; + Code << "SIMD_int32x4_fromFloat32x4Bits(" << getValueAsStr(I->getOperand(0)) << ')'; } else { - Code << "SIMD.float32x4.fromInt32x4Bits(" << getValueAsStr(I->getOperand(0)) << ')'; + Code << "SIMD_float32x4_fromInt32x4Bits(" << getValueAsStr(I->getOperand(0)) << ')'; } break; } @@ -1188,9 +1196,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { std::string PS = getValueAsStr(P); Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4(HEAPU32[" << PS << ">>2],HEAPU32[" << PS << "+4>>2],HEAPU32[" << PS << "+8>>2],HEAPU32[" << PS << "+12>>2])"; + Code << "SIMD_int32x4(HEAPU32[" << PS << ">>2],HEAPU32[" << PS << "+4>>2],HEAPU32[" << PS << "+8>>2],HEAPU32[" << PS << "+12>>2])"; } else { - Code << "SIMD.float32x4(HEAPF32[" << PS << ">>2],HEAPF32[" << PS << "+4>>2],HEAPF32[" << PS << "+8>>2],HEAPF32[" << PS << "+12>>2])"; + Code << "SIMD_float32x4(HEAPF32[" << PS << ">>2],HEAPF32[" << PS << "+4>>2],HEAPF32[" << PS << "+8>>2],HEAPF32[" << PS << "+12>>2])"; } break; } @@ -1201,9 +1209,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { assert(Index <= 3); Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4.with"; + Code << "SIMD_int32x4_with"; } else { - Code << "SIMD.float32x4.with"; + Code << "SIMD_float32x4_with"; } Code << SIMDLane[Index]; Code << "(" << getValueAsStr(III->getOperand(0)) << ',' << getValueAsStr(III->getOperand(1)) << ')'; @@ -1235,9 +1243,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { if (shuffleA || shuffleB) { std::string T = (shuffleA ? A : B); if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4.shuffle(" << T << ", SIMD."; + Code << "SIMD_int32x4_shuffle(" << T << ", SIMD."; } else { - Code << "SIMD.float32x4.shuffle(" << T << ", SIMD."; + Code << "SIMD_float32x4_shuffle(" << T << ", SIMD."; } for (unsigned int i = 0; i < 4; i++) { int Mask = SVI->getMaskValue(i); @@ -1273,9 +1281,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { B = C; } if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4.shuffleMix(" << A << ", " << B << ", SIMD."; + Code << "SIMD_int32x4_shuffleMix(" << A << ", " << B << ", SIMD."; } else { - Code << "SIMD.float32x4.shuffleMix(" << A << ", " << B << ", SIMD."; + Code << "SIMD_float32x4_shuffleMix(" << A << ", " << B << ", SIMD."; } for (unsigned int i = 0; i < 4; i++) { int Mask = SVI->getMaskValue(i); @@ -1293,9 +1301,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { } // Other cases. if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD.int32x4("; + Code << "SIMD_int32x4("; } else { - Code << "SIMD.float32x4("; + Code << "SIMD_float32x4("; } for (unsigned int i = 0; i < 4; i++) { int Mask = SVI->getMaskValue(i); @@ -1336,8 +1344,11 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { const ConstantInt *IndexInt = cast(EEI->getIndexOperand()); unsigned Index = IndexInt->getZExtValue(); assert(Index <= 3); - Code << getAssignIfNeeded(I); - Code << getValueAsStr(EEI->getVectorOperand()) << '.' << simdLane[Index]; + Code << getAssignIfNeeded(EEI); + std::string OperandCode; + raw_string_ostream CodeStream(OperandCode); + CodeStream << getValueAsStr(EEI->getVectorOperand()) << '.' << simdLane[Index]; + Code << getCast(CodeStream.str(), EEI->getType()); return true; } } @@ -1963,8 +1974,11 @@ void JSWriter::printFunctionBody(const Function *F) { Out << "+0"; break; case Type::VectorTyID: - // TODO: When ecmascript_simd issue #54 is implemented, we'll do a coercive call here. - Out << "0"; + if (cast(VI->second)->getElementType()->isIntegerTy()) { + Out << "SIMD_int32x4(0,0,0,0)"; + } else { + Out << "SIMD_float32x4(0,0,0,0)"; + } break; } } From 1dcb703a715212eb93371096086de007554fbc59 Mon Sep 17 00:00:00 2001 From: Ningxin Hu Date: Tue, 23 Sep 2014 16:34:02 -0700 Subject: [PATCH 5/9] Map vector load and store instructions to SIMD.js load and store APIs. --- lib/Target/JSBackend/JSBackend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index ae0e292db66..5ab3c63d860 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1196,9 +1196,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { std::string PS = getValueAsStr(P); Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD_int32x4(HEAPU32[" << PS << ">>2],HEAPU32[" << PS << "+4>>2],HEAPU32[" << PS << "+8>>2],HEAPU32[" << PS << "+12>>2])"; + Code << "SIMD_int32x4_load(HEAPU32.buffer, " << PS << ")"; } else { - Code << "SIMD_float32x4(HEAPF32[" << PS << ">>2],HEAPF32[" << PS << "+4>>2],HEAPF32[" << PS << "+8>>2],HEAPF32[" << PS << "+12>>2])"; + Code << "SIMD_float32x4_load(HEAPF32.buffer, " << PS << ")"; } break; } @@ -1332,9 +1332,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { std::string VS = getValueAsStr(SI->getValueOperand()); Code << getAdHocAssign(PS, P->getType()) << getValueAsStr(P) << ';'; if (VT->getElementType()->isIntegerTy()) { - Code << "HEAPU32[" << PS << ">>2]=" << VS << ".x;HEAPU32[" << PS << "+4>>2]=" << VS << ".y;HEAPU32[" << PS << "+8>>2]=" << VS << ".z;HEAPU32[" << PS << "+12>>2]=" << VS << ".w"; + Code << "SIMD_int32x4_store(HEAPU32.buffer, " << PS << ", " << VS << ")"; } else { - Code << "HEAPF32[" << PS << ">>2]=" << VS << ".x;HEAPF32[" << PS << "+4>>2]=" << VS << ".y;HEAPF32[" << PS << "+8>>2]=" << VS << ".z;HEAPF32[" << PS << "+12>>2]=" << VS << ".w"; + Code << "SIMD_float32x4_store(HEAPF32.buffer, " << PS << ", " << VS << ")"; } return true; } else if (Operator::getOpcode(I) == Instruction::ExtractElement) { From a99ae677b137c77372005d03adde82330cb0b8b3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 26 Sep 2014 11:47:07 -0700 Subject: [PATCH 6/9] Optiomize InsertElement chains. LLVM doesn't have vector constructor operators; instead it uses chains of insertelements. Teach Emscripten to collect chains and detect when they form splats and constructor calls so that it can emit the natural API calls. --- lib/Target/JSBackend/JSBackend.cpp | 90 +++++++++++++++++++++---- test/CodeGen/JS/insertelement-chains.ll | 88 ++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 14 deletions(-) create mode 100644 test/CodeGen/JS/insertelement-chains.ll diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 5ab3c63d860..ac1fbef3a31 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -442,6 +442,7 @@ namespace { void addBlock(const BasicBlock *BB, Relooper& R, LLVMToRelooperMap& LLVMToRelooper); void printFunctionBody(const Function *F); + void generateInsertElementExpression(const InsertElementInst *III, raw_string_ostream& Code); bool generateSIMDExpression(const User *I, raw_string_ostream& Code); void generateExpression(const User *I, raw_string_ostream& Code); @@ -1143,6 +1144,79 @@ std::string JSWriter::getValueAsCastParenStr(const Value* V, AsmCast sign) { } } +void JSWriter::generateInsertElementExpression(const InsertElementInst *III, raw_string_ostream& Code) { + // LLVM has no vector type constructor operator; it uses chains of + // insertelement instructions instead. If this insertelement is part of a + // chain, skip it for now; we'll process it when we reach the end. + if (III->hasOneUse() && isa(*III->use_begin())) + return; + + // This insertelement is at the base of a chain of single-user insertelement + // instructions. Collect all the inserted elements so that we can categorize + // the chain as either a splat, a constructor, or an actual series of inserts. + VectorType *VT = III->getType(); + unsigned NumElems = VT->getNumElements(); + unsigned NumInserted = 0; + SmallVector Operands(NumElems, NULL); + const Value *Splat = III->getOperand(1); + const Value *Base = III; + do { + const InsertElementInst *BaseIII = cast(Base); + const ConstantInt *IndexInt = cast(BaseIII->getOperand(2)); + unsigned Index = IndexInt->getZExtValue(); + if (Operands[Index] == NULL) + ++NumInserted; + Value *Op = BaseIII->getOperand(1); + if (Operands[Index] == NULL) { + Operands[Index] = Op; + if (Op != Splat) + Splat = NULL; + } + Base = BaseIII->getOperand(0); + } while (Base->hasOneUse() && isa(Base)); + + // Emit code for the chain. + Code << getAssignIfNeeded(III); + if (NumInserted == NumElems) { + if (Splat) { + // Emit splat code. + if (VT->getElementType()->isIntegerTy()) { + Code << "SIMD_int32x4_splat(" << getValueAsStr(Splat) << ")"; + } else { + Code << "SIMD_float32x4_splat(" << getValueAsStr(Splat) << ")"; + } + } else { + // Emit constructor code. + if (VT->getElementType()->isIntegerTy()) { + Code << "SIMD_int32x4("; + } else { + Code << "SIMD_float32x4("; + } + for (unsigned Index = 0; Index < NumElems; ++Index) { + if (Index != 0) + Code << ", "; + Code << getValueAsStr(Operands[Index]); + } + Code << ")"; + } + } else { + // Emit a series of inserts. + std::string Result = getValueAsStr(Base); + for (unsigned Index = 0; Index < NumElems; ++Index) { + std::string with; + if (!Operands[Index]) + continue; + if (VT->getElementType()->isIntegerTy()) { + with = "SIMD_int32x4_with"; + } else { + with = "SIMD_float32x4_with"; + } + Result = with + SIMDLane[Index] + "(" + Result + ',' + getValueAsStr(Operands[Index]) + ')'; + } + Code << Result; + } +} + bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { VectorType *VT; if ((VT = dyn_cast(I->getType()))) { @@ -1202,21 +1276,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { } break; } - case Instruction::InsertElement: { - const InsertElementInst *III = cast(I); - const ConstantInt *IndexInt = cast(III->getOperand(2)); - unsigned Index = IndexInt->getZExtValue(); - assert(Index <= 3); - Code << getAssignIfNeeded(I); - if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD_int32x4_with"; - } else { - Code << "SIMD_float32x4_with"; - } - Code << SIMDLane[Index]; - Code << "(" << getValueAsStr(III->getOperand(0)) << ',' << getValueAsStr(III->getOperand(1)) << ')'; + case Instruction::InsertElement: + generateInsertElementExpression(cast(I), Code); break; - } case Instruction::ShuffleVector: { Code << getAssignIfNeeded(I); const ShuffleVectorInst *SVI = cast(I); diff --git a/test/CodeGen/JS/insertelement-chains.ll b/test/CodeGen/JS/insertelement-chains.ll new file mode 100644 index 00000000000..e9ffd61bd95 --- /dev/null +++ b/test/CodeGen/JS/insertelement-chains.ll @@ -0,0 +1,88 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "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" +target triple = "asmjs-unknown-emscripten" + +; Basic constructor. + +; CHECK: function _test0($x,$y,$z,$w) { +; CHECK: $d = SIMD_float32x4($x, $y, $z, $w) +; CHECK: } +define <4 x float> @test0(float %x, float %y, float %z, float %w) { + %a = insertelement <4 x float> undef, float %x, i32 0 + %b = insertelement <4 x float> %a, float %y, i32 1 + %c = insertelement <4 x float> %b, float %z, i32 2 + %d = insertelement <4 x float> %c, float %w, i32 3 + ret <4 x float> %d +} + +; Same as test0 but elements inserted in a different order. + +; CHECK: function _test1($x,$y,$z,$w) { +; CHECK: $d = SIMD_float32x4($x, $y, $z, $w) +; CHECK: } +define <4 x float> @test1(float %x, float %y, float %z, float %w) { + %a = insertelement <4 x float> undef, float %w, i32 3 + %b = insertelement <4 x float> %a, float %y, i32 1 + %c = insertelement <4 x float> %b, float %z, i32 2 + %d = insertelement <4 x float> %c, float %x, i32 0 + ret <4 x float> %d +} + +; Overwriting elements. + +; CHECK: function _test2($x,$y,$z,$w) { +; CHECK: $h = SIMD_float32x4($x, $y, $z, $w) +; CHECK: } +define <4 x float> @test2(float %x, float %y, float %z, float %w) { + %a = insertelement <4 x float> undef, float %z, i32 0 + %b = insertelement <4 x float> %a, float %x, i32 0 + %c = insertelement <4 x float> %b, float %w, i32 1 + %d = insertelement <4 x float> %c, float %y, i32 1 + %e = insertelement <4 x float> %d, float %x, i32 2 + %f = insertelement <4 x float> %e, float %z, i32 2 + %g = insertelement <4 x float> %f, float %y, i32 3 + %h = insertelement <4 x float> %g, float %w, i32 3 + ret <4 x float> %h +} + +; Basic splat testcase. + +; CHECK: function _test3($x) { +; CHECK: $d = SIMD_float32x4_splat($x) +; CHECK: } +define <4 x float> @test3(float %x) { + %a = insertelement <4 x float> undef, float %x, i32 0 + %b = insertelement <4 x float> %a, float %x, i32 1 + %c = insertelement <4 x float> %b, float %x, i32 2 + %d = insertelement <4 x float> %c, float %x, i32 3 + ret <4 x float> %d +} + +; Same as test3 but elements inserted in a different order. + +; CHECK: function _test4($x) { +; CHECK: $d = SIMD_float32x4_splat($x) +; CHECK: } +define <4 x float> @test4(float %x) { + %a = insertelement <4 x float> undef, float %x, i32 3 + %b = insertelement <4 x float> %a, float %x, i32 1 + %c = insertelement <4 x float> %b, float %x, i32 2 + %d = insertelement <4 x float> %c, float %x, i32 0 + ret <4 x float> %d +} + +; Insert chain. + +; CHECK: function _test5($x,$y,$z,$w) { +; CHECK: $f = SIMD_float32x4_withZ(SIMD_float32x4_withY(SIMD_float32x4_withX(SIMD_float32x4_splat(Math_fround(0)),$x),$y),$z) +; CHECK: } +define <4 x float> @test5(float %x, float %y, float %z, float %w) { + %a = insertelement <4 x float> undef, float %z, i32 0 + %b = insertelement <4 x float> %a, float %x, i32 0 + %c = insertelement <4 x float> %b, float %w, i32 1 + %d = insertelement <4 x float> %c, float %y, i32 1 + %e = insertelement <4 x float> %d, float %x, i32 2 + %f = insertelement <4 x float> %e, float %z, i32 2 + ret <4 x float> %f +} From e37775be46808390d306ab81601ab5f473e32a44 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 26 Sep 2014 11:47:27 -0700 Subject: [PATCH 7/9] Reference the array buffer directly. Instead of taking the array buffer from the typed array view, just reference the buffer object directly. --- lib/Target/JSBackend/JSBackend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index ac1fbef3a31..78128c37611 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1270,9 +1270,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { std::string PS = getValueAsStr(P); Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD_int32x4_load(HEAPU32.buffer, " << PS << ")"; + Code << "SIMD_int32x4_load(buffer, " << PS << ")"; } else { - Code << "SIMD_float32x4_load(HEAPF32.buffer, " << PS << ")"; + Code << "SIMD_float32x4_load(buffer, " << PS << ")"; } break; } @@ -1394,9 +1394,9 @@ bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { std::string VS = getValueAsStr(SI->getValueOperand()); Code << getAdHocAssign(PS, P->getType()) << getValueAsStr(P) << ';'; if (VT->getElementType()->isIntegerTy()) { - Code << "SIMD_int32x4_store(HEAPU32.buffer, " << PS << ", " << VS << ")"; + Code << "SIMD_int32x4_store(buffer, " << PS << ", " << VS << ")"; } else { - Code << "SIMD_float32x4_store(HEAPF32.buffer, " << PS << ", " << VS << ")"; + Code << "SIMD_float32x4_store(buffer, " << PS << ", " << VS << ")"; } return true; } else if (Operator::getOpcode(I) == Instruction::ExtractElement) { From 6061ad0c1e5d0e40ee6e38d54dc79cafdd9685c8 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 26 Sep 2014 15:29:00 -0700 Subject: [PATCH 8/9] Implement SIMD casts. This uses the new single-argument SIMD constructor. --- lib/Target/JSBackend/JSBackend.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 78128c37611..b2aedf57950 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -679,11 +679,13 @@ std::string JSWriter::getAssignIfNeeded(const Value *V) { std::string JSWriter::getCast(const StringRef &s, Type *t, AsmCast sign) { switch (t->getTypeID()) { default: { - // some types we cannot cast, like vectors - ignore - if (t->isVectorTy()) return s; errs() << *t << "\n"; assert(false && "Unsupported type"); } + case Type::VectorTyID: + return (cast(t)->getElementType()->isIntegerTy() ? + "SIMD_int32x4(" + s + ")" : + "SIMD_float32x4(" + s + ")").str(); case Type::FloatTyID: { if (PreciseF32 && !(sign & ASM_FFI_OUT)) { if (sign & ASM_FFI_IN) { From 2d54400cd76762918e430f8ed48c280f69323fbd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 29 Sep 2014 10:23:37 -0700 Subject: [PATCH 9/9] 1.24.1 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index 7ae54502c61..63fbeafc47e 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.24.0 +1.24.1