diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-12-27 19:57:19 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-12-27 19:57:19 -0800 |
commit | 81afe65c6fa734101c96dc99ec10b1aed3f43602 (patch) | |
tree | 7af4be660811c17f77cefe25c9be2b7df36df980 /lib/Target/CppBackend/CPPBackend.cpp | |
parent | 9a21bed266588de64040a9ec3b3dafa912eb4c6a (diff) |
CPPBackend => JSBackend
Diffstat (limited to 'lib/Target/CppBackend/CPPBackend.cpp')
-rw-r--r-- | lib/Target/CppBackend/CPPBackend.cpp | 1738 |
1 files changed, 0 insertions, 1738 deletions
diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp deleted file mode 100644 index 1253d8a622..0000000000 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ /dev/null @@ -1,1738 +0,0 @@ -//===-- CPPBackend.cpp - Library for converting LLVM code to JS -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements compiling of LLVM IR, which is assumed to have been -// simplified using the PNaCl passes, i64 legalization, and other necessary -// transformations, into JavaScript in asm.js format, suitable for passing -// to emscripten for final processing. -// -//===----------------------------------------------------------------------===// - -#include "CPPTargetMachine.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Config/config.h" -#include "llvm/IR/CallingConv.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Pass.h" -#include "llvm/PassManager.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/DebugInfo.h" -#include <algorithm> -#include <cstdio> -#include <map> -#include <set> // TODO: unordered_set? -using namespace llvm; - -#include <OptPasses.h> -#include <Relooper.h> - -#define dump(x) fprintf(stderr, x "\n") -#define dumpv(x, ...) fprintf(stderr, x "\n", __VA_ARGS__) -#define dumpfail(x) { fprintf(stderr, x "\n"); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); } -#define dumpfailv(x, ...) { fprintf(stderr, x "\n", __VA_ARGS__); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); } -#define dumpIR(value) { \ - std::string temp; \ - raw_string_ostream stream(temp); \ - stream << *(value); \ - fprintf(stderr, "%s\n", temp.c_str()); \ -} -#undef assert -#define assert(x) { if (!(x)) dumpfail(#x); } - -extern "C" void LLVMInitializeCppBackendTarget() { - // Register the target. - RegisterTargetMachine<CPPTargetMachine> X(TheCppBackendTarget); -} - -namespace { - enum AsmCast { - ASM_SIGNED = 0, - ASM_UNSIGNED = 1, - ASM_NONSPECIFIC = 2 // nonspecific means to not differentiate ints. |0 for all, regardless of size and sign - }; - - typedef std::map<const Value*,std::string> ValueMap; - typedef std::set<std::string> NameSet; - typedef std::vector<unsigned char> HeapData; - typedef std::pair<unsigned, unsigned> Address; - typedef std::map<std::string, Type::TypeID> VarMap; - typedef std::map<std::string, Address> GlobalAddressMap; - typedef std::vector<std::string> FunctionTable; - typedef std::map<std::string, FunctionTable> FunctionTableMap; - typedef std::map<std::string, std::string> StringMap; - - /// JSWriter - This class is the main chunk of code that converts an LLVM - /// module to JavaScript. - class JSWriter : public ModulePass { - formatted_raw_ostream &Out; - const Module *TheModule; - unsigned UniqueNum; - ValueMap ValueNames; - NameSet UsedNames; - VarMap UsedVars; - HeapData GlobalData8; - HeapData GlobalData32; - HeapData GlobalData64; - GlobalAddressMap GlobalAddresses; - NameSet Externals; // vars - NameSet Declares; // funcs - StringMap Redirects; // library function redirects actually used, needed for wrapper funcs in tables - std::string PostSets; - std::map<std::string, unsigned> IndexedFunctions; // name -> index - FunctionTableMap FunctionTables; // sig => list of functions - std::vector<std::string> GlobalInitializers; - - #include "CallHandlers.h" - - public: - static char ID; - explicit JSWriter(formatted_raw_ostream &o) : - ModulePass(ID), Out(o), UniqueNum(0) {} - - virtual const char *getPassName() const { return "JavaScript backend"; } - - bool runOnModule(Module &M); - - void printProgram(const std::string& fname, const std::string& modName ); - void printModule(const std::string& fname, const std::string& modName ); - void printContents(const std::string& fname, const std::string& modName ); - void printFunction(const std::string& fname, const std::string& funcName ); - void printFunctions(); - void printInline(const std::string& fname, const std::string& funcName ); - void printVariable(const std::string& fname, const std::string& varName ); - - void error(const std::string& msg); - - formatted_raw_ostream& nl(formatted_raw_ostream &Out, int delta = 0); - - private: - void printCommaSeparated(const HeapData v); - - // parsing of constants has two phases: calculate, and then emit - void parseConstant(const std::string& name, const Constant* CV, bool calculate); - - #define MEM_ALIGN 8 - #define MEM_ALIGN_BITS 64 - - unsigned memAlign(unsigned x) { - return x + (x%MEM_ALIGN != 0 ? MEM_ALIGN - x%MEM_ALIGN : 0); - } - - HeapData *allocateAddress(const std::string& Name, unsigned Bits = MEM_ALIGN_BITS) { - assert(Bits == 64); // FIXME when we use optimal alignments - HeapData *GlobalData = NULL; - switch (Bits) { - case 8: GlobalData = &GlobalData8; break; - case 32: GlobalData = &GlobalData32; break; - case 64: GlobalData = &GlobalData64; break; - default: assert(false); - } - while (GlobalData->size() % (Bits/8) != 0) GlobalData->push_back(0); - GlobalAddresses[Name] = Address(GlobalData->size(), Bits); - return GlobalData; - } - - #define GLOBAL_BASE 8 - - // return the absolute offset of a global - unsigned getGlobalAddress(const std::string &s) { - if (GlobalAddresses.find(s) == GlobalAddresses.end()) dumpfailv("cannot find global address %s", s.c_str()); - Address a = GlobalAddresses[s]; - assert(a.second == 64); // FIXME when we use optimal alignments - switch (a.second) { - case 64: - assert((a.first + GLOBAL_BASE)%8 == 0); - return a.first + GLOBAL_BASE; - case 32: - assert((a.first + GLOBAL_BASE)%4 == 0); - return a.first + GLOBAL_BASE + GlobalData64.size(); - case 8: - return a.first + GLOBAL_BASE + GlobalData64.size() + GlobalData32.size(); - default: - dumpfailv("bad global address %s %d %d\n", s.c_str(), a.first, a.second); - } - } - // returns the internal offset inside the proper block: GlobalData8, 32, 64 - unsigned getRelativeGlobalAddress(const std::string &s) { - if (GlobalAddresses.find(s) == GlobalAddresses.end()) dumpfailv("cannot find global address %s", s.c_str()); - Address a = GlobalAddresses[s]; - return a.first; - } - char getFunctionSignatureLetter(Type *T) { - if (T->isVoidTy()) return 'v'; - else if (T->isFloatTy() || T->isDoubleTy()) return 'd'; // TODO: float - else return 'i'; - } - std::string getFunctionSignature(const FunctionType *F) { - std::string Ret; - Ret += getFunctionSignatureLetter(F->getReturnType()); - for (FunctionType::param_iterator AI = F->param_begin(), - AE = F->param_end(); AI != AE; ++AI) { - Ret += getFunctionSignatureLetter(*AI); - } - return Ret; - } - unsigned getFunctionIndex(const Function *F) { - std::string Name = getCppName(F); - if (IndexedFunctions.find(Name) != IndexedFunctions.end()) return IndexedFunctions[Name]; - std::string Sig = getFunctionSignature(F->getFunctionType()); - FunctionTable &Table = FunctionTables[Sig]; - // use alignment info to avoid unnecessary holes. This is not optimal though, - // (1) depends on order of appearance, and (2) really just need align for &class::method, see test_polymorph - unsigned Alignment = F->getAlignment() || 1; - while (Table.size() == 0 || Table.size() % Alignment) Table.push_back("0"); - unsigned Index = Table.size(); - Table.push_back(Name); - IndexedFunctions[Name] = Index; - - // invoke the callHandler for this, if there is one. the function may only be indexed but never called directly, we need to catch it in the handler - CallHandlerMap::iterator CH = CallHandlers->find(Name); - if (CH != CallHandlers->end()) { - (this->*(CH->second))(NULL, Name, -1); - } - - return Index; - } - void ensureFunctionTable(const FunctionType *F) { - FunctionTables[getFunctionSignature(F)]; - } - // Return a constant we are about to write into a global as a numeric offset. If the - // value is not known at compile time, emit a postSet to that location. - unsigned getConstAsOffset(const Value *V, unsigned AbsoluteTarget) { - if (const Function *F = dyn_cast<const Function>(V)) { - return getFunctionIndex(F); - } else { - if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) { - if (GV->hasExternalLinkage()) { - // We don't have a constant to emit here, so we must emit a postSet - // All postsets are of external values, so they are pointers, hence 32-bit - std::string Name = getOpName(V); - Externals.insert(Name); - PostSets += "HEAP32[" + utostr(AbsoluteTarget>>2) + "] = " + Name + ';'; - return 0; // emit zero in there for now, until the postSet - } - } - return getGlobalAddress(V->getName().str()); - } - } - std::string getPtrAsStr(const Value* Ptr) { - if (const Function *F = dyn_cast<Function>(Ptr)) { - return utostr(getFunctionIndex(F)); - } else if (const Constant *CV = dyn_cast<Constant>(Ptr)) { - if (const GlobalValue *GV = dyn_cast<GlobalValue>(Ptr)) { - if (GV->isDeclaration()) { - std::string Name = getOpName(Ptr); - Externals.insert(Name); - return Name; - } - } - return utostr(getGlobalAddress(CV->getName().str())); - } else { - return getOpName(Ptr); - } - } - - std::string getPtrLoad(const Value* Ptr); - std::string getPtrUse(const Value* Ptr); - std::string getConstant(const Constant*, AsmCast sign=ASM_SIGNED); - std::string getValueAsStr(const Value*, AsmCast sign=ASM_SIGNED); - std::string getValueAsCastStr(const Value*, AsmCast sign=ASM_SIGNED); - std::string getValueAsParenStr(const Value*); - std::string getValueAsCastParenStr(const Value*, AsmCast sign=ASM_SIGNED); - - std::string getCppName(const Value* val); - - std::string getPhiCode(const BasicBlock *From, const BasicBlock *To); - - void printAttributes(const AttributeSet &PAL, const std::string &name); - void printType(Type* Ty); - void printTypes(const Module* M); - - std::string getAssign(const StringRef &, const Type *); - std::string getCast(const StringRef &, const Type *, AsmCast sign=ASM_SIGNED); - std::string getParenCast(const StringRef &, const Type *, AsmCast sign=ASM_SIGNED); - std::string getDoubleToInt(const StringRef &); - std::string getIMul(const Value *, const Value *); - std::string getLoad(const std::string& Assign, const Value *P, const Type *T, unsigned Alignment, char sep=';'); - std::string getStore(const Value *P, const Type *T, const std::string& VS, unsigned Alignment, char sep=';'); - - void printFunctionBody(const Function *F); - void generateInstruction(const Instruction *I, raw_string_ostream& Code); - std::string getOpName(const Value*); - - void processConstants(); - - // nativization - - typedef std::set<const Value*> NativizedVarsMap; - NativizedVarsMap NativizedVars; - - void calculateNativizedVars(const Function *F); - - // special analyses - - bool canReloop(const Function *F); - - // main entry point - - void printModuleBody(); - }; -} // end anonymous namespace. - -formatted_raw_ostream &JSWriter::nl(formatted_raw_ostream &Out, int delta) { - Out << '\n'; - return Out; -} - -static inline void sanitize(std::string& str) { - for (size_t i = 1; i < str.length(); ++i) - if (!isalnum(str[i]) && str[i] != '_' && str[i] != '$') - str[i] = '_'; -} - -void JSWriter::error(const std::string& msg) { - report_fatal_error(msg); -} - -std::string JSWriter::getPhiCode(const BasicBlock *From, const BasicBlock *To) { - // FIXME this is all quite inefficient, and also done once per incoming to each phi - - // Find the phis, and generate assignments and dependencies - typedef std::map<std::string, std::string> StringMap; - StringMap assigns; // variable -> assign statement - std::map<std::string, Value*> values; // variable -> Value - StringMap deps; // variable -> dependency - StringMap undeps; // reverse: dependency -> variable - for (BasicBlock::const_iterator I = To->begin(), E = To->end(); - I != E; ++I) { - const PHINode* P = dyn_cast<PHINode>(I); - if (!P) break; - int index = P->getBasicBlockIndex(From); - if (index < 0) continue; - // we found it - std::string name = getCppName(P); - assigns[name] = getAssign(name, P->getType()); - Value *V = P->getIncomingValue(index); - values[name] = V; - std::string vname = getValueAsStr(V); - if (const Instruction *VI = dyn_cast<const Instruction>(V)) { - if (VI->getParent() == To) { - deps[name] = vname; - undeps[vname] = name; - } - } - } - // Emit assignments+values, taking into account dependencies, and breaking cycles - std::string pre = "", post = ""; - while (assigns.size() > 0) { - bool emitted = false; - for (StringMap::iterator I = assigns.begin(); I != assigns.end();) { - StringMap::iterator last = I; - std::string curr = last->first; - Value *V = values[curr]; - std::string CV = getValueAsStr(V); - I++; // advance now, as we may erase - // if we have no dependencies, or we found none to emit and are at the end (so there is a cycle), emit - StringMap::iterator dep = deps.find(curr); - if (dep == deps.end() || (!emitted && I == assigns.end())) { - if (dep != deps.end()) { - // break a cycle - std::string depString = dep->second; - std::string temp = curr + "$phi"; - pre += getAssign(temp, V->getType()) + CV + ';'; - CV = temp; - deps.erase(curr); - undeps.erase(depString); - } - post += assigns[curr] + CV + ';'; - assigns.erase(last); - emitted = true; - } - } - } - return pre + post; -} - -std::string JSWriter::getCppName(const Value* val) { - std::string name; - ValueMap::iterator I = ValueNames.find(val); - if (I != ValueNames.end() && I->first == val) - return I->second; - - if (val->hasName()) { - if (isa<Function>(val) || isa<Constant>(val)) { - name = std::string("_") + val->getName().str(); - } else { - name = std::string("$") + val->getName().str(); - } - sanitize(name); - } else { - name = "unique$" + utostr(UniqueNum++); - } - return ValueNames[val] = name; -} - -std::string JSWriter::getAssign(const StringRef &s, const Type *t) { - UsedVars[s] = t->getTypeID(); - return (s + " = ").str(); -} - -std::string JSWriter::getCast(const StringRef &s, const Type *t, AsmCast sign) { - switch (t->getTypeID()) { - default: assert(false && "Unsupported type"); - case Type::FloatTyID: // TODO return ("Math_fround(" + s + ")").str(); - case Type::DoubleTyID: return ("+" + s).str(); - case Type::IntegerTyID: { - // fall through to the end for nonspecific - switch (t->getIntegerBitWidth()) { - case 1: if (sign != ASM_NONSPECIFIC) return (s + "&1").str(); - case 8: if (sign != ASM_NONSPECIFIC) return sign == ASM_UNSIGNED ? (s + "&255").str() : (s + "<<24>>24").str(); - case 16: if (sign != ASM_NONSPECIFIC) return sign == ASM_UNSIGNED ? (s + "&65535").str() : (s + "<<16>>16").str(); - case 32: return (sign == ASM_SIGNED || sign == ASM_NONSPECIFIC ? s + "|0" : s + ">>>0").str(); - default: assert(0); - } - } - case Type::PointerTyID: return (s + "|0").str(); - } -} - -std::string JSWriter::getParenCast(const StringRef &s, const Type *t, AsmCast sign) { - return getCast(("(" + s + ")").str(), t, sign); -} - -std::string JSWriter::getDoubleToInt(const StringRef &s) { - return ("~~(" + s + ")").str(); -} - -std::string JSWriter::getIMul(const Value *V1, const Value *V2) { - const ConstantInt *CI = NULL; - const Value *Other = NULL; - if ((CI = dyn_cast<ConstantInt>(V1))) { - Other = V2; - } else if ((CI = dyn_cast<ConstantInt>(V2))) { - Other = V1; - } - // we ignore optimizing the case of multiplying two constants - optimizer would have removed those - if (CI) { - std::string OtherStr = getValueAsStr(Other); - unsigned C = CI->getZExtValue(); - if (C == 0) return "0"; - if (C == 1) return OtherStr; - unsigned Orig = C, Shifts = 0; - while (C) { - if ((C & 1) && (C != 1)) break; // not power of 2 - C >>= 1; - Shifts++; - if (C == 0) return OtherStr + "<<" + utostr(Shifts-1); // power of 2, emit shift - } - if (Orig < (1<<20)) return "(" + OtherStr + "*" + utostr(Orig) + ")|0"; // small enough, avoid imul - } - return "Math_imul(" + getValueAsStr(V1) + ", " + getValueAsStr(V2) + ")|0"; // unknown or too large, emit imul -} - -std::string JSWriter::getLoad(const std::string& Assign, const Value *P, const Type *T, unsigned Alignment, char sep) { - unsigned Bytes = T->getPrimitiveSizeInBits()/8; - std::string text; - if (Bytes <= Alignment || Alignment == 0) { - text = Assign + getPtrLoad(P); - if (Alignment == 536870912) text += "; abort() /* segfault */"; - } else { - // unaligned in some manner - std::string PS = getOpName(P); - switch (Bytes) { - case 8: { - switch (Alignment) { - case 4: { - text = "HEAP32[tempDoublePtr>>2]=HEAP32[" + PS + ">>2]" + sep + - "HEAP32[tempDoublePtr+4>>2]=HEAP32[" + PS + "+4>>2]"; - break; - } - case 2: { - text = "HEAP16[tempDoublePtr>>1]=HEAP16[" + PS + ">>1]" + sep + - "HEAP16[tempDoublePtr+2>>1]=HEAP16[" + PS + "+2>>1]" + sep + - "HEAP16[tempDoublePtr+4>>1]=HEAP16[" + PS + "+4>>1]" + sep + - "HEAP16[tempDoublePtr+6>>1]=HEAP16[" + PS + "+6>>1]"; - break; - } - case 1: { - text = "HEAP8[tempDoublePtr]=HEAP8[" + PS + "]" + sep + - "HEAP8[tempDoublePtr+1]=HEAP8[" + PS + "+1|0]" + sep + - "HEAP8[tempDoublePtr+2]=HEAP8[" + PS + "+2|0]" + sep + - "HEAP8[tempDoublePtr+3]=HEAP8[" + PS + "+3|0]" + sep + - "HEAP8[tempDoublePtr+4]=HEAP8[" + PS + "+4|0]" + sep + - "HEAP8[tempDoublePtr+5]=HEAP8[" + PS + "+5|0]" + sep + - "HEAP8[tempDoublePtr+6]=HEAP8[" + PS + "+6|0]" + sep + - "HEAP8[tempDoublePtr+7]=HEAP8[" + PS + "+7|0]"; - break; - } - default: assert(0 && "bad 8 store"); - } - text += sep + Assign + "+HEAPF64[tempDoublePtr>>3]"; - break; - } - case 4: { - if (T->isIntegerTy()) { - switch (Alignment) { - case 2: { - text = Assign + "HEAPU16[" + PS + ">>1]|" + - "(HEAPU16[" + PS + "+2>>1]<<16)"; - break; - } - case 1: { - text = Assign + "HEAPU8[" + PS + "]|" + - "(HEAPU8[" + PS + "+1|0]<<8)|" + - "(HEAPU8[" + PS + "+2|0]<<16)|" + - "(HEAPU8[" + PS + "+3|0]<<24)"; - break; - } - default: assert(0 && "bad 4i store"); - } - } else { // float - switch (Alignment) { - case 2: { - text = "HEAP16[tempDoublePtr>>1]=HEAP16[" + PS + ">>1]" + sep + - "HEAP16[tempDoublePtr+2>>1]=HEAP16[" + PS + "+2>>1]"; - break; - } - case 1: { - text = "HEAP8[tempDoublePtr]=HEAP8[" + PS + "]" + sep + - "HEAP8[tempDoublePtr+1|0]=HEAP8[" + PS + "+1|0]" + sep + - "HEAP8[tempDoublePtr+2|0]=HEAP8[" + PS + "+2|0]" + sep + - "HEAP8[tempDoublePtr+3|0]=HEAP8[" + PS + "+3|0]"; - break; - } - default: assert(0 && "bad 4f store"); - } - text += Assign + "+HEAPF32[tempDoublePtr>>2]"; - } - break; - } - case 2: { - text = Assign + "HEAPU8[" + PS + "]|" + - "(HEAPU8[" + PS + "+1|0]<<8)"; - break; - } - default: assert(0 && "bad store"); - } - } - return text; -} - -std::string JSWriter::getStore(const Value *P, const Type *T, const std::string& VS, unsigned Alignment, char sep) { - assert(sep == ';'); // FIXME when we need that - unsigned Bytes = T->getPrimitiveSizeInBits()/8; - std::string text; - if (Bytes <= Alignment || Alignment == 0) { - text = getPtrUse(P) + " = " + VS; - if (Alignment == 536870912) text += "; abort() /* segfault */"; - } else { - // unaligned in some manner - std::string PS = getOpName(P); - switch (Bytes) { - case 8: { - text = "HEAPF64[tempDoublePtr>>3]=" + VS + ';'; - switch (Alignment) { - case 4: { - text += "HEAP32[" + PS + ">>2]=HEAP32[tempDoublePtr>>2];" + - "HEAP32[" + PS + "+4>>2]=HEAP32[tempDoublePtr+4>>2]"; - break; - } - case 2: { - text += "HEAP16[" + PS + ">>1]=HEAP16[tempDoublePtr>>1];" + - "HEAP16[" + PS + "+2>>1]=HEAP16[tempDoublePtr+2>>1];" + - "HEAP16[" + PS + "+4>>1]=HEAP16[tempDoublePtr+4>>1];" + - "HEAP16[" + PS + "+6>>1]=HEAP16[tempDoublePtr+6>>1]"; - break; - } - case 1: { - text += "HEAP8[" + PS + "]=HEAP8[tempDoublePtr];" + - "HEAP8[" + PS + "+1|0]=HEAP8[tempDoublePtr+1|0];" + - "HEAP8[" + PS + "+2|0]=HEAP8[tempDoublePtr+2|0];" + - "HEAP8[" + PS + "+3|0]=HEAP8[tempDoublePtr+3|0];" + - "HEAP8[" + PS + "+4|0]=HEAP8[tempDoublePtr+4|0];" + - "HEAP8[" + PS + "+5|0]=HEAP8[tempDoublePtr+5|0];" + - "HEAP8[" + PS + "+6|0]=HEAP8[tempDoublePtr+6|0];" + - "HEAP8[" + PS + "+7|0]=HEAP8[tempDoublePtr+7|0]"; - break; - } - default: assert(0 && "bad 8 store"); - } - break; - } - case 4: { - if (T->isIntegerTy()) { - switch (Alignment) { - case 2: { - text = "HEAP16[" + PS + ">>1]=" + VS + "&65535;" + - "HEAP16[" + PS + "+2>>1]=" + VS + ">>>16"; - break; - } - case 1: { - text = "HEAP8[" + PS + "]=" + VS + "&255;" + - "HEAP8[" + PS + "+1|0]=(" + VS + ">>8)&255;" + - "HEAP8[" + PS + "+2|0]=(" + VS + ">>16)&255;" + - "HEAP8[" + PS + "+3|0]=" + VS + ">>24"; - break; - } - default: assert(0 && "bad 4i store"); - } - } else { // float - text = "HEAPF32[tempDoublePtr>>2]=" + VS + ';'; - switch (Alignment) { - case 2: { - text += "HEAP16[" + PS + ">>1]=HEAP16[tempDoublePtr>>1];" + - "HEAP16[" + PS + "+2>>1]=HEAP16[tempDoublePtr+2>>1]"; - break; - } - case 1: { - text += "HEAP8[" + PS + "]=HEAP8[tempDoublePtr];" + - "HEAP8[" + PS + "+1|0]=HEAP8[tempDoublePtr+1|0];" + - "HEAP8[" + PS + "+2|0]=HEAP8[tempDoublePtr+2|0];" + - "HEAP8[" + PS + "+3|0]=HEAP8[tempDoublePtr+3|0]"; - break; - } - default: assert(0 && "bad 4f store"); - } - } - break; - } - case 2: { - text = "HEAP8[" + PS + "]=" + VS + "&255;" + - "HEAP8[" + PS + "+1|0]=" + VS + ">>8"; - break; - } - default: assert(0 && "bad store"); - } - } - return text; -} - -std::string JSWriter::getOpName(const Value* V) { // TODO: remove this - return getCppName(V); -} - -std::string JSWriter::getPtrLoad(const Value* Ptr) { - Type *t = cast<PointerType>(Ptr->getType())->getElementType(); - return getCast(getPtrUse(Ptr), t, ASM_NONSPECIFIC); -} - -std::string JSWriter::getPtrUse(const Value* Ptr) { - Type *t = cast<PointerType>(Ptr->getType())->getElementType(); - unsigned Bytes = t->getPrimitiveSizeInBits()/8; - if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) { - std::string text = ""; - unsigned Addr = getGlobalAddress(GV->getName().str()); - switch (Bytes) { - default: assert(false && "Unsupported type"); - case 8: return "HEAPF64[" + utostr(Addr >> 3) + "]"; - case 4: { - if (t->isIntegerTy()) { - return "HEAP32[" + utostr(Addr >> 2) + "]"; - } else { - return "HEAPF32[" + utostr(Addr >> 2) + "]"; - } - } - case 2: return "HEAP16[" + utostr(Addr >> 1) + "]"; - case 1: return "HEAP8[" + utostr(Addr) + "]"; - } - } else { - std::string Name = getOpName(Ptr); - switch (Bytes) { - default: assert(false && "Unsupported type"); - case 8: return "HEAPF64[" + Name + ">>3]"; - case 4: { - if (t->isIntegerTy()) { - return "HEAP32[" + Name + ">>2]"; - } else { - return "HEAPF32[" + Name + ">>2]"; - } - } - case 2: return "HEAP16[" + Name + ">>1]"; - case 1: return "HEAP8[" + Name + "]"; - } - } -} - -static int hexToInt(char x) { - if (x <= '9') { - assert(x >= '0'); - return x - '0'; - } else { - assert('A' <= x && x <= 'F'); - return x - 'A' + 10; - } -} - -/* static inline std::string ftostr(const APFloat& V) { - std::string Buf; - if (&V.getSemantics() == &APFloat::IEEEdouble) { - raw_string_ostream(Buf) << V.convertToDouble(); - return Buf; - } else if (&V.getSemantics() == &APFloat::IEEEsingle) { - raw_string_ostream(Buf) << (double)V.convertToFloat(); - return Buf; - } - return "<unknown format in ftostr>"; // error -} */ - -static inline std::string ftostr_exact(const ConstantFP *CFP) { - std::string temp; - raw_string_ostream stream(temp); - stream << *CFP; // bitcast on APF produces odd results, so do it this horrible way - const char *raw = temp.c_str(); - if (CFP->getType()->isFloatTy()) { - raw += 6; // skip "float " - } else { - raw += 7; // skip "double " - } - if (raw[1] != 'x') return raw; // number has already been printed out - raw += 2; // skip "0x" - unsigned len = strlen(raw); - assert((len&1) == 0); // must be complete bytes, so an even number of chars - unsigned missing = 8 - len/2; - union dbl { double d; unsigned char b[sizeof(double)]; } dbl; - dbl.d = 0; - for (unsigned i = 0; i < 8 - missing; i++) { - dbl.b[7-i] = (hexToInt(raw[2*i]) << 4) | - hexToInt(raw[2*i+1]); - } - char buffer[101]; - snprintf(buffer, 100, "%.30g", dbl.d); - return buffer; -} - -std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) { - if (isa<PointerType>(CV->getType())) { - return getPtrAsStr(CV); - } else { - if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) { - std::string S = ftostr_exact(CFP); - S = '+' + S; - //if (S.find('.') == S.npos) { TODO: do this when necessary, but it is necessary even for 0.0001 - return S; - } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) { - if (sign == ASM_SIGNED && CI->getValue().getBitWidth() == 1) sign = ASM_UNSIGNED; // booleans cannot be signed in a meaningful way - return CI->getValue().toString(10, sign != ASM_UNSIGNED); - } else if (isa<UndefValue>(CV)) { - return CV->getType()->isIntegerTy() ? "0" : "+0"; // XXX fround, refactor this - } else { - dumpIR(CV); - assert(false); - } - } -} - -std::string JSWriter::getValueAsStr(const Value* V, AsmCast sign) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV, sign); - } else { - return getCppName(V); - } -} - -std::string JSWriter::getValueAsCastStr(const Value* V, AsmCast sign) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV, sign); - } else { - return getCast(getCppName(V), V->getType(), sign); - } -} - -std::string JSWriter::getValueAsParenStr(const Value* V) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV); - } else { - return "(" + getCppName(V) + ")"; - } -} - -std::string JSWriter::getValueAsCastParenStr(const Value* V, AsmCast sign) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV, sign); - } else { - return "(" + getCast(getCppName(V), V->getType(), sign) + ")"; - } -} - -// generateInstruction - This member is called for each Instruction in a function. -void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Code) { - std::string iName(getCppName(I)); - - Type *T = I->getType(); - if (T->isIntegerTy() && T->getIntegerBitWidth() > 32) { - dumpIR(I); - assert(0 && "FIXME: finish legalization"); // FIXME - } - - switch (I->getOpcode()) { - default: - error("Invalid instruction"); - break; - - case Instruction::Ret: { - const ReturnInst* ret = cast<ReturnInst>(I); - Value *RV = ret->getReturnValue(); - Code << "STACKTOP = sp;"; - Code << "return"; - if (RV == NULL) { - Code << ";"; - } else { - Code << " " + getValueAsCastStr(RV, ASM_NONSPECIFIC) + ";"; - } - break; - } - case Instruction::Br: - case Instruction::Switch: break; // handled while relooping - case Instruction::Unreachable: { - // No need to emit anything, as there should be an abort right before these - // Code << "abort();"; - break; - } - case Instruction::Add: - case Instruction::FAdd: - case Instruction::Sub: - case Instruction::FSub: - case Instruction::Mul: - case Instruction::FMul: - case Instruction::UDiv: - case Instruction::SDiv: - case Instruction::FDiv: - case Instruction::URem: - case Instruction::SRem: - case Instruction::FRem: - case Instruction::And: - case Instruction::Or: - case Instruction::Xor: - case Instruction::Shl: - case Instruction::LShr: - case Instruction::AShr:{ - Code << getAssign(iName, I->getType()); - unsigned opcode = I->getOpcode(); - switch (opcode) { - case Instruction::Add: Code << getParenCast( - getValueAsParenStr(I->getOperand(0)) + - " + " + - getValueAsParenStr(I->getOperand(1)), - I->getType() - ); break; - case Instruction::Sub: Code << getParenCast( - getValueAsParenStr(I->getOperand(0)) + - " - " + - getValueAsParenStr(I->getOperand(1)), - I->getType() - ); break; - case Instruction::Mul: Code << getIMul(I->getOperand(0), I->getOperand(1)); break; - case Instruction::UDiv: - case Instruction::SDiv: - case Instruction::URem: - case Instruction::SRem: Code << "(" + - getValueAsCastParenStr(I->getOperand(0), (opcode == Instruction::SDiv || opcode == Instruction::SRem) ? ASM_SIGNED : ASM_UNSIGNED) + - ((opcode == Instruction::UDiv || opcode == Instruction::SDiv) ? " / " : " % ") + - getValueAsCastParenStr(I->getOperand(1), (opcode == Instruction::SDiv || opcode == Instruction::SRem) ? ASM_SIGNED : ASM_UNSIGNED) + - ")&-1"; break; - case Instruction::And: Code << getValueAsStr(I->getOperand(0)) + " & " + getValueAsStr(I->getOperand(1)); break; - case Instruction::Or: Code << getValueAsStr(I->getOperand(0)) + " | " + getValueAsStr(I->getOperand(1)); break; - case Instruction::Xor: Code << getValueAsStr(I->getOperand(0)) + " ^ " + getValueAsStr(I->getOperand(1)); break; - case Instruction::Shl: { - std::string Shifted = getValueAsStr(I->getOperand(0)) + " << " + getValueAsStr(I->getOperand(1)); - if (I->getType()->getIntegerBitWidth() < 32) { - Shifted = getParenCast(Shifted, I->getType(), ASM_UNSIGNED); // remove bits that are shifted beyond the size of this value - } - Code << Shifted; - break; - } - case Instruction::AShr: - case Instruction::LShr: { - std::string Input = getValueAsStr(I->getOperand(0)); - if (I->getType()->getIntegerBitWidth() < 32) { - Input = '(' + getCast(Input, I->getType(), opcode == Instruction::AShr ? ASM_SIGNED : ASM_UNSIGNED) + ')'; // fill in high bits, as shift needs those and is done in 32-bit - } - Code << Input + (opcode == Instruction::AShr ? " >> " : " >>> ") + getValueAsStr(I->getOperand(1)); - break; - } - case Instruction::FAdd: Code << getValueAsStr(I->getOperand(0)) + " + " + getValueAsStr(I->getOperand(1)); break; // TODO: ensurefloat here - case Instruction::FSub: Code << getValueAsStr(I->getOperand(0)) + " - " + getValueAsStr(I->getOperand(1)); break; - case Instruction::FMul: Code << getValueAsStr(I->getOperand(0)) + " * " + getValueAsStr(I->getOperand(1)); break; - case Instruction::FDiv: Code << getValueAsStr(I->getOperand(0)) + " / " + getValueAsStr(I->getOperand(1)); break; - case Instruction::FRem: Code << getValueAsStr(I->getOperand(0)) + " % " + getValueAsStr(I->getOperand(1)); break; - default: error("bad icmp"); break; - } - Code << ';'; - break; - } - case Instruction::FCmp: { - Code << getAssign(iName, I->getType()); - switch (cast<FCmpInst>(I)->getPredicate()) { - case FCmpInst::FCMP_OEQ: - case FCmpInst::FCMP_UEQ: Code << getValueAsStr(I->getOperand(0)) + " == " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_ONE: - case FCmpInst::FCMP_UNE: Code << getValueAsStr(I->getOperand(0)) + " != " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_OGT: - case FCmpInst::FCMP_UGT: Code << getValueAsStr(I->getOperand(0)) + " > " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_OGE: - case FCmpInst::FCMP_UGE: Code << getValueAsStr(I->getOperand(0)) + " >= " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_ULT: Code << getValueAsStr(I->getOperand(0)) + " < " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_OLE: - case FCmpInst::FCMP_ULE: Code << getValueAsStr(I->getOperand(0)) + " <= " + getValueAsStr(I->getOperand(1)); break; - case FCmpInst::FCMP_ORD: Code << "(" + getValueAsStr(I->getOperand(0)) + " == " + getValueAsStr(I->getOperand(0)) + ") & " + - "(" + getValueAsStr(I->getOperand(1)) + " == " + getValueAsStr(I->getOperand(1)) + ")"; break; - case FCmpInst::FCMP_UNO: Code << "(" + getValueAsStr(I->getOperand(0)) + " != " + getValueAsStr(I->getOperand(0)) + ") | " + - "(" + getValueAsStr(I->getOperand(1)) + " != " + getValueAsStr(I->getOperand(1)) + ")"; break; - case FCmpInst::FCMP_FALSE: Code << "0"; break; - case FCmpInst::FCMP_TRUE : Code << "1"; break; - default: error("bad fcmp"); break; - } - Code &l |