aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/CppBackend/CPPBackend.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-12-27 19:57:19 -0800
committerAlon Zakai <alonzakai@gmail.com>2013-12-27 19:57:19 -0800
commit81afe65c6fa734101c96dc99ec10b1aed3f43602 (patch)
tree7af4be660811c17f77cefe25c9be2b7df36df980 /lib/Target/CppBackend/CPPBackend.cpp
parent9a21bed266588de64040a9ec3b3dafa912eb4c6a (diff)
CPPBackend => JSBackend
Diffstat (limited to 'lib/Target/CppBackend/CPPBackend.cpp')
-rw-r--r--lib/Target/CppBackend/CPPBackend.cpp1738
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 << ";";
- break;
- }
- case Instruction::ICmp: {
- unsigned predicate = cast<ICmpInst>(I)->getPredicate();
- AsmCast sign = (predicate == ICmpInst::ICMP_ULE ||
- predicate == ICmpInst::ICMP_UGE ||
- predicate == ICmpInst::ICMP_ULT ||
- predicate == ICmpInst::ICMP_UGT) ? ASM_UNSIGNED : ASM_SIGNED;
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) + "(" +
- getValueAsCastStr(I->getOperand(0), sign) +
- ")";
- switch (predicate) {
- case ICmpInst::ICMP_EQ: Code << "=="; break;
- case ICmpInst::ICMP_NE: Code << "!="; break;
- case ICmpInst::ICMP_ULE: Code << "<="; break;
- case ICmpInst::ICMP_SLE: Code << "<="; break;
- case ICmpInst::ICMP_UGE: Code << ">="; break;
- case ICmpInst::ICMP_SGE: Code << ">="; break;
- case ICmpInst::ICMP_ULT: Code << "<"; break;
- case ICmpInst::ICMP_SLT: Code << "<"; break;
- case ICmpInst::ICMP_UGT: Code << ">"; break;
- case ICmpInst::ICMP_SGT: Code << ">"; break;
- default: assert(0);
- }
- Code << "(" +
- getValueAsCastStr(I->getOperand(1), sign) +
- ");";
- break;
- }
- case Instruction::Alloca: {
- if (NativizedVars.count(I)) {
- // nativized stack variable, we just need a 'var' definition
- UsedVars[iName] = cast<PointerType>(I->getType())->getElementType()->getTypeID();
- break;
- }
- const AllocaInst* AI = cast<AllocaInst>(I);
- Type *T = AI->getAllocatedType();
- assert(!isa<ArrayType>(T));
- const Value *AS = AI->getArraySize();
- unsigned BaseSize = T->getScalarSizeInBits()/8;
- std::string Size;
- if (const ConstantInt *CI = dyn_cast<ConstantInt>(AS)) {
- Size = Twine(memAlign(BaseSize * CI->getZExtValue())).str();
- } else {
- Size = "((" + utostr(BaseSize) + '*' + getValueAsStr(AS) + ")|0)";
- }
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) + "STACKTOP; STACKTOP = STACKTOP + " + Size + "|0;";
- break;
- }
- case Instruction::Load: {
- const LoadInst *LI = cast<LoadInst>(I);
- const Value *P = LI->getPointerOperand();
- unsigned Alignment = LI->getAlignment();
- std::string Assign = getAssign(iName, LI->getType());
- if (NativizedVars.count(P)) {
- Code << Assign + getValueAsStr(P) + ';';
- } else {
- Code << getLoad(Assign, P, LI->getType(), Alignment) + ';';
- }
- break;
- }
- case Instruction::Store: {
- const StoreInst *SI = cast<StoreInst>(I);
- const Value *P = SI->getPointerOperand();
- const Value *V = SI->getValueOperand();
- unsigned Alignment = SI->getAlignment();
- std::string VS = getValueAsStr(V);
- if (NativizedVars.count(P)) {
- Code << getValueAsStr(P) + " = " + VS + ';';
- } else {
- Code << getStore(P, V->getType(), VS, Alignment) + ';';
- }
-
- Type *T = V->getType();
- if (T->isIntegerTy() && T->getIntegerBitWidth() > 32) {
- assert(0 && "FIXME: finish legalization"); // FIXME
- }
- break;
- }
- case Instruction::GetElementPtr: {
- assert(false && "Unhandled instruction");
- break;
- }
- case Instruction::PHI: {
- // handled separately - we push them back into the relooper branchings
- break;
- }
- case Instruction::PtrToInt:
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) + getPtrAsStr(I->getOperand(0)) + ';';
- break;
- case Instruction::IntToPtr:
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) + getValueAsStr(I->getOperand(0)) + ";";
- break;
- case Instruction::Trunc:
- case Instruction::ZExt:
- case Instruction::SExt:
- case Instruction::FPTrunc:
- case Instruction::FPExt:
- case Instruction::FPToUI:
- case Instruction::FPToSI:
- case Instruction::UIToFP:
- case Instruction::SIToFP: {
- Code << getAssign(iName, I->getType());
- switch (I->getOpcode()) {
- case Instruction::Trunc: {
- //unsigned inBits = V->getType()->getIntegerBitWidth();
- unsigned outBits = I->getType()->getIntegerBitWidth();
- Code << getValueAsStr(I->getOperand(0)) + "&" + utostr(pow(2, outBits)-1);
- break;
- }
- case Instruction::SExt: {
- std::string bits = utostr(32 - I->getOperand(0)->getType()->getIntegerBitWidth());
- Code << getValueAsStr(I->getOperand(0)) + " << " + bits + " >> " + bits;
- break;
- }
- case Instruction::ZExt: Code << getValueAsCastStr(I->getOperand(0), ASM_UNSIGNED); break;
- case Instruction::FPExt: Code << getValueAsStr(I->getOperand(0)); break; // TODO: fround
- case Instruction::FPTrunc: Code << getValueAsStr(I->getOperand(0)); break; // TODO: fround
- case Instruction::SIToFP: Code << getCast(getValueAsCastParenStr(I->getOperand(0), ASM_SIGNED), I->getType()); break;
- case Instruction::UIToFP: Code << getCast(getValueAsCastParenStr(I->getOperand(0), ASM_UNSIGNED), I->getType()); break;
- case Instruction::FPToSI: Code << getDoubleToInt(getValueAsParenStr(I->getOperand(0))); break;
- case Instruction::FPToUI: Code << getCast(getDoubleToInt(getValueAsParenStr(I->getOperand(0))), I->getType(), ASM_UNSIGNED); break;
- case Instruction::PtrToInt: Code << getValueAsStr(I->getOperand(0)); break;
- case Instruction::IntToPtr: Code << getValueAsStr(I->getOperand(0)); break;
- default: llvm_unreachable("Unreachable");
- }
- Code << ";";
- break;
- }
- case Instruction::BitCast: {
- Code << getAssign(iName, I->getType());
- // Most bitcasts are no-ops for us. However, the exception is int to float and float to int
- Type *InType = I->getOperand(0)->getType();
- Type *OutType = I->getType();
- std::string V = getValueAsStr(I->getOperand(0));
- if (InType->isIntegerTy() && OutType->isFloatingPointTy()) {
- assert(InType->getIntegerBitWidth() == 32);
- Code << "(HEAP32[tempDoublePtr>>2]=" + V + "," + "+HEAPF32[tempDoublePtr>>2]);";
- } else if (OutType->isIntegerTy() && InType->isFloatingPointTy()) {
- assert(OutType->getIntegerBitWidth() == 32);
- Code << "(HEAPF32[tempDoublePtr>>2]=" + V + "," + "HEAP32[tempDoublePtr>>2]|0);";
- } else {
- Code << V + ";";
- }
- break;
- }
- case Instruction::Call: {
- const CallInst *CI = cast<CallInst>(I);
- Code << handleCall(CI) + ';';
- break;
- }
- case Instruction::Select: {
- const SelectInst* SI = cast<SelectInst>(I);
- Code << getAssign(iName, I->getType()) + getValueAsStr(SI->getCondition()) + " ? " +
- getValueAsStr(SI->getTrueValue()) + " : " +
- getValueAsStr(SI->getFalseValue()) + ';';
- break;
- }
- case Instruction::AtomicCmpXchg: {
- std::string Assign = getAssign(iName, I->getType());
- const Value *P = I->getOperand(0);
- Code << getLoad(Assign, P, I->getType(), 0) + ';' +
- "if ((" + getCast(iName, I->getType()) + ") == " + getValueAsCastParenStr(I->getOperand(1)) + ") " +
- getStore(P, I->getType(), getValueAsStr(I->getOperand(2)), 0) + ";";
- break;
- }
- case Instruction::AtomicRMW: {
- const AtomicRMWInst *rmwi = cast<AtomicRMWInst>(I);
- const Value *P = rmwi->getOperand(0);
- const Value *V = rmwi->getOperand(1);
- std::string Assign = getAssign(iName, I->getType());
- std::string VS = getValueAsStr(V);
- Code << getLoad(Assign, 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(P, I->getType(), VS, 0); break;
- case AtomicRMWInst::Add: Code << getStore(P, I->getType(), "((" + VS + '+' + iName + ")|0)", 0); break;
- case AtomicRMWInst::Sub: Code << getStore(P, I->getType(), "((" + VS + '-' + iName + ")|0)", 0); break;
- case AtomicRMWInst::And: Code << getStore(P, I->getType(), "(" + VS + '&' + iName + ")", 0); break;
- case AtomicRMWInst::Nand: Code << getStore(P, I->getType(), "(~(" + VS + '&' + iName + "))", 0); break;
- case AtomicRMWInst::Or: Code << getStore(P, I->getType(), "(" + VS + '|' + iName + ")", 0); break;
- case AtomicRMWInst::Xor: Code << getStore(P, I->getType(), "(" + VS + '^' + iName + ")", 0); break;
- case AtomicRMWInst::Max:
- case AtomicRMWInst::Min:
- case AtomicRMWInst::UMax:
- case AtomicRMWInst::UMin:
- case AtomicRMWInst::BAD_BINOP: llvm_unreachable("Bad atomic operation");
- }
- Code << ";";
- break;
- }
- }
- // append debug info
- if (MDNode *N = I->getMetadata("dbg")) {
- DILocation Loc(N);
- unsigned Line = Loc.getLineNumber();
- StringRef File = Loc.getFilename();
- Code << " //@line " + utostr(Line) + " \"" + File.str() + "\"";
- }
-}
-
-static const SwitchInst *considerSwitch(const Instruction *I) {
- const SwitchInst *SI = dyn_cast<SwitchInst>(I);
- if (!SI) return NULL;
- // use a switch if the range is not too big or sparse
- int Minn = INT_MAX, Maxx = INT_MIN, Num = 0;
- for (SwitchInst::ConstCaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) {
- const IntegersSubset CaseVal = i.getCaseValueEx();
- assert(CaseVal.isSingleNumbersOnly());
- std::string Condition = "";
- for (unsigned Index = 0; Index < CaseVal.getNumItems(); Index++) {
- int Curr = CaseVal.getSingleNumber(Index).toConstantInt()->getZExtValue();
- if (Curr < Minn) Minn = Curr;
- if (Curr > Maxx) Maxx = Curr;
- }
- Num++;
- }
- int Range = Maxx - Minn;
- return Num < 5 || Range > 10*1024 || (Range/Num) > 1024 ? NULL : SI; // heuristics
-}
-
-void JSWriter::printFunctionBody(const Function *F) {
- assert(!F->isDeclaration());
-
- // Prepare relooper TODO: resize buffer as needed
- #define RELOOPER_BUFFER 10*1024*1024
- static char *buffer = new char[RELOOPER_BUFFER];
- Relooper::SetOutputBuffer(buffer, RELOOPER_BUFFER);
- Relooper R;
- //if (!canReloop(F)) R.SetEmulate(true);
- R.SetAsmJSMode(1);
- Block *Entry = NULL;
- std::map<const BasicBlock*, Block*> LLVMToRelooper;
-
- // Create relooper blocks with their contents
- for (Function::const_iterator BI = F->begin(), BE = F->end();
- BI != BE; ++BI) {
- std::string Code;
- raw_string_ostream CodeStream(Code);
- for (BasicBlock::const_iterator I = BI->begin(), E = BI->end();
- I != E; ++I) {
- generateInstruction(I, CodeStream);
- CodeStream << '\n';
- }
- CodeStream.flush();
- const SwitchInst* SI = considerSwitch(BI->getTerminator());
- Block *Curr = new Block(Code.c_str(), SI ? getValueAsCastStr(SI->getCondition()).c_str() : NULL);
- const BasicBlock *BB = &*BI;
- LLVMToRelooper[BB] = Curr;
- R.AddBlock(Curr);
- if (!Entry) Entry = Curr;
- }
-
- // Create branchings
- for (Function::const_iterator BI = F->begin(), BE = F->end();
- BI != BE; ++BI) {
- const TerminatorInst *TI = BI->getTerminator();
- switch (TI->getOpcode()) {
- default: {
- dumpfailv("invalid branch instr %s\n", TI->getOpcodeName());
- break;
- }
- case Instruction::Br: {
- const BranchInst* br = cast<BranchInst>(TI);
- if (br->getNumOperands() == 3) {
- BasicBlock *S0 = br->getSuccessor(0);
- BasicBlock *S1 = br->getSuccessor(1);
- std::string P0 = getPhiCode(&*BI, S0);
- std::string P1 = getPhiCode(&*BI, S1);
- LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*S0], getValueAsStr(TI->getOperand(0)).c_str(), P0.size() > 0 ? P0.c_str() : NULL);
- LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*S1], NULL, P1.size() > 0 ? P1.c_str() : NULL);
- } else if (br->getNumOperands() == 1) {
- BasicBlock *S = br->getSuccessor(0);
- std::string P = getPhiCode(&*BI, S);
- LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*S], NULL, P.size() > 0 ? P.c_str() : NULL);
- } else {
- error("Branch with 2 operands?");
- }
- break;
- }
- case Instruction::Switch: {
- const SwitchInst* SI = cast<SwitchInst>(TI);
- bool UseSwitch = !!considerSwitch(SI);
- BasicBlock *DD = SI->getDefaultDest();
- std::string P = getPhiCode(&*BI, DD);
- LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*DD], NULL, P.size() > 0 ? P.c_str() : NULL);
- typedef std::map<const BasicBlock*, std::string> BlockCondMap;
- BlockCondMap BlocksToConditions;
- for (SwitchInst::ConstCaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) {
- const BasicBlock *BB = i.getCaseSuccessor();
- const IntegersSubset CaseVal = i.getCaseValueEx();
- assert(CaseVal.isSingleNumbersOnly());
- std::string Condition = "";
- for (unsigned Index = 0; Index < CaseVal.getNumItems(); Index++) {
- std::string Curr = CaseVal.getSingleNumber(Index).toConstantInt()->getValue().toString(10, true);
- if (UseSwitch) {
- Condition += "case " + Curr + ": ";
- } else {
- if (Condition.size() > 0) Condition += " | ";
- Condition += "(" + getValueAsCastParenStr(SI->getCondition()) + " == " + Curr + ")";
- }
- }
- BlocksToConditions[BB] = Condition + (!UseSwitch && BlocksToConditions[BB].size() > 0 ? " | " : "") + BlocksToConditions[BB];
- }
- for (BlockCondMap::iterator I = BlocksToConditions.begin(), E = BlocksToConditions.end(); I != E; ++I) {
- const BasicBlock *BB = I->first;
- std::string P = getPhiCode(&*BI, BB);
- LLVMToRelooper[&*BI]->AddBranchTo(LLVMToRelooper[&*BB], I->second.c_str(), P.size() > 0 ? P.c_str() : NULL);
- }
- break;
- }
- case Instruction::Ret:
- case Instruction::Unreachable: break;
- }
- }
-
- // Calculate relooping and print
- R.Calculate(Entry);
- R.Render();
-
- // Emit local variables
- UsedVars["sp"] = Type::getInt32Ty(F->getContext())->getTypeID();
- UsedVars["label"] = Type::getInt32Ty(F->getContext())->getTypeID();
- if (!UsedVars.empty()) {
- unsigned Count = 0;
- for (VarMap::iterator VI = UsedVars.begin(); VI != UsedVars.end(); ++VI) {
- if (Count == 20) {
- Out << ";\n";
- Count = 0;
- }
- if (Count == 0) Out << " var ";
- if (Count > 0) {
- Out << ", ";
- }
- Count++;
- Out << VI->first << " = ";
- switch (VI->second) {
- default:
- assert(false);
- case Type::PointerTyID:
- case Type::IntegerTyID:
- Out << "0";
- break;
- case Type::FloatTyID:
- // TODO Out << "Math_fround(0)";
- case Type::DoubleTyID:
- Out << "+0"; // FIXME
- break;
- }
- }
- Out << ";";
- nl(Out);
- }
-
- // Emit stack entry
- Out << " " + getAssign("sp", Type::getInt32Ty(F->getContext())) + "STACKTOP;";
-
- // Emit (relooped) code
- nl(Out) << buffer;
-
- // Ensure a final return if necessary
- Type *RT = F->getFunctionType()->getReturnType();
- if (!RT->isVoidTy()) {
- char *LastCurly = strrchr(buffer, '}');
- if (!LastCurly) LastCurly = buffer;
- char *FinalReturn = strstr(LastCurly, "return ");
- if (!FinalReturn) {
- Out << " return " + getCast("0", RT, ASM_NONSPECIFIC) + ";\n";
- }
- }
-}
-
-void JSWriter::processConstants() {
- // First, calculate the address of each constant
- for (Module::const_global_iterator I = TheModule->global_begin(),
- E = TheModule->global_end(); I != E; ++I) {
- if (I->hasInitializer()) {
- parseConstant(I->getName().str(), I->getInitializer(), true);
- }
- }
- // Second, allocate their contents
- for (Module::const_global_iterator I = TheModule->global_begin(),
- E = TheModule->global_end(); I != E; ++I) {
- if (I->hasInitializer()) {
- parseConstant(I->getName().str(), I->getInitializer(), false);
- }
- }
-}
-
-void JSWriter::printModuleBody() {
- processConstants();
-
- // Emit function bodies.
- nl(Out) << "// EMSCRIPTEN_START_FUNCTIONS"; nl(Out);
- for (Module::const_iterator I = TheModule->begin(), E = TheModule->end();
- I != E; ++I) {
- if (!I->isDeclaration()) {
- // Ensure all arguments and locals are named (we assume used values need names, which might be false if the optimizer did not run)
- unsigned Next = 1;
- for (Function::const_arg_iterator AI = I->arg_begin(), AE = I->arg_end();
- AI != AE; ++AI) {
- if (!AI->hasName() && AI->hasNUsesOrMore(1)) {
- ValueNames[AI] = "$" + utostr(Next++);
- }
- }
- for (Function::const_iterator BI = I->begin(), BE = I->end();
- BI != BE; ++BI) {
- for (BasicBlock::const_iterator II = BI->begin(), E = BI->end();
- II != E; ++II) {
- if (!II->hasName() && II->hasNUsesOrMore(1)) {
- ValueNames[II] = "$" + utostr(Next++);
- }
- }
- }
-
- // Prepare and analyze function
-
- UsedVars.clear();
- UniqueNum = 0;
- calculateNativizedVars(I);
-
- // Emit the function
-
- Out << "function _" << I->getName() << "(";
- for (Function::const_arg_iterator AI = I->arg_begin(), AE = I->arg_end();
- AI != AE; ++AI) {
- if (AI != I->arg_begin()) Out << ",";
- Out << getCppName(AI);
- }
- Out << ") {";
- nl(Out);
- for (Function::const_arg_iterator AI = I->arg_begin(), AE = I->arg_end();
- AI != AE; ++AI) {
- std::string name = getCppName(AI);
- Out << " " << name << " = " << getCast(name, AI->getType(), ASM_NONSPECIFIC) << ";";
- nl(Out);
- }
- printFunctionBody(I);
- Out << "}";
- nl(Out);
- }
- }
- Out << " function runPostSets() {\n";
- Out << " " + PostSets + "\n";
- Out << " }\n";
- PostSets = "";
- Out << "// EMSCRIPTEN_END_FUNCTIONS\n\n";
-
- assert(GlobalData32.size() == 0 && GlobalData8.size() == 0); // FIXME when we use optimal constant alignments
-
- // TODO fix commas
- Out << "/* memory initializer */ allocate([";
- printCommaSeparated(GlobalData64);
- if (GlobalData64.size() > 0 && GlobalData32.size() + GlobalData8.size() > 0) {
- Out << ",";
- }
- printCommaSeparated(GlobalData32);
- if (GlobalData32.size() > 0 && GlobalData8.size() > 0) {
- Out << ",";
- }
- printCommaSeparated(GlobalData8);
- Out << "], \"i8\", ALLOC_NONE, Runtime.GLOBAL_BASE);";
-
- // Emit metadata for emcc driver
- Out << "\n\n// EMSCRIPTEN_METADATA\n";
- Out << "{\n";
-
- Out << "\"declares\": [";
- bool first = true;
- for (Module::const_iterator I = TheModule->begin(), E = TheModule->end();
- I != E; ++I) {
- if (I->isDeclaration()) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"" + I->getName() + "\"";
- }
- }
- for (NameSet::iterator I = Declares.begin(), E = Declares.end();
- I != E; ++I) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"" + *I + "\"";
- }
- Out << "],";
-
- Out << "\"redirects\": {";
- first = true;
- for (StringMap::iterator I = Redirects.begin(), E = Redirects.end();
- I != E; ++I) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"_" << I->first << "\": \"" + I->second + "\"";
- }
- Out << "},";
-
- Out << "\"externs\": [";
- first = true;
- for (NameSet::iterator I = Externals.begin(), E = Externals.end();
- I != E; ++I) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"" + *I + "\"";
- }
- Out << "],";
-
- Out << "\"implementedFunctions\": [";
- first = true;
- for (Module::const_iterator I = TheModule->begin(), E = TheModule->end();
- I != E; ++I) {
- if (!I->isDeclaration()) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"_" << I->getName() << '"';
- }
- }
- Out << "],";
-
- Out << "\"tables\": {";
- unsigned Num = FunctionTables.size();
- for (FunctionTableMap::iterator I = FunctionTables.begin(), E = FunctionTables.end(); I != E; ++I) {
- Out << " \"" + I->first + "\": \"var FUNCTION_TABLE_" + I->first + " = [";
- FunctionTable &Table = I->second;
- // ensure power of two
- unsigned Size = 1;
- while (Size < Table.size()) Size <<= 1;
- while (Table.size() < Size) Table.push_back("0");
- for (unsigned i = 0; i < Table.size(); i++) {
- Out << Table[i];
- if (i < Table.size()-1) Out << ",";
- }
- Out << "];\"";
- if (--Num > 0) Out << ",";
- Out << "\n";
- }
- Out << "},";
-
- Out << "\"initializers\": [";
- first = true;
- for (unsigned i = 0; i < GlobalInitializers.size(); i++) {
- if (first) {
- first = false;
- } else {
- Out << ", ";
- }
- Out << "\"" + GlobalInitializers[i] + "\"";
- }
- Out << "]";
-
- Out << "\n}\n";
-}
-
-void JSWriter::parseConstant(const std::string& name, const Constant* CV, bool calculate) {
- if (isa<GlobalValue>(CV))
- return;
- //dumpv("parsing constant %s\n", name.c_str());
- // TODO: we repeat some work in both calculate and emit phases here
- // FIXME: use the proper optimal alignments
- if (const ConstantDataSequential *CDS =
- dyn_cast<ConstantDataSequential>(CV)) {
- assert(CDS->isString());
- if (calculate) {
- HeapData *GlobalData = allocateAddress(name);
- StringRef Str = CDS->getAsString();
- for (unsigned int i = 0; i < Str.size(); i++) {
- GlobalData->push_back(Str.data()[i]);
- }
- }
- } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
- APFloat APF = CFP->getValueAPF();
- if (CFP->getType() == Type::getFloatTy(CFP->getContext())) {
- if (calculate) {
- HeapData *GlobalData = allocateAddress(name);
- union flt { float f; unsigned char b[sizeof(float)]; } flt;
- flt.f = APF.convertToFloat();
- for (unsigned i = 0; i < sizeof(float); ++i) {
- GlobalData->push_back(flt.b[i]);
- }
- }
- } else if (CFP->getType() == Type::getDoubleTy(CFP->getContext())) {
- if (calculate) {
- HeapData *GlobalData = allocateAddress(name);
- union dbl { double d; unsigned char b[sizeof(double)]; } dbl;
- dbl.d = APF.convertToDouble();
- for (unsigned i = 0; i < sizeof(double); ++i) {
- GlobalData->push_back(dbl.b[i]);
- }
- }
- } else {
- assert(false);
- }
- } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
- if (calculate) {
- union { uint64_t i; unsigned char b[sizeof(uint64_t)]; } integer;
- integer.i = *CI->getValue().getRawData();
- unsigned BitWidth = 64; // CI->getValue().getBitWidth();
- assert(BitWidth == 32 || BitWidth == 64);
- HeapData *GlobalData = allocateAddress(name);
- // assuming compiler is little endian
- for (unsigned i = 0; i < BitWidth / 8; ++i) {
- GlobalData->push_back(integer.b[i]);
- }
- }
- } else if (isa<ConstantPointerNull>(CV)) {
- assert(false);
- } else if (isa<ConstantAggregateZero>(CV)) {
- if (calculate) {
- DataLayout DL(TheModule);
- unsigned Bytes = DL.getTypeStoreSize(CV->getType());
- // FIXME: assume full 64-bit alignment for now
- Bytes = memAlign(Bytes);
- HeapData *GlobalData = allocateAddress(name);
- for (unsigned i = 0; i < Bytes; ++i) {
- GlobalData->push_back(0);
- }
- // FIXME: create a zero section at the end, avoid filling meminit with zeros
- }
- } else if (isa<ConstantArray>(CV)) {
- assert(false);
- } else if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(CV)) {
- if (name == "__init_array_start") {
- // this is the global static initializer
- if (calculate) {
- unsigned Num = CS->getNumOperands();
- for (unsigned i = 0; i < Num; i++) {
- const Value* C = CS->getOperand(i);
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
- C = CE->getOperand(0); // ignore bitcasts
- }
- GlobalInitializers.push_back(getCppName(C));
- }
- }
- } else if (calculate) {
- HeapData *GlobalData = allocateAddress(name);
- DataLayout DL(TheModule);
- unsigned Bytes = DL.getTypeStoreSize(CV->getType());
- for (unsigned i = 0; i < Bytes; ++i) {
- GlobalData->push_back(0);
- }
- } else {
- // Per the PNaCl abi, this must be a packed struct of a very specific type
- // https://chromium.googlesource.com/native_client/pnacl-llvm/+/7287c45c13dc887cebe3db6abfa2f1080186bb97/lib/Transforms/NaCl/FlattenGlobals.cpp
- assert(CS->getType()->isPacked());
- // This is the only constant where we cannot just emit everything during the first phase, 'calculate', as we may refer to other globals
- unsigned Num = CS->getNumOperands();
- unsigned Offset = getRelativeGlobalAddress(name);
- unsigned OffsetStart = Offset;
- unsigned Absolute = getGlobalAddress(name);
- for (unsigned i = 0; i < Num; i++) {
- const Constant* C = CS->getOperand(i);
- if (isa<ConstantAggregateZero>(C)) {
- DataLayout DL(TheModule);
- unsigned Bytes = DL.getTypeStoreSize(C->getType());
- Offset += Bytes; // zeros, so just skip
- } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
- Value *V = CE->getOperand(0);
- unsigned Data = 0;
- if (CE->getOpcode() == Instruction::PtrToInt) {
- Data = getConstAsOffset(V, Absolute + Offset - OffsetStart);
- } else if (CE->getOpcode() == Instruction::Add) {
- V = dyn_cast<ConstantExpr>(V)->getOperand(0);
- Data = getConstAsOffset(V, Absolute + Offset - OffsetStart);
- ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(1));
- Data += *CI->getValue().getRawData();
- } else {
- dumpIR(CE);
- assert(0);
- }
- union { unsigned i; unsigned char b[sizeof(unsigned)]; } integer;
- integer.i = Data;
- assert(Offset+4 <= GlobalData64.size());
- for (unsigned i = 0; i < 4; ++i) {
- GlobalData64[Offset++] = integer.b[i];
- }
- } else if (const ConstantDataSequential *CDS = dyn_cast<ConstantDataSequential>(C)) {
- assert(CDS->isString());
- StringRef Str = CDS->getAsString();
- assert(Offset+Str.size() <= GlobalData64.size());
- for (unsigned int i = 0; i < Str.size(); i++) {
- GlobalData64[Offset++] = Str.data()[i];
- }
- } else {
- dumpIR(C);
- assert(0);
- }
- }
- }
- } else if (isa<ConstantVector>(CV)) {
- assert(false);
- } else if (isa<BlockAddress>(CV)) {
- assert(false);
- } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
- if (name == "__init_array_start") {
- // this is the global static initializer
- if (calculate) {
- Value *V = CE->getOperand(0);
- GlobalInitializers.push_back(getCppName(V));
- // is the func
- }
- } else if (name == "__fini_array_start") {
- // nothing to do
- } else {
- // a global equal to a ptrtoint of some function, so a 32-bit integer for us
- if (calculate) {
- HeapData *GlobalData = allocateAddress(name);
- for (unsigned i = 0; i < 4; ++i) {
- GlobalData->push_back(0);
- }
- } else {
- unsigned Data = 0;
- if (CE->getOpcode() == Instruction::Add) {
- Data = cast<ConstantInt>(CE->getOperand(1))->getZExtValue();
- CE = dyn_cast<ConstantExpr>(CE->getOperand(0));
- }
- assert(CE->isCast());
- Value *V = CE->getOperand(0);
- Data += getConstAsOffset(V, getGlobalAddress(name));
- union { unsigned i; unsigned char b[sizeof(unsigned)]; } integer;
- integer.i = Data;
- unsigned Offset = getRelativeGlobalAddress(name);
- assert(Offset+4 <= GlobalData64.size());
- for (unsigned i = 0; i < 4; ++i) {
- GlobalData64[Offset++] = integer.b[i];
- }
- }
- }
- } else if (isa<UndefValue>(CV)) {
- assert(false);
- } else {
- assert(false);
- }
-}
-
-// nativization
-
-void JSWriter::calculateNativizedVars(const Function *F) {
- NativizedVars.clear();
-
- for (Function::const_iterator BI = F->begin(), BE = F->end(); BI != BE; ++BI) {
- for (BasicBlock::const_iterator II = BI->begin(), E = BI->end(); II != E; ++II) {
- const Instruction *I = &*II;
- if (I->getOpcode() == Instruction::Alloca) {
- // this is on the stack. if its address is never used nor escaped, we can nativize it
- bool Fail = false;
- for (Instruction::const_use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE && !Fail; ++UI) {
- const Instruction *U = dyn_cast<Instruction>(*UI);
- if (!U) { Fail = true; break; } // not an instruction, not cool
- switch (U->getOpcode()) {
- case Instruction::Load: break; // load is cool
- case Instruction::Store: {
- if (U->getOperand(0) == I) Fail = true; // store *of* it is not cool; store *to* it is fine
- break;
- }
- default: { Fail = true; break; } // anything that is "not" "cool", is "not cool"
- }
- }
- if (!Fail) NativizedVars.insert(I);
- }
- }
- }
-}
-
-// special analyses
-
-bool JSWriter::canReloop(const Function *F) {
- return true;
-}
-
-// main entry
-
-void JSWriter::printCommaSeparated(const HeapData data) {
- for (HeapData::const_iterator I = data.begin();
- I != data.end(); ++I) {
- if (I != data.begin()) {
- Out << ",";
- }
- Out << (int)*I;
- }
-}
-
-void JSWriter::printProgram(const std::string& fname,
- const std::string& mName) {
- printModule(fname,mName);
-}
-
-void JSWriter::printModule(const std::string& fname,
- const std::string& mName) {
- printModuleBody();
-}
-
-bool JSWriter::runOnModule(Module &M) {
- TheModule = &M;
-
- setupCallHandlers();
-
- printProgram("", "");
-
- return false;
-}
-
-char JSWriter::ID = 0;
-
-//===----------------------------------------------------------------------===//
-// External Interface declaration
-//===----------------------------------------------------------------------===//
-
-bool CPPTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
- formatted_raw_ostream &o,
- CodeGenFileType FileType,
- bool DisableVerify,
- AnalysisID StartAfter,
- AnalysisID StopAfter) {
- assert(FileType == TargetMachine::CGFT_AssemblyFile);
-
- PM.add(createSimplifyAllocasPass());
- PM.add(new JSWriter(o));
-
- return false;
-}
-