From 386b52eee6aab2947342f33f564a993de0492939 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 14 Nov 2015 15:32:26 -0800 Subject: [PATCH 1/4] careful with iterators in relooper ordered set/map --- lib/Target/JSBackend/Relooper.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/Target/JSBackend/Relooper.h b/lib/Target/JSBackend/Relooper.h index 7a55215b018..8fc1a0c2eab 100644 --- a/lib/Target/JSBackend/Relooper.h +++ b/lib/Target/JSBackend/Relooper.h @@ -87,6 +87,16 @@ struct InsertOrderedSet } size_t count(const T& val) const { return Map.count(val); } + + InsertOrderedSet() {} + InsertOrderedSet(const InsertOrderedSet& other) { + for (auto i : other.List) { + insert(i); // inserting manually creates proper iterators + } + } + InsertOrderedSet& operator=(const InsertOrderedSet& other) { + abort(); // TODO, watch out for iterators + } }; // like std::map, except that begin() -> end() iterates in the @@ -127,6 +137,14 @@ struct InsertOrderedMap size_t size() const { return Map.size(); } size_t count(const Key& k) const { return Map.count(k); } + + InsertOrderedMap() {} + InsertOrderedMap(InsertOrderedMap& other) { + abort(); // TODO, watch out for iterators + } + InsertOrderedMap& operator=(const InsertOrderedMap& other) { + abort(); // TODO, watch out for iterators + } }; From de8e1042fb3f4d3be1e309a7013bf9208b39f5cf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 18 Nov 2015 14:58:07 -0800 Subject: [PATCH 2/4] emit the specific signatures of each asm const --- lib/Target/JSBackend/CallHandlers.h | 14 +++--- lib/Target/JSBackend/JSBackend.cpp | 66 ++++++++++++----------------- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index c0eb1100934..3105af7cee9 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -75,7 +75,7 @@ DEF_CALL_HANDLER(__default__, { // function pointer call ensureFunctionTable(FT); if (!Invoke) { - Sig = getFunctionSignature(FT, &Name); + Sig = getFunctionSignature(FT); if (!EmulatedFunctionPointers) { Name = std::string("FUNCTION_TABLE_") + Sig + "[" + Name + " & #FM_" + Sig + "#]"; NeedCasts = false; // function table call, so stays in asm module @@ -113,7 +113,7 @@ DEF_CALL_HANDLER(__default__, { } if (Invoke) { - Sig = getFunctionSignature(FT, &Name); + Sig = getFunctionSignature(FT); Name = "invoke_" + Sig; NeedCasts = true; } @@ -550,9 +550,13 @@ DEF_CALL_HANDLER(emscripten_float32x4_store2, { std::string handleAsmConst(const Instruction *CI) { unsigned Num = getNumArgOperands(CI); - unsigned Arity = Num - 1; // ignore the first argument, which is a pointer to the code - std::string func = "emscripten_asm_const_" + utostr(Arity); - std::string ret = "_" + func + "(" + utostr(getAsmConstId(CI->getOperand(0), Arity)); + std::string Sig; + Sig += getFunctionSignatureLetter(CI->getType()); + for (unsigned i = 1; i < Num; i++) { + Sig += getFunctionSignatureLetter(CI->getOperand(i)->getType()); + } + std::string func = "emscripten_asm_const_" + Sig; + std::string ret = "_" + func + "(" + utostr(getAsmConstId(CI->getOperand(0), Sig)); for (unsigned i = 1; i < Num; i++) { ret += ", " + getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC); } diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 316d0ecbd99..2b9d5eb3d26 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -174,6 +174,10 @@ namespace { typedef std::map BlockIndexMap; typedef std::map BlockAddressMap; typedef std::map LLVMToRelooperMap; + struct AsmConstInfo { + int Id; + std::set Sigs; + }; /// JSWriter - This class is the main chunk of code that converts an LLVM /// module to JavaScript. @@ -200,8 +204,7 @@ namespace { std::vector Exports; // additional exports StringMap Aliases; BlockAddressMap BlockAddresses; - NameIntMap AsmConsts; - IntIntSetMap AsmConstArities; + std::map AsmConsts; // code => { index, list of seen sigs } NameSet FuncRelocatableExterns; // which externals are accessed in this function; we load them once at the beginning (avoids a potential call in a heap access, and might be faster) std::string CantValidate; @@ -330,7 +333,7 @@ namespace { return 'i'; } } - std::string getFunctionSignature(const FunctionType *F, const std::string *Name=NULL) { + std::string getFunctionSignature(const FunctionType *F) { std::string Ret; Ret += getFunctionSignatureLetter(F->getReturnType()); for (FunctionType::param_iterator AI = F->param_begin(), @@ -348,7 +351,7 @@ namespace { unsigned getFunctionIndex(const Function *F) { const std::string &Name = getJSName(F); if (IndexedFunctions.find(Name) != IndexedFunctions.end()) return IndexedFunctions[Name]; - std::string Sig = getFunctionSignature(F->getFunctionType(), &Name); + std::string Sig = getFunctionSignature(F->getFunctionType()); FunctionTable& Table = ensureFunctionTable(F->getFunctionType()); if (NoAliasingFunctionPointers) { while (Table.size() < NextFunctionIndex) Table.push_back("0"); @@ -455,7 +458,7 @@ namespace { // Transform the string input into emscripten_asm_const_*(str, args1, arg2) // into an id. We emit a map of id => string contents, and emscripten // wraps it up so that calling that id calls that function. - unsigned getAsmConstId(const Value *V, int Arity) { + unsigned getAsmConstId(const Value *V, std::string Sig) { V = resolveFully(V); const Constant *CI = cast(V)->getInitializer(); std::string code; @@ -482,15 +485,18 @@ namespace { } } } - unsigned id; + unsigned Id; if (AsmConsts.count(code) > 0) { - id = AsmConsts[code]; + auto& Info = AsmConsts[code]; + Id = Info.Id; + Info.Sigs.insert(Sig); } else { - id = AsmConsts.size(); - AsmConsts[code] = id; + AsmConstInfo Info; + Info.Id = Id = AsmConsts.size(); + Info.Sigs.insert(Sig); + AsmConsts[code] = Info; } - AsmConstArities[id].insert(Arity); - return id; + return Id; } // Test whether the given value is known to be an absolute value or one we turn into an absolute value @@ -3301,44 +3307,24 @@ void JSWriter::printModuleBody() { Out << "\"asmConsts\": {"; first = true; - for (NameIntMap::const_iterator I = AsmConsts.begin(), E = AsmConsts.end(); I != E; ++I) { + for (auto& I : AsmConsts) { if (first) { first = false; } else { Out << ", "; } - Out << "\"" << utostr(I->second) << "\": \"" << I->first.c_str() << "\""; - } - Out << "},"; - - // Output a structure like: - // "asmConstArities": { - // "": [, ], - // "": [] - // } - // Each ASM_CONST_ID represents a single EM_ASM_* block in the code and each - // ARITY represents the number of arguments defined in the block in compiled - // output (which may vary, if the EM_ASM_* block is used inside a template). - Out << "\"asmConstArities\": {"; - first = true; - for (IntIntSetMap::const_iterator I = AsmConstArities.begin(), E = AsmConstArities.end(); - I != E; ++I) { - if (!first) { - Out << ", "; - } - Out << "\"" << utostr(I->first) << "\": ["; - first = true; - for (IntSet::const_iterator J = I->second.begin(), F = I->second.end(); - J != F; ++J) { - if (first) { - first = false; + Out << "\"" << utostr(I.second.Id) << "\": [\"" << I.first.c_str() << "\", ["; + auto& Sigs = I.second.Sigs; + bool innerFirst = true; + for (auto& Sig : Sigs) { + if (innerFirst) { + innerFirst = false; } else { Out << ", "; } - Out << utostr(*J); + Out << "\"" << Sig << "\""; } - first = false; - Out << "]"; + Out << "]]"; } Out << "}"; From e2c242c71d23aca01fcc8f73ee3464a718c59cb2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 24 Nov 2015 14:01:31 -0800 Subject: [PATCH 3/4] emit instruction and debug info for nan canonicalization warning --- lib/Target/JSBackend/JSBackend.cpp | 37 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index 2b9d5eb3d26..e443b76c5da 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -220,6 +220,7 @@ namespace { int GlobalBasePadding; int MaxGlobalAlign; int StaticBump; + const Instruction* CurrInstruction; #include "CallHandlers.h" @@ -229,7 +230,8 @@ namespace { : ModulePass(ID), Out(o), UniqueNum(0), NextFunctionIndex(0), CantValidate(""), UsesSIMDInt8x16(false), UsesSIMDInt16x8(false), UsesSIMDInt32x4(false), UsesSIMDFloat32x4(false), UsesSIMDFloat64x2(false), InvokeState(0), - OptLevel(OptLevel), StackBumped(false), GlobalBasePadding(0), MaxGlobalAlign(0) {} + OptLevel(OptLevel), StackBumped(false), GlobalBasePadding(0), MaxGlobalAlign(0), + CurrInstruction(nullptr) {} const char *getPassName() const override { return "JavaScript backend"; } @@ -545,6 +547,19 @@ namespace { return S; } + static void emitDebugInfo(raw_ostream& Code, const Instruction *I) { + auto &Loc = I->getDebugLoc(); + if (Loc) { + unsigned Line = Loc.getLine(); + auto *Scope = cast_or_null(Loc.getScope()); + if (Scope) { + StringRef File = Scope->getFilename(); + if (Line > 0) + Code << " //@line " << utostr(Line) << " \"" << (File.size() > 0 ? File.str() : "?") << "\""; + } + } + } + std::string ftostr(const ConstantFP *CFP, AsmCast sign) { const APFloat &flt = CFP->getValueAPF(); @@ -557,6 +572,11 @@ namespace { // this a build error in order to not break people's existing code, so issue a warning instead. if (WarnOnNoncanonicalNans) { errs() << "emcc: warning: cannot represent a NaN literal '" << CFP << "' with custom bit pattern in NaN-canonicalizing JS engines (e.g. Firefox and Safari) without erasing bits!\n"; + if (CurrInstruction) { + errs() << " in " << *CurrInstruction << " in " << CurrInstruction->getParent()->getParent()->getName() << "() "; + emitDebugInfo(errs(), CurrInstruction); + errs() << '\n'; + } } } return ensureCast("nan", CFP->getType(), sign); @@ -752,19 +772,6 @@ static inline std::string ensureFloat(const std::string &value, bool wrap) { return value; } -static void emitDebugInfo(raw_ostream& Code, const Instruction *I) { - auto &Loc = I->getDebugLoc(); - if (Loc) { - unsigned Line = Loc.getLine(); - auto *Scope = cast_or_null(Loc.getScope()); - if (Scope) { - StringRef File = Scope->getFilename(); - if (Line > 0) - Code << " //@line " << utostr(Line) << " \"" << (File.size() > 0 ? File.str() : "?") << "\""; - } - } -} - void JSWriter::error(const std::string& msg) { report_fatal_error(msg); } @@ -2688,9 +2695,11 @@ void JSWriter::addBlock(const BasicBlock *BB, Relooper& R, LLVMToRelooperMap& LL for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { if (I->stripPointerCasts() == I) { + CurrInstruction = I; generateExpression(I, CodeStream); } } + CurrInstruction = nullptr; CodeStream.flush(); const Value* Condition = considerConditionVar(BB->getTerminator()); Block *Curr = new Block(Code.c_str(), Condition ? getValueAsCastStr(Condition).c_str() : NULL); From fbda12e311d1a1195855ffacc2f9f81d27ffedb1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 25 Nov 2015 12:44:05 -0800 Subject: [PATCH 4/4] 1.35.10 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index 792aebb8a21..b5af602a932 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -"1.35.9" +"1.35.10"