From 3294faad0d910008e1c7e6acdc39b5bfa428002a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 11 Aug 2014 14:19:22 +0300 Subject: [PATCH 01/31] Make memory initializer allocation aware of whether running in a pthread. --- lib/Target/JSBackend/JSBackend.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 2035563106d..7f9bfd2f510 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2650,6 +2650,7 @@ void JSWriter::printModuleBody() { assert(GlobalData32.size() == 0 && GlobalData8.size() == 0); // FIXME when we use optimal constant alignments // TODO fix commas + Out << "if (!ENVIRONMENT_IS_PTHREAD) {\n"; Out << "/* memory initializer */ allocate(["; printCommaSeparated(GlobalData64); if (GlobalData64.size() > 0 && GlobalData32.size() + GlobalData8.size() > 0) { @@ -2660,7 +2661,8 @@ void JSWriter::printModuleBody() { Out << ","; } printCommaSeparated(GlobalData8); - Out << "], \"i8\", ALLOC_NONE, Runtime.GLOBAL_BASE);"; + Out << "], \"i8\", ALLOC_NONE, Runtime.GLOBAL_BASE);\n"; + Out << "}\n"; // Emit metadata for emcc driver Out << "\n\n// EMSCRIPTEN_METADATA\n"; From 2c387abc1ca47442b1dd50a7ce213b725d616a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 5 Sep 2014 16:44:40 +0300 Subject: [PATCH 02/31] Implement volatile loads and stores to use Atomics.load and store to guarantee that SpiderMonkey will not optimize those instructions out when executing, and to offer x86-like strong memory consistency across code that uses such constructs. --- lib/Target/JSBackend/JSBackend.cpp | 69 +++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 7f9bfd2f510..e87435b1ee2 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -495,6 +495,7 @@ namespace { } std::string getPtrLoad(const Value* Ptr); + std::string getHeapNameAndIndex(const Value *Ptr, const char **HeapName); 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); @@ -840,18 +841,67 @@ std::string JSWriter::getIMul(const Value *V1, const Value *V2) { return "Math_imul(" + getValueAsStr(V1) + ", " + getValueAsStr(V2) + ")|0"; // unknown or too large, emit imul } +/// Given a pointer to memory, returns the HEAP object and index to that object that is used to access that memory. +/// @param Ptr [in] The heap object. +/// @param HeapName [out] Receives the name of the HEAP object used to perform the memory acess. +/// @return The index to the heap HeapName for the memory access. +std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapName) +{ + Type *t = cast(Ptr->getType())->getElementType(); + unsigned Bytes = DL->getTypeAllocSize(t); + + if (const GlobalVariable *GV = dyn_cast(Ptr)) { + unsigned Addr = getGlobalAddress(GV->getName().str()); + switch (Bytes) { + default: llvm_unreachable("Unsupported type"); + case 8: *HeapName = "HEAPF64"; return utostr(Addr >> 3); + case 4: + if (t->isIntegerTy() || t->isPointerTy()) *HeapName = "HEAP32"; + else *HeapName = "HEAPF32"; + return utostr(Addr >> 2); + case 2: *HeapName = "HEAP16"; return utostr(Addr >> 1); break; + case 1: *HeapName = "HEAP8"; return utostr(Addr); break; + } + } else { + std::string Index = getValueAsStr(Ptr); + switch (Bytes) { + default: llvm_unreachable("Unsupported type"); + case 8: *HeapName = "HEAPF64"; return Index + ">>3"; + case 4: + if (t->isIntegerTy() || t->isPointerTy()) *HeapName = "HEAP32"; + else *HeapName = "HEAPF32"; + return Index + ">>2"; + case 2: *HeapName = "HEAP16"; return Index + ">>1"; + case 1: *HeapName = "HEAP8"; return Index; + } + } +} + std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) { std::string Assign = getAssign(I); unsigned Bytes = DL->getTypeAllocSize(T); std::string text; if (Bytes <= Alignment || Alignment == 0) { - text = Assign + getPtrLoad(P); + if (cast(I)->isVolatile()) { + const char *HeapName; + std::string Index = getHeapNameAndIndex(P, &HeapName); + text = Assign + "Atomics.load(" + HeapName + ',' + Index + ')'; + } else { + text = Assign + getPtrLoad(P); + } if (isAbsolute(P)) { // loads from an absolute constants are either intentional segfaults (int x = *((int*)0)), or code problems text += "; abort() /* segfault, load from absolute addr */"; } } else { // unaligned in some manner + + if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + errs() << "emcc: warning: unable to implement unaligned volatile load as atomic in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; + emitDebugInfo(errs(), I); + errs() << "\n"; + } + if (WarnOnUnaligned) { errs() << "emcc: warning: unaligned load in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; emitDebugInfo(errs(), I); @@ -938,15 +988,30 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns return text; } +static const std::string AtomicsStore = "Atomics.store("; + std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, const std::string& VS, unsigned Alignment, char sep) { assert(sep == ';'); // FIXME when we need that unsigned Bytes = DL->getTypeAllocSize(T); std::string text; if (Bytes <= Alignment || Alignment == 0) { - text = getPtrUse(P) + " = " + VS; + if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + const char *HeapName; + std::string Index = getHeapNameAndIndex(P, &HeapName); + text = AtomicsStore + HeapName + ',' + Index + ',' + VS+ ')'; + } else { + text = getPtrUse(P) + " = " + VS; + } if (Alignment == 536870912) text += "; abort() /* segfault */"; } else { // unaligned in some manner + + if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + errs() << "emcc: warning: unable to implement unaligned volatile store as atomic in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; + emitDebugInfo(errs(), I); + errs() << "\n"; + } + if (WarnOnUnaligned) { errs() << "emcc: warning: unaligned store in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; emitDebugInfo(errs(), I); From ecf31f640bcfac170bd34ec631fd79752e177774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 30 Nov 2014 13:32:36 -0800 Subject: [PATCH 03/31] Add support for LLVM atomics. --- lib/Target/JSBackend/JSBackend.cpp | 55 ++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index e87435b1ee2..809b6db83d1 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2335,21 +2335,46 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { const Value *P = rmwi->getOperand(0); const Value *V = rmwi->getOperand(1); std::string VS = getValueAsStr(V); - Code << getLoad(rmwi, P, I->getType(), 0) << ';'; - // Most bitcasts are no-ops for us. However, the exception is int to float and float to int - switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: Code << getStore(rmwi, P, I->getType(), VS, 0); break; - case AtomicRMWInst::Add: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '+' + VS + ")|0)", 0); break; - case AtomicRMWInst::Sub: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '-' + VS + ")|0)", 0); break; - case AtomicRMWInst::And: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '&' + VS + ")", 0); break; - case AtomicRMWInst::Nand: Code << getStore(rmwi, P, I->getType(), "(~(" + getJSName(I) + '&' + VS + "))", 0); break; - case AtomicRMWInst::Or: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '|' + VS + ")", 0); break; - case AtomicRMWInst::Xor: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '^' + VS + ")", 0); break; - case AtomicRMWInst::Max: - case AtomicRMWInst::Min: - case AtomicRMWInst::UMax: - case AtomicRMWInst::UMin: - case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation"); + + if (true/*compilingWithPthreadsSupport*/) { + std::string Assign = getAssign(rmwi); + unsigned Bytes = DL->getTypeAllocSize(T); + std::string text; + const char *HeapName; + std::string Index = getHeapNameAndIndex(P, &HeapName); + const char *atomicFunc = 0; + switch (rmwi->getOperation()) { + case AtomicRMWInst::Xchg: atomicFunc = "Atomics.compareExchange("; break; + case AtomicRMWInst::Add: atomicFunc = "Atomics.add("; break; + case AtomicRMWInst::Sub: atomicFunc = "Atomics.sub("; break; + case AtomicRMWInst::And: atomicFunc = "Atomics.and("; break; + case AtomicRMWInst::Or: atomicFunc = "Atomics.or("; break; + case AtomicRMWInst::Xor: atomicFunc = "Atomics.xor("; break; + case AtomicRMWInst::Nand: // TODO + case AtomicRMWInst::Max: + case AtomicRMWInst::Min: + case AtomicRMWInst::UMax: + case AtomicRMWInst::UMin: + case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation"); + } + Code << Assign << atomicFunc << HeapName << ", " << Index << ", " << VS << ")"; break; + } else { + Code << getLoad(rmwi, P, I->getType(), 0) << ';'; + // Most bitcasts are no-ops for us. However, the exception is int to float and float to int + switch (rmwi->getOperation()) { + case AtomicRMWInst::Xchg: Code << getStore(rmwi, P, I->getType(), VS, 0); break; + case AtomicRMWInst::Add: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '+' + VS + ")|0)", 0); break; + case AtomicRMWInst::Sub: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '-' + VS + ")|0)", 0); break; + case AtomicRMWInst::And: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '&' + VS + ")", 0); break; + case AtomicRMWInst::Nand: Code << getStore(rmwi, P, I->getType(), "(~(" + getJSName(I) + '&' + VS + "))", 0); break; + case AtomicRMWInst::Or: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '|' + VS + ")", 0); break; + case AtomicRMWInst::Xor: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '^' + VS + ")", 0); break; + case AtomicRMWInst::Max: + case AtomicRMWInst::Min: + case AtomicRMWInst::UMax: + case AtomicRMWInst::UMin: + case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation"); + } } break; } From 919886673a052fe7f947bdef9de533c6cabc93d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 30 Nov 2014 14:46:12 -0800 Subject: [PATCH 04/31] Implement Atomic compare-and-exchange support. --- lib/Target/JSBackend/JSBackend.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 809b6db83d1..34ff57ba3b5 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2330,6 +2330,21 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { getValueAsStr(I->getOperand(2)); break; } + case Instruction::AtomicCmpXchg: { + const AtomicCmpXchgInst *cxi = cast(I); + const Value *P = I->getOperand(0); + if (true/*compilingWithPthreadsSupport*/) { + const char *HeapName; + std::string Index = getHeapNameAndIndex(P, &HeapName); + std::string Assign = getAssign(cxi); + Code << Assign << "Atomics.compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ")"; + } else { + Code << getLoad(cxi, P, I->getType(), 0) << ';' << + "if ((" << getCast(getJSName(I), I->getType()) << ") == " << getValueAsCastParenStr(I->getOperand(1)) << ") " << + getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); + } + break; + } case Instruction::AtomicRMW: { const AtomicRMWInst *rmwi = cast(I); const Value *P = rmwi->getOperand(0); @@ -2344,7 +2359,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); const char *atomicFunc = 0; switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: atomicFunc = "Atomics.compareExchange("; break; + case AtomicRMWInst::Xchg: atomicFunc = "Atomics.store("; break; case AtomicRMWInst::Add: atomicFunc = "Atomics.add("; break; case AtomicRMWInst::Sub: atomicFunc = "Atomics.sub("; break; case AtomicRMWInst::And: atomicFunc = "Atomics.and("; break; From b4a3db71355a45bd826ad46a65bcfc6fb86353a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 30 Nov 2014 15:00:23 -0800 Subject: [PATCH 05/31] Implement Atomic fence support --- lib/Target/JSBackend/JSBackend.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 34ff57ba3b5..2294950d420 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2394,7 +2394,11 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { break; } case Instruction::Fence: // no threads, so nothing to do here - Code << "/* fence */"; + if (true/*compilingWithPthreadsSupport*/) { + Code << "Atomics.fence()"; + } else { + Code << "/* fence */"; + } break; } From 1ed5faa5e3d0d1b0f72eee2f8a7189e8723363dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 19 Jan 2015 09:48:24 +0200 Subject: [PATCH 06/31] Add support for AtomicCmpXchg instruction for pthreads. --- lib/Target/JSBackend/JSBackend.cpp | 17 ++++++++++++++--- lib/Transforms/NaCl/RewriteAtomics.cpp | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 2294950d420..46be905f7d6 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1936,7 +1936,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { if (!generateSIMDExpression(I, Code)) switch (Operator::getOpcode(I)) { default: { I->dump(); - error("Invalid instruction"); + error("Invalid instruction in JSWriter::generateExpression"); break; } case Instruction::Ret: { @@ -2330,18 +2330,29 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { getValueAsStr(I->getOperand(2)); break; } + case Instruction::ExtractValue: { + const ExtractValueInst *evi = cast(I); + std::string Assign = getAssign(evi); + Code << Assign << getValueAsStr(I->getOperand(0)) << "_" << evi->idx_begin()[0]; + break; + } case Instruction::AtomicCmpXchg: { const AtomicCmpXchgInst *cxi = cast(I); const Value *P = I->getOperand(0); if (true/*compilingWithPthreadsSupport*/) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); - std::string Assign = getAssign(cxi); - Code << Assign << "Atomics.compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ")"; + //std::string Assign = getAssign(cxi); + std::string Assign = getJSName(I); + Code << Assign << "_0 = Atomics.compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; + Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0)"; } else { + report_fatal_error("TODO: AtomicCmpXchg without pthreads not currently supported!"); + /* Code << getLoad(cxi, P, I->getType(), 0) << ';' << "if ((" << getCast(getJSName(I), I->getType()) << ") == " << getValueAsCastParenStr(I->getOperand(1)) << ") " << getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); + */ } break; } diff --git a/lib/Transforms/NaCl/RewriteAtomics.cpp b/lib/Transforms/NaCl/RewriteAtomics.cpp index a1b99e31b68..6722f46a47f 100644 --- a/lib/Transforms/NaCl/RewriteAtomics.cpp +++ b/lib/Transforms/NaCl/RewriteAtomics.cpp @@ -379,6 +379,7 @@ void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { /// %success = icmp eq %old, %val /// Note: weak is currently dropped if present, the cmpxchg is always strong. void AtomicVisitor::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { + return; // XXX EMSCRIPTEN PointerHelper PH(*this, I); const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = findAtomicIntrinsic(I, Intrinsic::nacl_atomic_cmpxchg, PH.PET); From 4b51d3f9ee6a3e9bfe9b129801cc3a32aec63034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 19 Jan 2015 14:02:08 +0200 Subject: [PATCH 07/31] Make Atomics API asm.js compliant. --- lib/Target/JSBackend/JSBackend.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 46be905f7d6..e8656a36f4c 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -885,7 +885,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns if (cast(I)->isVolatile()) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); - text = Assign + "Atomics.load(" + HeapName + ',' + Index + ')'; + text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; } else { text = Assign + getPtrLoad(P); } @@ -988,7 +988,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns return text; } -static const std::string AtomicsStore = "Atomics.store("; +static const std::string AtomicsStore = "Atomics_store("; std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, const std::string& VS, unsigned Alignment, char sep) { assert(sep == ';'); // FIXME when we need that @@ -2344,7 +2344,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); //std::string Assign = getAssign(cxi); std::string Assign = getJSName(I); - Code << Assign << "_0 = Atomics.compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; + Code << Assign << "_0 = Atomics_compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0)"; } else { report_fatal_error("TODO: AtomicCmpXchg without pthreads not currently supported!"); @@ -2370,12 +2370,12 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); const char *atomicFunc = 0; switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: atomicFunc = "Atomics.store("; break; - case AtomicRMWInst::Add: atomicFunc = "Atomics.add("; break; - case AtomicRMWInst::Sub: atomicFunc = "Atomics.sub("; break; - case AtomicRMWInst::And: atomicFunc = "Atomics.and("; break; - case AtomicRMWInst::Or: atomicFunc = "Atomics.or("; break; - case AtomicRMWInst::Xor: atomicFunc = "Atomics.xor("; break; + case AtomicRMWInst::Xchg: atomicFunc = "Atomics_store("; break; + case AtomicRMWInst::Add: atomicFunc = "Atomics_add("; break; + case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub("; break; + case AtomicRMWInst::And: atomicFunc = "Atomics_and("; break; + case AtomicRMWInst::Or: atomicFunc = "Atomics_or("; break; + case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor("; break; case AtomicRMWInst::Nand: // TODO case AtomicRMWInst::Max: case AtomicRMWInst::Min: @@ -2406,7 +2406,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { } case Instruction::Fence: // no threads, so nothing to do here if (true/*compilingWithPthreadsSupport*/) { - Code << "Atomics.fence()"; + Code << "Atomics_fence()"; } else { Code << "/* fence */"; } From f6980c0736b1b6b415e9346d99206997023251a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 19 Jan 2015 14:49:45 +0200 Subject: [PATCH 08/31] Add call handlers to built-in functions emscripten_atomic_cas_* so that these route to more performant asm.js functions without taking a route to handwritten JS. --- lib/Target/JSBackend/CallHandlers.h | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 50702e36f40..936e1d15049 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -549,6 +549,35 @@ DEF_CALL_HANDLER(emscripten_asm_const_double, { return getAssign(CI) + getCast(handleAsmConst(CI), Type::getDoubleTy(CI->getContext())); }) +std::string getAddressAsString(const Value *Ptr, int shift) { + Type *t = cast(Ptr->getType())->getElementType(); + if (const GlobalVariable *GV = dyn_cast(Ptr)) { + return utostr(getGlobalAddress(GV->getName().str()) >> shift); + } else { + return getValueAsStr(Ptr) + ">>" + utostr(shift); + } +} + +DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { + return getAssign(CI) + "Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_cas_u16, { + return getAssign(CI) + "Atomics_compareExchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_cas_u32, { + return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_cas_f32, { + return getAssign(CI) + "Atomics_compareExchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_cas_f64, { + return getAssign(CI) + "Atomics_compareExchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + #define DEF_BUILTIN_HANDLER(name, to) \ DEF_CALL_HANDLER(name, { \ return CH___default__(CI, #to); \ @@ -727,6 +756,12 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_asm_const_int); SETUP_CALL_HANDLER(emscripten_asm_const_double); + SETUP_CALL_HANDLER(emscripten_atomic_cas_u8); + SETUP_CALL_HANDLER(emscripten_atomic_cas_u16); + SETUP_CALL_HANDLER(emscripten_atomic_cas_u32); + SETUP_CALL_HANDLER(emscripten_atomic_cas_f32); + SETUP_CALL_HANDLER(emscripten_atomic_cas_f64); + SETUP_CALL_HANDLER(abs); SETUP_CALL_HANDLER(labs); SETUP_CALL_HANDLER(cos); From 2cb9593223d9fe03f690286aec6c6f921c767db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 19 Jan 2015 16:41:34 +0200 Subject: [PATCH 09/31] Add direct asm.js call handlers for Atomics operations. --- lib/Target/JSBackend/CallHandlers.h | 161 +++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 4 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 936e1d15049..ba655b0c3cd 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -561,23 +561,131 @@ std::string getAddressAsString(const Value *Ptr, int shift) { DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { return getAssign(CI) + "Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) - DEF_CALL_HANDLER(emscripten_atomic_cas_u16, { return getAssign(CI) + "Atomics_compareExchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) - DEF_CALL_HANDLER(emscripten_atomic_cas_u32, { return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) - DEF_CALL_HANDLER(emscripten_atomic_cas_f32, { return getAssign(CI) + "Atomics_compareExchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) - DEF_CALL_HANDLER(emscripten_atomic_cas_f64, { return getAssign(CI) + "Atomics_compareExchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) +DEF_CALL_HANDLER(emscripten_atomic_load_u8, { + return getAssign(CI) + "Atomics_load(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_load_u16, { + return getAssign(CI) + "Atomics_load(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_load_u32, { + return getAssign(CI) + "Atomics_load(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_load_f32, { + return getAssign(CI) + "Atomics_load(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_load_f64, { + return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_store_u8, { + return getAssign(CI) + "Atomics_store(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_store_u16, { + return getAssign(CI) + "Atomics_store(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_store_u32, { + return getAssign(CI) + "Atomics_store(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_store_f32, { + return getAssign(CI) + "Atomics_store(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_store_f64, { + return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_add_u8, { + return getAssign(CI) + "Atomics_add(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_add_u16, { + return getAssign(CI) + "Atomics_add(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_add_u32, { + return getAssign(CI) + "Atomics_add(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_add_f32, { + return getAssign(CI) + "Atomics_add(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_add_f64, { + return getAssign(CI) + "Atomics_add(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_sub_u8, { + return getAssign(CI) + "Atomics_sub(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_sub_u16, { + return getAssign(CI) + "Atomics_sub(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_sub_u32, { + return getAssign(CI) + "Atomics_sub(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_sub_f32, { + return getAssign(CI) + "Atomics_sub(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_sub_f64, { + return getAssign(CI) + "Atomics_sub(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_and_u8, { + return getAssign(CI) + "Atomics_and(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_and_u16, { + return getAssign(CI) + "Atomics_and(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_and_u32, { + return getAssign(CI) + "Atomics_and(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_and_f32, { + return getAssign(CI) + "Atomics_and(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_and_f64, { + return getAssign(CI) + "Atomics_and(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_or_u8, { + return getAssign(CI) + "Atomics_or(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_or_u16, { + return getAssign(CI) + "Atomics_or(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_or_u32, { + return getAssign(CI) + "Atomics_or(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_or_f32, { + return getAssign(CI) + "Atomics_or(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_or_f64, { + return getAssign(CI) + "Atomics_or(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + +DEF_CALL_HANDLER(emscripten_atomic_xor_u8, { + return getAssign(CI) + "Atomics_xor(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_xor_u16, { + return getAssign(CI) + "Atomics_xor(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_xor_u32, { + return getAssign(CI) + "Atomics_xor(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_xor_f32, { + return getAssign(CI) + "Atomics_xor(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_xor_f64, { + return getAssign(CI) + "Atomics_xor(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +}) + #define DEF_BUILTIN_HANDLER(name, to) \ DEF_CALL_HANDLER(name, { \ return CH___default__(CI, #to); \ @@ -666,6 +774,7 @@ DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThanOrEqual, SIMD_int32x4_greaterT 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); +DEF_BUILTIN_HANDLER(emscripten_atomic_fence, Atomics_fence); // Setups @@ -762,6 +871,50 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_atomic_cas_f32); SETUP_CALL_HANDLER(emscripten_atomic_cas_f64); + SETUP_CALL_HANDLER(emscripten_atomic_load_u8); + SETUP_CALL_HANDLER(emscripten_atomic_load_u16); + SETUP_CALL_HANDLER(emscripten_atomic_load_u32); + SETUP_CALL_HANDLER(emscripten_atomic_load_f32); + SETUP_CALL_HANDLER(emscripten_atomic_load_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_store_u8); + SETUP_CALL_HANDLER(emscripten_atomic_store_u16); + SETUP_CALL_HANDLER(emscripten_atomic_store_u32); + SETUP_CALL_HANDLER(emscripten_atomic_store_f32); + SETUP_CALL_HANDLER(emscripten_atomic_store_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_add_u8); + SETUP_CALL_HANDLER(emscripten_atomic_add_u16); + SETUP_CALL_HANDLER(emscripten_atomic_add_u32); + SETUP_CALL_HANDLER(emscripten_atomic_add_f32); + SETUP_CALL_HANDLER(emscripten_atomic_add_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_sub_u8); + SETUP_CALL_HANDLER(emscripten_atomic_sub_u16); + SETUP_CALL_HANDLER(emscripten_atomic_sub_u32); + SETUP_CALL_HANDLER(emscripten_atomic_sub_f32); + SETUP_CALL_HANDLER(emscripten_atomic_sub_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_and_u8); + SETUP_CALL_HANDLER(emscripten_atomic_and_u16); + SETUP_CALL_HANDLER(emscripten_atomic_and_u32); + SETUP_CALL_HANDLER(emscripten_atomic_and_f32); + SETUP_CALL_HANDLER(emscripten_atomic_and_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_or_u8); + SETUP_CALL_HANDLER(emscripten_atomic_or_u16); + SETUP_CALL_HANDLER(emscripten_atomic_or_u32); + SETUP_CALL_HANDLER(emscripten_atomic_or_f32); + SETUP_CALL_HANDLER(emscripten_atomic_or_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_xor_u8); + SETUP_CALL_HANDLER(emscripten_atomic_xor_u16); + SETUP_CALL_HANDLER(emscripten_atomic_xor_u32); + SETUP_CALL_HANDLER(emscripten_atomic_xor_f32); + SETUP_CALL_HANDLER(emscripten_atomic_xor_f64); + + SETUP_CALL_HANDLER(emscripten_atomic_fence); + SETUP_CALL_HANDLER(abs); SETUP_CALL_HANDLER(labs); SETUP_CALL_HANDLER(cos); From 9eeb1e81a640bc0e1cf5fdd83b6260cf0587be2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 10 Feb 2015 22:02:09 +0200 Subject: [PATCH 10/31] Emulate HEAPF32 and HEAPF64 Atomic loads and stores in the absence of actual operations in the Atomics API. --- lib/Target/JSBackend/CallHandlers.h | 50 +++++++++++++---------------- lib/Target/JSBackend/JSBackend.cpp | 47 +++++++++++++++++++++------ 2 files changed, 60 insertions(+), 37 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index ba655b0c3cd..91471755304 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -568,9 +568,11 @@ DEF_CALL_HANDLER(emscripten_atomic_cas_u32, { return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_cas_f32, { + errs() << "emcc: warning: float32 compare-and-swap is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_compareExchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_cas_f64, { + errs() << "emcc: warning: float64 compare-and-swap is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_compareExchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) @@ -584,10 +586,16 @@ DEF_CALL_HANDLER(emscripten_atomic_load_u32, { return getAssign(CI) + "Atomics_load(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_f32, { - return getAssign(CI) + "Atomics_load(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, + // we must emulate manually. + return getAssign(CI) + "__Atomics_load_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + ")"; +// return getAssign(CI) + "Atomics_load(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_f64, { - return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, + // we must emulate manually. + return getAssign(CI) + "__Atomics_load_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ")"; +// return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_u8, { @@ -600,10 +608,16 @@ DEF_CALL_HANDLER(emscripten_atomic_store_u32, { return getAssign(CI) + "Atomics_store(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_f32, { - return getAssign(CI) + "Atomics_store(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, + // we must emulate manually. + return getAssign(CI) + "__Atomics_store_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +// return getAssign(CI) + "Atomics_store(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_f64, { - return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, + // we must emulate manually. + return getAssign(CI) + "__Atomics_store_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +// return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_u8, { @@ -616,9 +630,11 @@ DEF_CALL_HANDLER(emscripten_atomic_add_u32, { return getAssign(CI) + "Atomics_add(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_f32, { + errs() << "emcc: warning: float32 atomic add is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_add(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_f64, { + errs() << "emcc: warning: float64 atomic add is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_add(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) @@ -632,9 +648,11 @@ DEF_CALL_HANDLER(emscripten_atomic_sub_u32, { return getAssign(CI) + "Atomics_sub(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_f32, { + errs() << "emcc: warning: float32 atomic sub is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_sub(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_f64, { + errs() << "emcc: warning: float64 atomic sub is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; return getAssign(CI) + "Atomics_sub(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) @@ -647,12 +665,6 @@ DEF_CALL_HANDLER(emscripten_atomic_and_u16, { DEF_CALL_HANDLER(emscripten_atomic_and_u32, { return getAssign(CI) + "Atomics_and(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) -DEF_CALL_HANDLER(emscripten_atomic_and_f32, { - return getAssign(CI) + "Atomics_and(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_atomic_and_f64, { - return getAssign(CI) + "Atomics_and(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) DEF_CALL_HANDLER(emscripten_atomic_or_u8, { return getAssign(CI) + "Atomics_or(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; @@ -663,12 +675,6 @@ DEF_CALL_HANDLER(emscripten_atomic_or_u16, { DEF_CALL_HANDLER(emscripten_atomic_or_u32, { return getAssign(CI) + "Atomics_or(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) -DEF_CALL_HANDLER(emscripten_atomic_or_f32, { - return getAssign(CI) + "Atomics_or(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_atomic_or_f64, { - return getAssign(CI) + "Atomics_or(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) DEF_CALL_HANDLER(emscripten_atomic_xor_u8, { return getAssign(CI) + "Atomics_xor(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; @@ -679,12 +685,6 @@ DEF_CALL_HANDLER(emscripten_atomic_xor_u16, { DEF_CALL_HANDLER(emscripten_atomic_xor_u32, { return getAssign(CI) + "Atomics_xor(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) -DEF_CALL_HANDLER(emscripten_atomic_xor_f32, { - return getAssign(CI) + "Atomics_xor(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_atomic_xor_f64, { - return getAssign(CI) + "Atomics_xor(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -}) #define DEF_BUILTIN_HANDLER(name, to) \ DEF_CALL_HANDLER(name, { \ @@ -898,20 +898,14 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_atomic_and_u8); SETUP_CALL_HANDLER(emscripten_atomic_and_u16); SETUP_CALL_HANDLER(emscripten_atomic_and_u32); - SETUP_CALL_HANDLER(emscripten_atomic_and_f32); - SETUP_CALL_HANDLER(emscripten_atomic_and_f64); SETUP_CALL_HANDLER(emscripten_atomic_or_u8); SETUP_CALL_HANDLER(emscripten_atomic_or_u16); SETUP_CALL_HANDLER(emscripten_atomic_or_u32); - SETUP_CALL_HANDLER(emscripten_atomic_or_f32); - SETUP_CALL_HANDLER(emscripten_atomic_or_f64); SETUP_CALL_HANDLER(emscripten_atomic_xor_u8); SETUP_CALL_HANDLER(emscripten_atomic_xor_u16); SETUP_CALL_HANDLER(emscripten_atomic_xor_u32); - SETUP_CALL_HANDLER(emscripten_atomic_xor_f32); - SETUP_CALL_HANDLER(emscripten_atomic_xor_f64); SETUP_CALL_HANDLER(emscripten_atomic_fence); diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index e8656a36f4c..7fb59a4e4ca 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -496,6 +496,7 @@ namespace { std::string getPtrLoad(const Value* Ptr); std::string getHeapNameAndIndex(const Value *Ptr, const char **HeapName); + std::string getByteAddressAsStr(const Value *Ptr); 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); @@ -877,6 +878,16 @@ std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapNam } } +std::string JSWriter::getByteAddressAsStr(const Value *Ptr) +{ + Type *t = cast(Ptr->getType())->getElementType(); + if (const GlobalVariable *GV = dyn_cast(Ptr)) { + return utostr(getGlobalAddress(GV->getName().str())); + } else { + return getValueAsStr(Ptr); + } +} + std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) { std::string Assign = getAssign(I); unsigned Bytes = DL->getTypeAllocSize(T); @@ -885,7 +896,13 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns if (cast(I)->isVolatile()) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); - text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; + if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are + // implemented, we could remove the emulation, but until then we must emulate manually. + text = Assign + "__Atomics_load_" + HeapName + "_emulated(" + getByteAddressAsStr(P) + ')'; + } else { + text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; + } } else { text = Assign + getPtrLoad(P); } @@ -998,7 +1015,13 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); - text = AtomicsStore + HeapName + ',' + Index + ',' + VS+ ')'; + if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are + // implemented, we could remove the emulation, but until then we must emulate manually. + text = std::string("__Atomics_store_") + HeapName + "_emulated(" + getByteAddressAsStr(P) + ',' + VS + ')'; + } else { + text = AtomicsStore + HeapName + ',' + Index + ',' + VS + ')'; + } } else { text = getPtrUse(P) + " = " + VS; } @@ -2370,12 +2393,12 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); const char *atomicFunc = 0; switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: atomicFunc = "Atomics_store("; break; - case AtomicRMWInst::Add: atomicFunc = "Atomics_add("; break; - case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub("; break; - case AtomicRMWInst::And: atomicFunc = "Atomics_and("; break; - case AtomicRMWInst::Or: atomicFunc = "Atomics_or("; break; - case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor("; break; + case AtomicRMWInst::Xchg: atomicFunc = "Atomics_store"; break; + case AtomicRMWInst::Add: atomicFunc = "Atomics_add"; break; + case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub"; break; + case AtomicRMWInst::And: atomicFunc = "Atomics_and"; break; + case AtomicRMWInst::Or: atomicFunc = "Atomics_or"; break; + case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor"; break; case AtomicRMWInst::Nand: // TODO case AtomicRMWInst::Max: case AtomicRMWInst::Min: @@ -2383,7 +2406,13 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { case AtomicRMWInst::UMin: case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation"); } - Code << Assign << atomicFunc << HeapName << ", " << Index << ", " << VS << ")"; break; + if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { + // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are + // implemented, we could remove the emulation, but until then we must emulate manually. + Code << Assign << "__" << atomicFunc << HeapName << "_emulated(" << getByteAddressAsStr(P) << ", " << VS << ")"; break; + } else { + Code << Assign << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; + } } else { Code << getLoad(rmwi, P, I->getType(), 0) << ';'; // Most bitcasts are no-ops for us. However, the exception is int to float and float to int From a0804f03af7d5e3b8b80e0c25e7c9e7a8ee5579a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 21 Feb 2015 23:29:04 +0200 Subject: [PATCH 11/31] Add a backend command line parameter -emscripten-enable-pthreads to control whether targeting multithreading with Atomics and SAB or not. --- lib/Target/JSBackend/JSBackend.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 7fb59a4e4ca..b686b355b3e 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -68,6 +68,11 @@ PreciseF32("emscripten-precise-f32", cl::desc("Enables Math.fround usage to implement precise float32 semantics and performance (see emscripten PRECISE_F32 option)"), cl::init(false)); +static cl::opt +EnablePthreads("emscripten-enable-pthreads", + cl::desc("Enables compilation targeting JavaScript Shared Array Buffer and Atomics API to implement support for pthreads-based multithreading"), + cl::init(false)); + static cl::opt WarnOnUnaligned("emscripten-warn-unaligned", cl::desc("Warns about unaligned loads and stores (which can negatively affect performance)"), @@ -913,7 +918,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns } else { // unaligned in some manner - if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + if (EnablePthreads && cast(I)->isVolatile()) { errs() << "emcc: warning: unable to implement unaligned volatile load as atomic in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; emitDebugInfo(errs(), I); errs() << "\n"; @@ -1012,7 +1017,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co unsigned Bytes = DL->getTypeAllocSize(T); std::string text; if (Bytes <= Alignment || Alignment == 0) { - if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + if (EnablePthreads && cast(I)->isVolatile()) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { @@ -1029,7 +1034,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co } else { // unaligned in some manner - if (true/*compilingWithPthreadsSupport*/ && cast(I)->isVolatile()) { + if (EnablePthreads && cast(I)->isVolatile()) { errs() << "emcc: warning: unable to implement unaligned volatile store as atomic in " << I->getParent()->getParent()->getName() << ":" << *I << " | "; emitDebugInfo(errs(), I); errs() << "\n"; @@ -2362,7 +2367,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { case Instruction::AtomicCmpXchg: { const AtomicCmpXchgInst *cxi = cast(I); const Value *P = I->getOperand(0); - if (true/*compilingWithPthreadsSupport*/) { + if (EnablePthreads) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); //std::string Assign = getAssign(cxi); @@ -2385,7 +2390,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { const Value *V = rmwi->getOperand(1); std::string VS = getValueAsStr(V); - if (true/*compilingWithPthreadsSupport*/) { + if (EnablePthreads) { std::string Assign = getAssign(rmwi); unsigned Bytes = DL->getTypeAllocSize(T); std::string text; @@ -2434,7 +2439,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { break; } case Instruction::Fence: // no threads, so nothing to do here - if (true/*compilingWithPthreadsSupport*/) { + if (EnablePthreads) { Code << "Atomics_fence()"; } else { Code << "/* fence */"; From b4bcbe273d665bb05cb75a165041f6cb1fca71fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 22 Feb 2015 01:19:58 +0200 Subject: [PATCH 12/31] Implement support for AtomicCmpXchg when not compiling with pthreads support enabled. --- lib/Target/JSBackend/JSBackend.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index b686b355b3e..1716cfbebe9 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2367,20 +2367,16 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { case Instruction::AtomicCmpXchg: { const AtomicCmpXchgInst *cxi = cast(I); const Value *P = I->getOperand(0); + const char *HeapName; + std::string Index = getHeapNameAndIndex(P, &HeapName); + std::string Assign = getJSName(I); if (EnablePthreads) { - const char *HeapName; - std::string Index = getHeapNameAndIndex(P, &HeapName); - //std::string Assign = getAssign(cxi); - std::string Assign = getJSName(I); Code << Assign << "_0 = Atomics_compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0)"; } else { - report_fatal_error("TODO: AtomicCmpXchg without pthreads not currently supported!"); - /* - Code << getLoad(cxi, P, I->getType(), 0) << ';' << - "if ((" << getCast(getJSName(I), I->getType()) << ") == " << getValueAsCastParenStr(I->getOperand(1)) << ") " << - getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); - */ + Code << Assign << "_0 = " << HeapName << "[" << Index << "];\n"; + Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0); "; + Code << "if (" << Assign << "_1) " << getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); } break; } From 9e2c3abf023464377565da5373bfed99deaf480d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sun, 22 Feb 2015 01:39:22 +0200 Subject: [PATCH 13/31] Add missing check for not emitting atomic loads when not building with pthreads enabled. --- lib/Target/JSBackend/JSBackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 1716cfbebe9..2cd150b4165 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -898,7 +898,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns unsigned Bytes = DL->getTypeAllocSize(T); std::string text; if (Bytes <= Alignment || Alignment == 0) { - if (cast(I)->isVolatile()) { + if (EnablePthreads && cast(I)->isVolatile()) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { From 61e6276e5b588256f0420cbc1c7d2ca94ec31175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 24 Mar 2015 17:20:50 +0200 Subject: [PATCH 14/31] Apply review formatting. --- lib/Target/JSBackend/JSBackend.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 2cd150b4165..5fa9318433d 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1010,8 +1010,6 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns return text; } -static const std::string AtomicsStore = "Atomics_store("; - std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, const std::string& VS, unsigned Alignment, char sep) { assert(sep == ';'); // FIXME when we need that unsigned Bytes = DL->getTypeAllocSize(T); @@ -1025,7 +1023,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co // implemented, we could remove the emulation, but until then we must emulate manually. text = std::string("__Atomics_store_") + HeapName + "_emulated(" + getByteAddressAsStr(P) + ',' + VS + ')'; } else { - text = AtomicsStore + HeapName + ',' + Index + ',' + VS + ')'; + text = std::string("Atomics_store(") + HeapName + ',' + Index + ',' + VS + ')'; } } else { text = getPtrUse(P) + " = " + VS; From 402699ef2dce4d032ea423a5fa8e47e2abfb2155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 24 Mar 2015 17:56:51 +0200 Subject: [PATCH 15/31] Register the variables required to implement Instruction::AtomicCmpXchg support to UsedVars in JSBackend.cpp. --- lib/Target/JSBackend/JSBackend.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 5fa9318433d..54ba8d5d245 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2368,13 +2368,15 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); std::string Assign = getJSName(I); + UsedVars[Assign + "_0"] = I->getOperand(1)->getType(); + UsedVars[Assign + "_1"] = Type::getInt1Ty(P->getContext()); if (EnablePthreads) { Code << Assign << "_0 = Atomics_compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0)"; } else { Code << Assign << "_0 = " << HeapName << "[" << Index << "];\n"; Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0); "; - Code << "if (" << Assign << "_1) " << getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); + Code << "if (" << Assign << "_1) " << getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); } break; } From 0b4e68cd7078e5f4b665c4a9cd2e7fbd59c8ed02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 24 Mar 2015 17:58:11 +0200 Subject: [PATCH 16/31] Align whitespace in AtomicRMWInst switch-cases in JSBackend.cpp. --- lib/Target/JSBackend/JSBackend.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 54ba8d5d245..9f501b823b7 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2395,11 +2395,11 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { const char *atomicFunc = 0; switch (rmwi->getOperation()) { case AtomicRMWInst::Xchg: atomicFunc = "Atomics_store"; break; - case AtomicRMWInst::Add: atomicFunc = "Atomics_add"; break; - case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub"; break; - case AtomicRMWInst::And: atomicFunc = "Atomics_and"; break; - case AtomicRMWInst::Or: atomicFunc = "Atomics_or"; break; - case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor"; break; + case AtomicRMWInst::Add: atomicFunc = "Atomics_add"; break; + case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub"; break; + case AtomicRMWInst::And: atomicFunc = "Atomics_and"; break; + case AtomicRMWInst::Or: atomicFunc = "Atomics_or"; break; + case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor"; break; case AtomicRMWInst::Nand: // TODO case AtomicRMWInst::Max: case AtomicRMWInst::Min: @@ -2419,7 +2419,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { // Most bitcasts are no-ops for us. However, the exception is int to float and float to int switch (rmwi->getOperation()) { case AtomicRMWInst::Xchg: Code << getStore(rmwi, P, I->getType(), VS, 0); break; - case AtomicRMWInst::Add: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '+' + VS + ")|0)", 0); break; + case AtomicRMWInst::Add: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '+' + VS + ")|0)", 0); break; case AtomicRMWInst::Sub: Code << getStore(rmwi, P, I->getType(), "((" + getJSName(I) + '-' + VS + ")|0)", 0); break; case AtomicRMWInst::And: Code << getStore(rmwi, P, I->getType(), "(" + getJSName(I) + '&' + VS + ")", 0); break; case AtomicRMWInst::Nand: Code << getStore(rmwi, P, I->getType(), "(~(" + getJSName(I) + '&' + VS + "))", 0); break; From 173e6f6a2ebff3b77139864ed9f1207d0f744b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 24 Mar 2015 17:59:34 +0200 Subject: [PATCH 17/31] Clarify comment in Instruction::Fence() for JSBackend.cpp. --- lib/Target/JSBackend/JSBackend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 9f501b823b7..13256c59978 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2434,11 +2434,11 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { } break; } - case Instruction::Fence: // no threads, so nothing to do here + case Instruction::Fence: if (EnablePthreads) { Code << "Atomics_fence()"; } else { - Code << "/* fence */"; + Code << "/* fence */"; // no threads, so nothing to do here } break; } From 900826db8c4167ba5921d762df2ebe34cba489a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 24 Mar 2015 18:05:09 +0200 Subject: [PATCH 18/31] Do not emit "if (!ENVIRONMENT_IS_PTHREAD)" at all when not building with pthreads enabled in JSBackend.cpp. --- lib/Target/JSBackend/JSBackend.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 13256c59978..edc992c1503 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2799,9 +2799,11 @@ void JSWriter::printModuleBody() { assert(GlobalData32.size() == 0 && GlobalData8.size() == 0); // FIXME when we use optimal constant alignments - // TODO fix commas - Out << "if (!ENVIRONMENT_IS_PTHREAD) {\n"; + if (EnablePthreads) { + Out << "if (!ENVIRONMENT_IS_PTHREAD) {\n"; + } Out << "/* memory initializer */ allocate(["; + // TODO fix commas printCommaSeparated(GlobalData64); if (GlobalData64.size() > 0 && GlobalData32.size() + GlobalData8.size() > 0) { Out << ","; @@ -2812,7 +2814,9 @@ void JSWriter::printModuleBody() { } printCommaSeparated(GlobalData8); Out << "], \"i8\", ALLOC_NONE, Runtime.GLOBAL_BASE);\n"; - Out << "}\n"; + if (EnablePthreads) { + Out << "}\n"; + } // Emit metadata for emcc driver Out << "\n\n// EMSCRIPTEN_METADATA\n"; From dac35354f6e8a1acad597dfdfa4c2efa72817e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 15 Apr 2015 12:40:57 +0300 Subject: [PATCH 19/31] Fix asm.js validation when code emits atomic operations to f32 and f64 types. --- lib/Target/JSBackend/CallHandlers.h | 4 ++-- lib/Target/JSBackend/JSBackend.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 91471755304..3c4bd925fa7 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -588,13 +588,13 @@ DEF_CALL_HANDLER(emscripten_atomic_load_u32, { DEF_CALL_HANDLER(emscripten_atomic_load_f32, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "__Atomics_load_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + ")"; + return getAssign(CI) + (PreciseF32 ? "Math_fround(" : "+") + "__Atomics_load_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + (PreciseF32 ? "))" : ")"); // return getAssign(CI) + "Atomics_load(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "__Atomics_load_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ")"; + return getAssign(CI) + "+__Atomics_load_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ")"; // return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; }) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index edc992c1503..26d9ab13259 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -902,9 +902,10 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns const char *HeapName; std::string Index = getHeapNameAndIndex(P, &HeapName); if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { + bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - text = Assign + "__Atomics_load_" + HeapName + "_emulated(" + getByteAddressAsStr(P) + ')'; + text = Assign + (fround ? "Math_fround(" : "+") + "__Atomics_load_" + HeapName + "_emulated(" + getByteAddressAsStr(P) + (fround ? "))" : ")"); } else { text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; } @@ -2410,7 +2411,8 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - Code << Assign << "__" << atomicFunc << HeapName << "_emulated(" << getByteAddressAsStr(P) << ", " << VS << ")"; break; + bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); + Code << Assign << (fround ? "Math_fround(" : "+") << "__" << atomicFunc << HeapName << "_emulated(" << getByteAddressAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; } else { Code << Assign << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; } From afb0efbdb162567e041639bec8a71400d1a5d0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 28 Apr 2015 16:10:50 +0300 Subject: [PATCH 20/31] Add support for more emulated 64bit operations. --- lib/Target/JSBackend/CallHandlers.h | 6 +++--- lib/Target/JSBackend/JSBackend.cpp | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 3c4bd925fa7..5956f1343ee 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -594,7 +594,7 @@ DEF_CALL_HANDLER(emscripten_atomic_load_f32, { DEF_CALL_HANDLER(emscripten_atomic_load_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "+__Atomics_load_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ")"; + return getAssign(CI) + "+_emscripten_atomic_load_f64(" + getAddressAsString(CI->getOperand(0), 3) + ")"; // return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; }) @@ -610,13 +610,13 @@ DEF_CALL_HANDLER(emscripten_atomic_store_u32, { DEF_CALL_HANDLER(emscripten_atomic_store_f32, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "__Atomics_store_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "_emscripten_atomic_store_f32(" + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; // return getAssign(CI) + "Atomics_store(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "__Atomics_store_f64_emulated(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "_emscripten_atomic_store_f64(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; // return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 26d9ab13259..63945f3c902 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -893,6 +893,13 @@ std::string JSWriter::getByteAddressAsStr(const Value *Ptr) } } +static const char *heapNameToAtomicTypeName(const char *HeapName) +{ + if (!strcmp(HeapName, "HEAPF32")) return "f32"; + if (!strcmp(HeapName, "HEAPF64")) return "f64"; + return ""; +} + std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) { std::string Assign = getAssign(I); unsigned Bytes = DL->getTypeAllocSize(T); @@ -905,7 +912,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - text = Assign + (fround ? "Math_fround(" : "+") + "__Atomics_load_" + HeapName + "_emulated(" + getByteAddressAsStr(P) + (fround ? "))" : ")"); + text = Assign + (fround ? "Math_fround(" : "+") + "_emscripten_atomic_load_" + heapNameToAtomicTypeName(HeapName) + "(" + getByteAddressAsStr(P) + (fround ? "))" : ")"); } else { text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; } @@ -1022,7 +1029,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - text = std::string("__Atomics_store_") + HeapName + "_emulated(" + getByteAddressAsStr(P) + ',' + VS + ')'; + text = std::string("_emscripten_atomic_store_") + heapNameToAtomicTypeName(HeapName) + "(" + getByteAddressAsStr(P) + ',' + VS + ')'; } else { text = std::string("Atomics_store(") + HeapName + ',' + Index + ',' + VS + ')'; } @@ -2395,12 +2402,12 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); const char *atomicFunc = 0; switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: atomicFunc = "Atomics_store"; break; - case AtomicRMWInst::Add: atomicFunc = "Atomics_add"; break; - case AtomicRMWInst::Sub: atomicFunc = "Atomics_sub"; break; - case AtomicRMWInst::And: atomicFunc = "Atomics_and"; break; - case AtomicRMWInst::Or: atomicFunc = "Atomics_or"; break; - case AtomicRMWInst::Xor: atomicFunc = "Atomics_xor"; break; + case AtomicRMWInst::Xchg: atomicFunc = "store"; break; + case AtomicRMWInst::Add: atomicFunc = "add"; break; + case AtomicRMWInst::Sub: atomicFunc = "sub"; break; + case AtomicRMWInst::And: atomicFunc = "and"; break; + case AtomicRMWInst::Or: atomicFunc = "or"; break; + case AtomicRMWInst::Xor: atomicFunc = "xor"; break; case AtomicRMWInst::Nand: // TODO case AtomicRMWInst::Max: case AtomicRMWInst::Min: @@ -2412,9 +2419,9 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); - Code << Assign << (fround ? "Math_fround(" : "+") << "__" << atomicFunc << HeapName << "_emulated(" << getByteAddressAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; + Code << Assign << (fround ? "Math_fround(" : "+") << "_emscripten_atomic_" << atomicFunc << "_" << heapNameToAtomicTypeName(HeapName) << "(" << getByteAddressAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; } else { - Code << Assign << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; + Code << Assign << "Atomics_" << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; } } else { Code << getLoad(rmwi, P, I->getType(), 0) << ';'; From 7ec89a948b8e2a3483d910b2f9d0ac406572ae92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 4 May 2015 22:58:40 +0300 Subject: [PATCH 21/31] Add support for expanding 64-bit atomic add and sub instructions from GCC intrinsics to Emscripten library function calls. Mark 64-bit AtomicCmpXchg instructions unsupported at the moment. --- lib/Transforms/NaCl/ExpandI64.cpp | 46 ++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/NaCl/ExpandI64.cpp b/lib/Transforms/NaCl/ExpandI64.cpp index a6050800fb3..a5dd202eebb 100644 --- a/lib/Transforms/NaCl/ExpandI64.cpp +++ b/lib/Transforms/NaCl/ExpandI64.cpp @@ -104,6 +104,8 @@ namespace { Function *Add, *Sub, *Mul, *SDiv, *UDiv, *SRem, *URem, *LShr, *AShr, *Shl, *GetHigh, *SetHigh, *FtoILow, *FtoIHigh, *DtoILow, *DtoIHigh, *SItoF, *UItoF, *SItoD, *UItoD, *BItoD, *BDtoILow, *BDtoIHigh; + Function *AtomicAdd, *AtomicSub, *AtomicAnd, *AtomicOr, *AtomicXor; + void ensureFuncs(); unsigned getNumChunks(Type *T); @@ -112,7 +114,7 @@ namespace { ExpandI64() : ModulePass(ID) { initializeExpandI64Pass(*PassRegistry::getPassRegistry()); - Add = Sub = Mul = SDiv = UDiv = SRem = URem = LShr = AShr = Shl = GetHigh = SetHigh = NULL; + Add = Sub = Mul = SDiv = UDiv = SRem = URem = LShr = AShr = Shl = GetHigh = SetHigh = AtomicAdd = AtomicSub = AtomicAnd = AtomicOr = AtomicXor = NULL; } virtual bool runOnModule(Module &M); @@ -929,6 +931,42 @@ bool ExpandI64::splitInst(Instruction *I) { } break; } + case Instruction::AtomicRMW: { + const AtomicRMWInst *rmwi = cast(I); + ChunksVec Chunks32Bit = getChunks(I->getOperand(1)); + unsigned Num = getNumChunks(I->getType()); + assert(Num == 2 && "Only know how to handle 32-bit and 64-bit AtomicRMW instructions!"); + ensureFuncs(); + Value *Low = NULL, *High = NULL; + Function *F = NULL; + switch (rmwi->getOperation()) { + case AtomicRMWInst::Add: F = AtomicAdd; break; + case AtomicRMWInst::Sub: F = AtomicSub; break; + case AtomicRMWInst::And: F = AtomicAnd; break; + case AtomicRMWInst::Or: F = AtomicOr; break; + case AtomicRMWInst::Xor: F = AtomicXor; break; + case AtomicRMWInst::Xchg: + case AtomicRMWInst::Nand: + case AtomicRMWInst::Max: + case AtomicRMWInst::Min: + case AtomicRMWInst::UMax: + case AtomicRMWInst::UMin: + default: llvm_unreachable("Bad atomic operation"); + } + SmallVector Args; + Args.push_back(new BitCastInst(I->getOperand(0), Type::getInt8PtrTy(TheModule->getContext()), "", I)); + Args.push_back(Chunks32Bit[0]); + Args.push_back(Chunks32Bit[1]); + Low = CopyDebug(CallInst::Create(F, Args, "", I), I); + High = CopyDebug(CallInst::Create(GetHigh, "", I), I); + Chunks.push_back(Low); + Chunks.push_back(High); + break; + } + case Instruction::AtomicCmpXchg: { + assert(0 && "64-bit compare-and-exchange (__sync_bool_compare_and_swap & __sync_val_compare_and_swap) are not supported! Please directly call emscripten_atomic_cas_u64() instead in order to emulate!"); + break; + } default: { I->dump(); assert(0 && "some i64 thing we can't legalize yet"); @@ -979,6 +1017,12 @@ void ExpandI64::ensureFuncs() { Type *i32 = Type::getInt32Ty(TheModule->getContext()); + AtomicAdd = TheModule->getFunction("_emscripten_atomic_fetch_and_add_u64"); + AtomicSub = TheModule->getFunction("_emscripten_atomic_fetch_and_sub_u64"); + AtomicAnd = TheModule->getFunction("_emscripten_atomic_fetch_and_and_u64"); + AtomicOr = TheModule->getFunction("_emscripten_atomic_fetch_and_or_u64"); + AtomicXor = TheModule->getFunction("_emscripten_atomic_fetch_and_xor_u64"); + SmallVector FourArgTypes; FourArgTypes.push_back(i32); FourArgTypes.push_back(i32); From c4ad168489779f8673acf9e1ec8b4867d5184d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 6 May 2015 01:05:06 +0300 Subject: [PATCH 22/31] Fix asm.js validation of 64-bit atomic stores. --- lib/Target/JSBackend/CallHandlers.h | 2 +- lib/Target/JSBackend/JSBackend.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 5956f1343ee..2f0dc1c8cb9 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -616,7 +616,7 @@ DEF_CALL_HANDLER(emscripten_atomic_store_f32, { DEF_CALL_HANDLER(emscripten_atomic_store_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "_emscripten_atomic_store_f64(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "+_emscripten_atomic_store_f64(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; // return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 63945f3c902..e9b60f4e656 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -1030,6 +1030,10 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. text = std::string("_emscripten_atomic_store_") + heapNameToAtomicTypeName(HeapName) + "(" + getByteAddressAsStr(P) + ',' + VS + ')'; + if (PreciseF32 && !strcmp(HeapName, "HEAPF32")) + text = "Math_fround(" + text + ")"; + else + text = "+" + text; } else { text = std::string("Atomics_store(") + HeapName + ',' + Index + ',' + VS + ')'; } From 91a60443dd3cae833b12e4ac530f65074ba52d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 14 May 2015 02:36:59 +0300 Subject: [PATCH 23/31] Add support for asm.js validating emscripten_atomic_exchange intrinsics. --- lib/Target/JSBackend/CallHandlers.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 2f0dc1c8cb9..b9eba2ec48a 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -558,6 +558,22 @@ std::string getAddressAsString(const Value *Ptr, int shift) { } } +DEF_CALL_HANDLER(emscripten_atomic_exchange_u8, { + return getAssign(CI) + "Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_exchange_u16, { + return getAssign(CI) + "Atomics_exchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_exchange_u32, { + return getAssign(CI) + "Atomics_exchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_exchange_f32, { + return getAssign(CI) + "Atomics_exchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) +DEF_CALL_HANDLER(emscripten_atomic_exchange_f64, { + return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; +}) + DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { return getAssign(CI) + "Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) @@ -865,6 +881,12 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_asm_const_int); SETUP_CALL_HANDLER(emscripten_asm_const_double); + SETUP_CALL_HANDLER(emscripten_atomic_exchange_u8); + SETUP_CALL_HANDLER(emscripten_atomic_exchange_u16); + SETUP_CALL_HANDLER(emscripten_atomic_exchange_u32); + SETUP_CALL_HANDLER(emscripten_atomic_exchange_f32); + SETUP_CALL_HANDLER(emscripten_atomic_exchange_f64); + SETUP_CALL_HANDLER(emscripten_atomic_cas_u8); SETUP_CALL_HANDLER(emscripten_atomic_cas_u16); SETUP_CALL_HANDLER(emscripten_atomic_cas_u32); From 25ecc3a1ae60b127ffdf2ed514da3e7d82941759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 14 May 2015 02:37:23 +0300 Subject: [PATCH 24/31] Fix emscripten atomic exchange to call correct atomic intrinsic. --- lib/Target/JSBackend/JSBackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index e9b60f4e656..8159b2db65d 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2406,7 +2406,7 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { std::string Index = getHeapNameAndIndex(P, &HeapName); const char *atomicFunc = 0; switch (rmwi->getOperation()) { - case AtomicRMWInst::Xchg: atomicFunc = "store"; break; + case AtomicRMWInst::Xchg: atomicFunc = "exchange"; break; case AtomicRMWInst::Add: atomicFunc = "add"; break; case AtomicRMWInst::Sub: atomicFunc = "sub"; break; case AtomicRMWInst::And: atomicFunc = "and"; break; From ff25c5e604d2de07e9a5c89146fcfb6ae06436e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 14 May 2015 13:31:09 +0300 Subject: [PATCH 25/31] Fix the number of params to emscripten_atomic_exchange intrinsic. --- lib/Target/JSBackend/CallHandlers.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index b9eba2ec48a..f3a6dece067 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -559,19 +559,19 @@ std::string getAddressAsString(const Value *Ptr, int shift) { } DEF_CALL_HANDLER(emscripten_atomic_exchange_u8, { - return getAssign(CI) + "Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_u16, { - return getAssign(CI) + "Atomics_exchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_u32, { - return getAssign(CI) + "Atomics_exchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_f32, { - return getAssign(CI) + "Atomics_exchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_f64, { - return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { From 91f70055017fcf4852a7c88e17f16ca14c66bf2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Fri, 15 May 2015 02:25:16 +0300 Subject: [PATCH 26/31] HACK: Atomics.exchange() is not yet implemented, so as a temp workaround, do it as u32 version with a CAS loop. TODO: revert this commit once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 lands. --- lib/Target/JSBackend/CallHandlers.h | 5 +++++ lib/Target/JSBackend/JSBackend.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index f3a6dece067..51b4312b767 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -558,6 +558,8 @@ std::string getAddressAsString(const Value *Ptr, int shift) { } } +/* TODO: Uncomment once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 is implemented! + DEF_CALL_HANDLER(emscripten_atomic_exchange_u8, { return getAssign(CI) + "Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) @@ -573,6 +575,7 @@ DEF_CALL_HANDLER(emscripten_atomic_exchange_f32, { DEF_CALL_HANDLER(emscripten_atomic_exchange_f64, { return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) +*/ DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { return getAssign(CI) + "Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; @@ -881,11 +884,13 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_asm_const_int); SETUP_CALL_HANDLER(emscripten_asm_const_double); +/* TODO: Uncomment once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 is implemented! SETUP_CALL_HANDLER(emscripten_atomic_exchange_u8); SETUP_CALL_HANDLER(emscripten_atomic_exchange_u16); SETUP_CALL_HANDLER(emscripten_atomic_exchange_u32); SETUP_CALL_HANDLER(emscripten_atomic_exchange_f32); SETUP_CALL_HANDLER(emscripten_atomic_exchange_f64); +*/ SETUP_CALL_HANDLER(emscripten_atomic_cas_u8); SETUP_CALL_HANDLER(emscripten_atomic_cas_u16); diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 8159b2db65d..7387371c240 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2424,6 +2424,11 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { // implemented, we could remove the emulation, but until then we must emulate manually. bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); Code << Assign << (fround ? "Math_fround(" : "+") << "_emscripten_atomic_" << atomicFunc << "_" << heapNameToAtomicTypeName(HeapName) << "(" << getByteAddressAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; + + // TODO: Remove the following two lines once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 is implemented! + } else if (rmwi->getOperation() == AtomicRMWInst::Xchg && !strcmp(HeapName, "HEAP32")) { + Code << Assign << "_emscripten_atomic_exchange_u32(" << getByteAddressAsStr(P) << ", " << VS << ")|0"; break; + } else { Code << Assign << "Atomics_" << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; } From ecc125257940df32a7aa14f2458d6a6df4058f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 1 Jun 2015 13:37:37 +0300 Subject: [PATCH 27/31] Add missing relocateGlobal() in getAddressAsString(). Remove unused and unsupported f32 and f64 atomic cas ops. --- lib/Target/JSBackend/CallHandlers.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index 51b4312b767..a2c3ab59c56 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -552,7 +552,7 @@ DEF_CALL_HANDLER(emscripten_asm_const_double, { std::string getAddressAsString(const Value *Ptr, int shift) { Type *t = cast(Ptr->getType())->getElementType(); if (const GlobalVariable *GV = dyn_cast(Ptr)) { - return utostr(getGlobalAddress(GV->getName().str()) >> shift); + return relocateGlobal(utostr(getGlobalAddress(GV->getName().str()) >> shift)); } else { return getValueAsStr(Ptr) + ">>" + utostr(shift); } @@ -586,14 +586,6 @@ DEF_CALL_HANDLER(emscripten_atomic_cas_u16, { DEF_CALL_HANDLER(emscripten_atomic_cas_u32, { return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) -DEF_CALL_HANDLER(emscripten_atomic_cas_f32, { - errs() << "emcc: warning: float32 compare-and-swap is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_compareExchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; -}) -DEF_CALL_HANDLER(emscripten_atomic_cas_f64, { - errs() << "emcc: warning: float64 compare-and-swap is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_compareExchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; -}) DEF_CALL_HANDLER(emscripten_atomic_load_u8, { return getAssign(CI) + "Atomics_load(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ")"; @@ -895,8 +887,6 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(emscripten_atomic_cas_u8); SETUP_CALL_HANDLER(emscripten_atomic_cas_u16); SETUP_CALL_HANDLER(emscripten_atomic_cas_u32); - SETUP_CALL_HANDLER(emscripten_atomic_cas_f32); - SETUP_CALL_HANDLER(emscripten_atomic_cas_f64); SETUP_CALL_HANDLER(emscripten_atomic_load_u8); SETUP_CALL_HANDLER(emscripten_atomic_load_u16); From 3c942aed22fbcd601aee29b3113fbca9a9342d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 1 Jun 2015 13:56:56 +0300 Subject: [PATCH 28/31] Remove code duplication between the different methods for accessing memory addresses. --- lib/Target/JSBackend/JSBackend.cpp | 138 ++++++++++++++++------------- 1 file changed, 75 insertions(+), 63 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 7387371c240..2f9e8d1dd4a 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -500,10 +500,28 @@ namespace { } std::string getPtrLoad(const Value* Ptr); + + /// Given a pointer to memory, returns the HEAP object and index to that object that is used to access that memory. + /// @param Ptr [in] The heap object. + /// @param HeapName [out] Receives the name of the HEAP object used to perform the memory acess. + /// @return The index to the heap HeapName for the memory access. std::string getHeapNameAndIndex(const Value *Ptr, const char **HeapName); + + /// Like getHeapNameAndIndex(), but for global variables only. + std::string getHeapNameAndIndexToGlobal(const GlobalVariable *GV, const char **HeapName); + + /// Like getHeapNameAndIndex(), but for pointers represented in string expression form. + static std::string getHeapNameAndIndexToPtr(const std::string& Ptr, unsigned Bytes, bool Integer, const char **HeapName); + + /// Converts the given pointer to a string expression form. std::string getByteAddressAsStr(const Value *Ptr); - std::string getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer=true); + + /// Returns a string expression for accessing the given memory address. std::string getPtrUse(const Value* Ptr); + + /// Like getPtrUse(), but for pointers represented in string expression form. + static std::string getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer=true); + 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); @@ -847,39 +865,63 @@ std::string JSWriter::getIMul(const Value *V1, const Value *V2) { return "Math_imul(" + getValueAsStr(V1) + ", " + getValueAsStr(V2) + ")|0"; // unknown or too large, emit imul } -/// Given a pointer to memory, returns the HEAP object and index to that object that is used to access that memory. -/// @param Ptr [in] The heap object. -/// @param HeapName [out] Receives the name of the HEAP object used to perform the memory acess. -/// @return The index to the heap HeapName for the memory access. +static inline const char *getHeapName(int Bytes, int Integer) +{ + switch (Bytes) { + default: llvm_unreachable("Unsupported type"); + case 8: return "HEAPF64"; + case 4: return Integer ? "HEAP32" : "HEAPF32"; + case 2: return "HEAP16"; + case 1: return "HEAP8"; + } +} + +static inline int getHeapShift(int Bytes) +{ + switch (Bytes) { + default: llvm_unreachable("Unsupported type"); + case 8: return 3; + case 4: return 2; + case 2: return 1; + case 1: return 0; + } +} + +static inline const char *getHeapShiftStr(int Bytes) +{ + switch (Bytes) { + default: llvm_unreachable("Unsupported type"); + case 8: return ">>3"; + case 4: return ">>2"; + case 2: return ">>1"; + case 1: return ">>0"; + } +} + +std::string JSWriter::getHeapNameAndIndexToGlobal(const GlobalVariable *GV, const char **HeapName) +{ + Type *t = cast(GV->getType())->getElementType(); + unsigned Bytes = DL->getTypeAllocSize(t); + unsigned Addr = getGlobalAddress(GV->getName().str()); + *HeapName = getHeapName(Bytes, t->isIntegerTy() || t->isPointerTy()); + return relocateGlobal(utostr(Addr >> getHeapShift(Bytes))); +} + +std::string JSWriter::getHeapNameAndIndexToPtr(const std::string& Ptr, unsigned Bytes, bool Integer, const char **HeapName) +{ + *HeapName = getHeapName(Bytes, Integer); + return Ptr + getHeapShiftStr(Bytes); +} + std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapName) { Type *t = cast(Ptr->getType())->getElementType(); unsigned Bytes = DL->getTypeAllocSize(t); if (const GlobalVariable *GV = dyn_cast(Ptr)) { - unsigned Addr = getGlobalAddress(GV->getName().str()); - switch (Bytes) { - default: llvm_unreachable("Unsupported type"); - case 8: *HeapName = "HEAPF64"; return utostr(Addr >> 3); - case 4: - if (t->isIntegerTy() || t->isPointerTy()) *HeapName = "HEAP32"; - else *HeapName = "HEAPF32"; - return utostr(Addr >> 2); - case 2: *HeapName = "HEAP16"; return utostr(Addr >> 1); break; - case 1: *HeapName = "HEAP8"; return utostr(Addr); break; - } + return getHeapNameAndIndexToGlobal(GV, HeapName); } else { - std::string Index = getValueAsStr(Ptr); - switch (Bytes) { - default: llvm_unreachable("Unsupported type"); - case 8: *HeapName = "HEAPF64"; return Index + ">>3"; - case 4: - if (t->isIntegerTy() || t->isPointerTy()) *HeapName = "HEAP32"; - else *HeapName = "HEAPF32"; - return Index + ">>2"; - case 2: *HeapName = "HEAP16"; return Index + ">>1"; - case 1: *HeapName = "HEAP8"; return Index; - } + return getHeapNameAndIndexToPtr(getValueAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy(), HeapName); } } @@ -1158,45 +1200,15 @@ std::string JSWriter::getPtrLoad(const Value* Ptr) { } std::string JSWriter::getHeapAccess(const std::string& Name, unsigned Bytes, bool Integer) { - switch (Bytes) { - default: llvm_unreachable("Unsupported type"); - case 8: return "HEAPF64[" + Name + ">>3]"; - case 4: { - if (Integer) { - return "HEAP32[" + Name + ">>2]"; - } else { - return "HEAPF32[" + Name + ">>2]"; - } - } - case 2: return "HEAP16[" + Name + ">>1]"; - case 1: return "HEAP8[" + Name + ">>0]"; - } + const char *HeapName = 0; + std::string Index = getHeapNameAndIndexToPtr(Name, Bytes, Integer, &HeapName); + return std::string(HeapName) + '[' + Index + ']'; } std::string JSWriter::getPtrUse(const Value* Ptr) { - Type *t = cast(Ptr->getType())->getElementType(); - unsigned Bytes = DL->getTypeAllocSize(t); - if (const GlobalVariable *GV = dyn_cast(Ptr)) { - unsigned Addr = getGlobalAddress(GV->getName().str()); - if (Relocatable) { - return getHeapAccess(relocateGlobal(utostr(Addr)), Bytes, t->isIntegerTy() || t->isPointerTy()); - } - switch (Bytes) { - default: llvm_unreachable("Unsupported type"); - case 8: return "HEAPF64[" + utostr(Addr >> 3) + "]"; - case 4: { - if (t->isIntegerTy() || t->isPointerTy()) { - return "HEAP32[" + utostr(Addr >> 2) + "]"; - } else { - assert(t->isFloatingPointTy()); - return "HEAPF32[" + utostr(Addr >> 2) + "]"; - } - } - case 2: return "HEAP16[" + utostr(Addr >> 1) + "]"; - case 1: return "HEAP8[" + utostr(Addr) + "]"; - } - } - return getHeapAccess(getValueAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy()); + const char *HeapName = 0; + std::string Index = getHeapNameAndIndex(Ptr, &HeapName); + return std::string(HeapName) + '[' + Index + ']'; } std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { From 91e09dc875b73ebc494acb255f83f979f90d079f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 1 Jun 2015 14:23:12 +0300 Subject: [PATCH 29/31] Remove getByteAddressAsStr() as a duplicate of getValueAsStr(). --- lib/Target/JSBackend/JSBackend.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 2f9e8d1dd4a..1844bb3a415 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -513,9 +513,6 @@ namespace { /// Like getHeapNameAndIndex(), but for pointers represented in string expression form. static std::string getHeapNameAndIndexToPtr(const std::string& Ptr, unsigned Bytes, bool Integer, const char **HeapName); - /// Converts the given pointer to a string expression form. - std::string getByteAddressAsStr(const Value *Ptr); - /// Returns a string expression for accessing the given memory address. std::string getPtrUse(const Value* Ptr); @@ -925,16 +922,6 @@ std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapNam } } -std::string JSWriter::getByteAddressAsStr(const Value *Ptr) -{ - Type *t = cast(Ptr->getType())->getElementType(); - if (const GlobalVariable *GV = dyn_cast(Ptr)) { - return utostr(getGlobalAddress(GV->getName().str())); - } else { - return getValueAsStr(Ptr); - } -} - static const char *heapNameToAtomicTypeName(const char *HeapName) { if (!strcmp(HeapName, "HEAPF32")) return "f32"; @@ -954,7 +941,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - text = Assign + (fround ? "Math_fround(" : "+") + "_emscripten_atomic_load_" + heapNameToAtomicTypeName(HeapName) + "(" + getByteAddressAsStr(P) + (fround ? "))" : ")"); + text = Assign + (fround ? "Math_fround(" : "+") + "_emscripten_atomic_load_" + heapNameToAtomicTypeName(HeapName) + "(" + getValueAsStr(P) + (fround ? "))" : ")"); } else { text = Assign + "Atomics_load(" + HeapName + ',' + Index + ')'; } @@ -1071,7 +1058,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co if (!strcmp(HeapName, "HEAPF32") || !strcmp(HeapName, "HEAPF64")) { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. - text = std::string("_emscripten_atomic_store_") + heapNameToAtomicTypeName(HeapName) + "(" + getByteAddressAsStr(P) + ',' + VS + ')'; + text = std::string("_emscripten_atomic_store_") + heapNameToAtomicTypeName(HeapName) + "(" + getValueAsStr(P) + ',' + VS + ')'; if (PreciseF32 && !strcmp(HeapName, "HEAPF32")) text = "Math_fround(" + text + ")"; else @@ -2435,11 +2422,11 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 and https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 are // implemented, we could remove the emulation, but until then we must emulate manually. bool fround = PreciseF32 && !strcmp(HeapName, "HEAPF32"); - Code << Assign << (fround ? "Math_fround(" : "+") << "_emscripten_atomic_" << atomicFunc << "_" << heapNameToAtomicTypeName(HeapName) << "(" << getByteAddressAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; + Code << Assign << (fround ? "Math_fround(" : "+") << "_emscripten_atomic_" << atomicFunc << "_" << heapNameToAtomicTypeName(HeapName) << "(" << getValueAsStr(P) << ", " << VS << (fround ? "))" : ")"); break; // TODO: Remove the following two lines once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 is implemented! } else if (rmwi->getOperation() == AtomicRMWInst::Xchg && !strcmp(HeapName, "HEAP32")) { - Code << Assign << "_emscripten_atomic_exchange_u32(" << getByteAddressAsStr(P) << ", " << VS << ")|0"; break; + Code << Assign << "_emscripten_atomic_exchange_u32(" << getValueAsStr(P) << ", " << VS << ")|0"; break; } else { Code << Assign << "Atomics_" << atomicFunc << "(" << HeapName << ", " << Index << ", " << VS << ")"; break; From c439cf259d109871a191d311e69fbff896213200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 1 Jun 2015 14:50:57 +0300 Subject: [PATCH 30/31] Use PNaCl intrinsics based approach for handling atomic cmpxchg. --- lib/Target/JSBackend/CallHandlers.h | 21 +++++++++++++-------- lib/Target/JSBackend/JSBackend.cpp | 24 ------------------------ lib/Transforms/NaCl/RewriteAtomics.cpp | 1 - 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index a2c3ab59c56..be643ed58b7 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -314,16 +314,21 @@ DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, { return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(CI->getOperand(1)); }) -#define CMPXCHG_HANDLER(name) \ +#define CMPXCHG_HANDLER(name, HeapName) \ DEF_CALL_HANDLER(name, { \ const Value *P = CI->getOperand(0); \ - return getLoad(CI, P, CI->getType(), 0) + ';' + \ - "if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsCastParenStr(CI->getOperand(1)) + ") " + \ - getStore(CI, P, CI->getType(), getValueAsStr(CI->getOperand(2)), 0); \ -}) -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i8); -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i16); -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i32); + if (EnablePthreads) { \ + return getAssign(CI) + "Atomics_compareExchange(" HeapName ", " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; \ + } else { \ + return getLoad(CI, P, CI->getType(), 0) + ';' + \ + "if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsCastParenStr(CI->getOperand(1)) + ") " + \ + getStore(CI, P, CI->getType(), getValueAsStr(CI->getOperand(2)), 0); \ + } \ +}) + +CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i8, "HEAP8"); +CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i16, "HEAP16"); +CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i32, "HEAP32"); #define UNROLL_LOOP_MAX 8 #define WRITE_LOOP_MAX 128 diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 1844bb3a415..925eb1ea3db 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -2367,30 +2367,6 @@ void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { getValueAsStr(I->getOperand(2)); break; } - case Instruction::ExtractValue: { - const ExtractValueInst *evi = cast(I); - std::string Assign = getAssign(evi); - Code << Assign << getValueAsStr(I->getOperand(0)) << "_" << evi->idx_begin()[0]; - break; - } - case Instruction::AtomicCmpXchg: { - const AtomicCmpXchgInst *cxi = cast(I); - const Value *P = I->getOperand(0); - const char *HeapName; - std::string Index = getHeapNameAndIndex(P, &HeapName); - std::string Assign = getJSName(I); - UsedVars[Assign + "_0"] = I->getOperand(1)->getType(); - UsedVars[Assign + "_1"] = Type::getInt1Ty(P->getContext()); - if (EnablePthreads) { - Code << Assign << "_0 = Atomics_compareExchange(" << HeapName << ", " << Index << ", " << getValueAsStr(I->getOperand(1)) << ", " << getValueAsStr(I->getOperand(2)) << ");\n"; - Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0)"; - } else { - Code << Assign << "_0 = " << HeapName << "[" << Index << "];\n"; - Code << Assign << "_1 = (" << Assign << "_0|0) == (" << getValueAsStr(I->getOperand(1)) << "|0); "; - Code << "if (" << Assign << "_1) " << getStore(cxi, P, I->getType(), getValueAsStr(I->getOperand(2)), 0); - } - break; - } case Instruction::AtomicRMW: { const AtomicRMWInst *rmwi = cast(I); const Value *P = rmwi->getOperand(0); diff --git a/lib/Transforms/NaCl/RewriteAtomics.cpp b/lib/Transforms/NaCl/RewriteAtomics.cpp index 6722f46a47f..a1b99e31b68 100644 --- a/lib/Transforms/NaCl/RewriteAtomics.cpp +++ b/lib/Transforms/NaCl/RewriteAtomics.cpp @@ -379,7 +379,6 @@ void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { /// %success = icmp eq %old, %val /// Note: weak is currently dropped if present, the cmpxchg is always strong. void AtomicVisitor::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { - return; // XXX EMSCRIPTEN PointerHelper PH(*this, I); const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = findAtomicIntrinsic(I, Intrinsic::nacl_atomic_cmpxchg, PH.PET); From 63bf6b63bbb0b5eccda29de937610cfffc526a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 1 Jun 2015 23:06:49 +0300 Subject: [PATCH 31/31] Rename getAddressAsString() to getShiftedPtr() and reuse its implementation from the existing functions. --- lib/Target/JSBackend/CallHandlers.h | 75 +++++++++++++---------------- lib/Target/JSBackend/JSBackend.cpp | 20 +++++++- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index be643ed58b7..e6ad8f5f8ec 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -318,7 +318,7 @@ DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, { DEF_CALL_HANDLER(name, { \ const Value *P = CI->getOperand(0); \ if (EnablePthreads) { \ - return getAssign(CI) + "Atomics_compareExchange(" HeapName ", " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; \ + return getAssign(CI) + "Atomics_compareExchange(" HeapName ", " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; \ } else { \ return getLoad(CI, P, CI->getType(), 0) + ';' + \ "if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsCastParenStr(CI->getOperand(1)) + ") " + \ @@ -554,31 +554,22 @@ DEF_CALL_HANDLER(emscripten_asm_const_double, { return getAssign(CI) + getCast(handleAsmConst(CI), Type::getDoubleTy(CI->getContext())); }) -std::string getAddressAsString(const Value *Ptr, int shift) { - Type *t = cast(Ptr->getType())->getElementType(); - if (const GlobalVariable *GV = dyn_cast(Ptr)) { - return relocateGlobal(utostr(getGlobalAddress(GV->getName().str()) >> shift)); - } else { - return getValueAsStr(Ptr) + ">>" + utostr(shift); - } -} - /* TODO: Uncomment once https://bugzilla.mozilla.org/show_bug.cgi?id=1141986 is implemented! DEF_CALL_HANDLER(emscripten_atomic_exchange_u8, { return getAssign(CI) + "Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_u16, { - return getAssign(CI) + "Atomics_exchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_u32, { - return getAssign(CI) + "Atomics_exchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_f32, { - return getAssign(CI) + "Atomics_exchange(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_exchange_f64, { - return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_exchange(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) */ @@ -586,120 +577,120 @@ DEF_CALL_HANDLER(emscripten_atomic_cas_u8, { return getAssign(CI) + "Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_cas_u16, { - return getAssign(CI) + "Atomics_compareExchange(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_compareExchange(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_cas_u32, { - return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; + return getAssign(CI) + "Atomics_compareExchange(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ", " + getValueAsStr(CI->getOperand(2)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_u8, { return getAssign(CI) + "Atomics_load(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_u16, { - return getAssign(CI) + "Atomics_load(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ")"; + return getAssign(CI) + "Atomics_load(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_u32, { - return getAssign(CI) + "Atomics_load(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; + return getAssign(CI) + "Atomics_load(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_f32, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + (PreciseF32 ? "Math_fround(" : "+") + "__Atomics_load_f32_emulated(" + getAddressAsString(CI->getOperand(0), 2) + (PreciseF32 ? "))" : ")"); -// return getAssign(CI) + "Atomics_load(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ")"; + return getAssign(CI) + (PreciseF32 ? "Math_fround(" : "+") + "__Atomics_load_f32_emulated(" + getShiftedPtr(CI->getOperand(0), 4) + (PreciseF32 ? "))" : ")"); +// return getAssign(CI) + "Atomics_load(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_load_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "+_emscripten_atomic_load_f64(" + getAddressAsString(CI->getOperand(0), 3) + ")"; -// return getAssign(CI) + "Atomics_load(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ")"; + return getAssign(CI) + "+_emscripten_atomic_load_f64(" + getShiftedPtr(CI->getOperand(0), 8) + ")"; +// return getAssign(CI) + "Atomics_load(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_u8, { return getAssign(CI) + "Atomics_store(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_u16, { - return getAssign(CI) + "Atomics_store(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_store(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_u32, { - return getAssign(CI) + "Atomics_store(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_store(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_f32, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "_emscripten_atomic_store_f32(" + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -// return getAssign(CI) + "Atomics_store(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "_emscripten_atomic_store_f32(" + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +// return getAssign(CI) + "Atomics_store(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_store_f64, { // TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then, // we must emulate manually. - return getAssign(CI) + "+_emscripten_atomic_store_f64(" + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; -// return getAssign(CI) + "Atomics_store(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "+_emscripten_atomic_store_f64(" + getShiftedPtr(CI->getOperand(0), 8) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; +// return getAssign(CI) + "Atomics_store(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_u8, { return getAssign(CI) + "Atomics_add(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_u16, { - return getAssign(CI) + "Atomics_add(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_add(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_u32, { - return getAssign(CI) + "Atomics_add(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_add(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_f32, { errs() << "emcc: warning: float32 atomic add is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_add(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_add(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_add_f64, { errs() << "emcc: warning: float64 atomic add is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_add(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_add(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_u8, { return getAssign(CI) + "Atomics_sub(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_u16, { - return getAssign(CI) + "Atomics_sub(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_sub(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_u32, { - return getAssign(CI) + "Atomics_sub(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_sub(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_f32, { errs() << "emcc: warning: float32 atomic sub is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_sub(HEAPF32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_sub(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_sub_f64, { errs() << "emcc: warning: float64 atomic sub is not supported!" << CI->getParent()->getParent()->getName() << ":" << *CI << "\n"; - return getAssign(CI) + "Atomics_sub(HEAPF64, " + getAddressAsString(CI->getOperand(0), 3) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_sub(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_and_u8, { return getAssign(CI) + "Atomics_and(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_and_u16, { - return getAssign(CI) + "Atomics_and(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_and(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_and_u32, { - return getAssign(CI) + "Atomics_and(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_and(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_or_u8, { return getAssign(CI) + "Atomics_or(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_or_u16, { - return getAssign(CI) + "Atomics_or(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_or(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_or_u32, { - return getAssign(CI) + "Atomics_or(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_or(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_xor_u8, { return getAssign(CI) + "Atomics_xor(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_xor_u16, { - return getAssign(CI) + "Atomics_xor(HEAP16, " + getAddressAsString(CI->getOperand(0), 1) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_xor(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) DEF_CALL_HANDLER(emscripten_atomic_xor_u32, { - return getAssign(CI) + "Atomics_xor(HEAP32, " + getAddressAsString(CI->getOperand(0), 2) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; + return getAssign(CI) + "Atomics_xor(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ", " + getValueAsStr(CI->getOperand(1)) + ")"; }) #define DEF_BUILTIN_HANDLER(name, to) \ diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 925eb1ea3db..a364c6e2c37 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -507,12 +507,17 @@ namespace { /// @return The index to the heap HeapName for the memory access. std::string getHeapNameAndIndex(const Value *Ptr, const char **HeapName); + // Like getHeapNameAndIndex(), but uses the given memory operation size instead of the one from Ptr. + std::string getHeapNameAndIndex(const Value *Ptr, const char **HeapName, unsigned Bytes); + /// Like getHeapNameAndIndex(), but for global variables only. std::string getHeapNameAndIndexToGlobal(const GlobalVariable *GV, const char **HeapName); /// Like getHeapNameAndIndex(), but for pointers represented in string expression form. static std::string getHeapNameAndIndexToPtr(const std::string& Ptr, unsigned Bytes, bool Integer, const char **HeapName); + std::string getShiftedPtr(const Value *Ptr, unsigned Bytes); + /// Returns a string expression for accessing the given memory address. std::string getPtrUse(const Value* Ptr); @@ -910,10 +915,9 @@ std::string JSWriter::getHeapNameAndIndexToPtr(const std::string& Ptr, unsigned return Ptr + getHeapShiftStr(Bytes); } -std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapName) +std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapName, unsigned Bytes) { Type *t = cast(Ptr->getType())->getElementType(); - unsigned Bytes = DL->getTypeAllocSize(t); if (const GlobalVariable *GV = dyn_cast(Ptr)) { return getHeapNameAndIndexToGlobal(GV, HeapName); @@ -922,6 +926,13 @@ std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapNam } } +std::string JSWriter::getHeapNameAndIndex(const Value *Ptr, const char **HeapName) +{ + Type *t = cast(Ptr->getType())->getElementType(); + unsigned Bytes = DL->getTypeAllocSize(t); + return getHeapNameAndIndex(Ptr, HeapName, Bytes); +} + static const char *heapNameToAtomicTypeName(const char *HeapName) { if (!strcmp(HeapName, "HEAPF32")) return "f32"; @@ -1192,6 +1203,11 @@ std::string JSWriter::getHeapAccess(const std::string& Name, unsigned Bytes, boo return std::string(HeapName) + '[' + Index + ']'; } +std::string JSWriter::getShiftedPtr(const Value *Ptr, unsigned Bytes) { + const char *HeapName = 0; // unused + return getHeapNameAndIndex(Ptr, &HeapName, Bytes); +} + std::string JSWriter::getPtrUse(const Value* Ptr) { const char *HeapName = 0; std::string Index = getHeapNameAndIndex(Ptr, &HeapName);