diff options
author | Dan Gohman <sunfish@google.com> | 2014-02-24 08:49:19 -0800 |
---|---|---|
committer | Dan Gohman <sunfish@google.com> | 2014-02-25 11:58:56 -0800 |
commit | 338da97ed47659b9ef04f60067f84cafc93e3dd3 (patch) | |
tree | 2a80c78435712eafe02ea4afdc96c8d7713016cb /lib | |
parent | 5653eb58d0b0068f0ef341c8928aa06d1d0ea3f7 (diff) |
Support GEP and ConstantExprs directly in the JSBackend.
This patch also lays the groundwork for the single-use instruction trick to
reduce the number of temporary variables.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Target/JSBackend/CallHandlers.h | 72 | ||||
-rw-r--r-- | lib/Target/JSBackend/JSBackend.cpp | 516 | ||||
-rw-r--r-- | lib/Transforms/NaCl/ExpandI64.cpp | 55 | ||||
-rw-r--r-- | lib/Transforms/NaCl/ExpandVarArgs.cpp | 11 | ||||
-rw-r--r-- | lib/Transforms/NaCl/LowerEmExceptionsPass.cpp | 16 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PNaClABISimplify.cpp | 4 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PromoteIntegers.cpp | 10 |
7 files changed, 393 insertions, 291 deletions
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h index c70a37bc47..dae61b2054 100644 --- a/lib/Target/JSBackend/CallHandlers.h +++ b/lib/Target/JSBackend/CallHandlers.h @@ -78,7 +78,7 @@ DEF_CALL_HANDLER(__default__, { if (!NeedCasts) { text += getValueAsStr(CI->getOperand(i)); } else { - text += getValueAsCastStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT); + text += getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT); } if (i < NumArgs - 1) text += ","; } @@ -89,11 +89,11 @@ DEF_CALL_HANDLER(__default__, { if (!InstRT->isVoidTy() && ActualRT->isVoidTy()) { // the function we are calling was cast to something returning a value, but it really // does not return a value - getAssign(getJSName(CI), InstRT); // ensure the variable is defined, but do not emit it here - // it should have 0 uses, but just to be safe + getAssignIfNeeded(CI); // ensure the variable is defined, but do not emit it here + // it should have 0 uses, but just to be safe } else if (!ActualRT->isVoidTy()) { unsigned FFI_IN = FFI ? ASM_FFI_IN : 0; - text = getAssign(getJSName(CI), ActualRT) + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN); + text = getAssignIfNeeded(CI) + "(" + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN) + ")"; } return text; }) @@ -107,10 +107,10 @@ DEF_CALL_HANDLER(emscripten_preinvoke, { DEF_CALL_HANDLER(emscripten_postinvoke, { assert(InvokeState == 1 || InvokeState == 2); // normally 2, but can be 1 if the call in between was optimized out InvokeState = 0; - return getAssign(getJSName(CI), CI->getType()) + "__THREW__; __THREW__ = 0"; + return getAssign(CI) + "__THREW__; __THREW__ = 0"; }) DEF_CALL_HANDLER(emscripten_landingpad, { - std::string Ret = getAssign(getJSName(CI), CI->getType()) + "___cxa_find_matching_catch(-1,-1"; + std::string Ret = getAssign(CI) + "___cxa_find_matching_catch(-1,-1"; unsigned Num = getNumArgOperands(CI); for (unsigned i = 1; i < Num-1; i++) { // ignore personality and cleanup XXX - we probably should not be doing that! Ret += ","; @@ -126,7 +126,7 @@ DEF_CALL_HANDLER(emscripten_resume, { // setjmp support DEF_CALL_HANDLER(emscripten_prep_setjmp, { - return getAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "STACKTOP; STACKTOP=(STACKTOP+168)|0;" + // XXX FIXME + return getAdHocAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "STACKTOP; STACKTOP=(STACKTOP+168)|0;" + // XXX FIXME "HEAP32[_setjmpTable>>2]=0"; }) DEF_CALL_HANDLER(emscripten_setjmp, { @@ -141,7 +141,7 @@ DEF_CALL_HANDLER(emscripten_longjmp, { DEF_CALL_HANDLER(emscripten_check_longjmp, { std::string Threw = getValueAsStr(CI->getOperand(0)); std::string Target = getJSName(CI); - std::string Assign = getAssign(Target, CI->getType()); + std::string Assign = getAssign(CI); return "if (((" + Threw + "|0) != 0) & ((threwValue|0) != 0)) { " + Assign + "_testSetjmp(HEAP32[" + Threw + ">>2]|0, _setjmpTable)|0; " + "if ((" + Target + "|0) == 0) { _longjmp(" + Threw + "|0, threwValue|0); } " + // rethrow @@ -150,13 +150,13 @@ DEF_CALL_HANDLER(emscripten_check_longjmp, { }) DEF_CALL_HANDLER(emscripten_get_longjmp_result, { std::string Threw = getValueAsStr(CI->getOperand(0)); - return getAssign(getJSName(CI), CI->getType()) + "tempRet0"; + return getAssign(CI) + "tempRet0"; }) // i64 support DEF_CALL_HANDLER(getHigh32, { - return getAssign(getJSName(CI), CI->getType()) + "tempRet0"; + return getAssign(CI) + "tempRet0"; }) DEF_CALL_HANDLER(setHigh32, { return "tempRet0 = " + getValueAsStr(CI->getOperand(0)); @@ -166,20 +166,20 @@ DEF_CALL_HANDLER(setHigh32, { DEF_CALL_HANDLER(low, { \ std::string Input = getValueAsStr(CI->getOperand(0)); \ if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Input; \ - return getAssign(getJSName(CI), CI->getType()) + "(~~" + Input + ")>>>0"; \ + return getAssign(CI) + "(~~" + Input + ")>>>0"; \ }) \ DEF_CALL_HANDLER(high, { \ std::string Input = getValueAsStr(CI->getOperand(0)); \ if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Input; \ - return getAssign(getJSName(CI), CI->getType()) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295) | 0) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0"; \ + return getAssign(CI) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295) | 0) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0"; \ }) TO_I(FtoILow, FtoIHigh); TO_I(DtoILow, DtoIHigh); DEF_CALL_HANDLER(BDtoILow, { - return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";" + getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr>>2]|0"; + return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";" + getAssign(CI) + "HEAP32[tempDoublePtr>>2]|0"; }) DEF_CALL_HANDLER(BDtoIHigh, { - return getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr+4>>2]|0"; + return getAssign(CI) + "HEAP32[tempDoublePtr+4>>2]|0"; }) DEF_CALL_HANDLER(SItoF, { std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + @@ -187,7 +187,7 @@ DEF_CALL_HANDLER(SItoF, { if (PreciseF32 && CI->getType()->isFloatTy()) { Ret = "Math_fround(" + Ret + ")"; } - return getAssign(getJSName(CI), CI->getType()) + Ret; + return getAssign(CI) + Ret; }) DEF_CALL_HANDLER(UItoF, { std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + @@ -195,20 +195,20 @@ DEF_CALL_HANDLER(UItoF, { if (PreciseF32 && CI->getType()->isFloatTy()) { Ret = "Math_fround(" + Ret + ")"; } - return getAssign(getJSName(CI), CI->getType()) + Ret; + return getAssign(CI) + Ret; }) DEF_CALL_HANDLER(SItoD, { - return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + + return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))"; }) DEF_CALL_HANDLER(UItoD, { - return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + + return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " + "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))"; }) DEF_CALL_HANDLER(BItoD, { return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getOperand(0)) + ";" + "HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getOperand(1)) + ";" + - getAssign(getJSName(CI), CI->getType()) + "+HEAPF64[tempDoublePtr>>3]"; + getAssign(CI) + "+HEAPF64[tempDoublePtr>>3]"; }) // misc @@ -323,7 +323,7 @@ DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, { }) DEF_CALL_HANDLER(llvm_expect_i32, { - return getAssign(getJSName(CI), CI->getType()) + getValueAsStr(CI->getOperand(0)); + return getAssign(CI) + getValueAsStr(CI->getOperand(0)); }) DEF_CALL_HANDLER(llvm_dbg_declare, { @@ -342,6 +342,18 @@ DEF_CALL_HANDLER(llvm_lifetime_end, { return ""; }) +DEF_CALL_HANDLER(llvm_invariant_start, { + return ""; +}) + +DEF_CALL_HANDLER(llvm_invariant_end, { + return ""; +}) + +DEF_CALL_HANDLER(llvm_prefetch, { + return ""; +}) + DEF_CALL_HANDLER(bitshift64Lshr, { return CH___default__(CI, "_bitshift64Lshr", 3); }) @@ -364,7 +376,7 @@ DEF_CALL_HANDLER(llvm_cttz_i32, { // vector ops DEF_CALL_HANDLER(emscripten_float32x4_signmask, { - return getAssign(getJSName(CI), CI->getType()) + "SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + ").signMask"; + return getAssign(CI) + "SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + ").signMask"; }) DEF_CALL_HANDLER(emscripten_float32x4_min, { return CH___default__(CI, "SIMD.float32x4.min"); @@ -391,19 +403,19 @@ DEF_CALL_HANDLER(emscripten_float32x4_greaterThan, { return CH___default__(CI, "SIMD.float32x4.greaterThan"); }) DEF_CALL_HANDLER(emscripten_float32x4_and, { - return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(" + + return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))"; }) DEF_CALL_HANDLER(emscripten_float32x4_andNot, { - return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(" + + return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + ")),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))"; }) DEF_CALL_HANDLER(emscripten_float32x4_or, { - return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(" + + return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))"; }) DEF_CALL_HANDLER(emscripten_float32x4_xor, { - return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(" + + return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))"; }) DEF_CALL_HANDLER(emscripten_int32x4_bitsToFloat32x4, { @@ -712,6 +724,9 @@ void setupCallHandlers() { SETUP_CALL_HANDLER(llvm_dbg_value); SETUP_CALL_HANDLER(llvm_lifetime_start); SETUP_CALL_HANDLER(llvm_lifetime_end); + SETUP_CALL_HANDLER(llvm_invariant_start); + SETUP_CALL_HANDLER(llvm_invariant_end); + SETUP_CALL_HANDLER(llvm_prefetch); SETUP_CALL_HANDLER(bitshift64Lshr); SETUP_CALL_HANDLER(bitshift64Ashr); SETUP_CALL_HANDLER(bitshift64Shl); @@ -977,7 +992,12 @@ void setupCallHandlers() { std::string handleCall(const Instruction *CI) { const Value *CV = getActuallyCalledValue(CI); assert(!isa<InlineAsm>(CV) && "asm() not supported, use EM_ASM() (see emscripten.h)"); - const std::string &Name = getJSName(CV); + + // Get the name to call this function by. If it's a direct call, meaning + // which know which Function we're calling, avoid calling getValueAsStr, as + // we don't need to use a function index. + const std::string &Name = isa<Function>(CV) ? getJSName(CV) : getValueAsStr(CV); + unsigned NumArgs = getNumArgOperands(CI); CallHandlerMap::iterator CH = CallHandlers->find("___default__"); if (isa<Function>(CV)) { diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp index a9d1aac129..a0c199e7db 100644 --- a/lib/Target/JSBackend/JSBackend.cpp +++ b/lib/Target/JSBackend/JSBackend.cpp @@ -15,8 +15,11 @@ //===----------------------------------------------------------------------===// #include "JSTargetMachine.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" @@ -24,7 +27,9 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -34,6 +39,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/DebugInfo.h" #include <algorithm> @@ -341,28 +347,6 @@ namespace { return false; } - std::string getPtrAsStr(const Value* Ptr) { - Ptr = Ptr->stripPointerCasts(); - if (isa<const ConstantPointerNull>(Ptr) || isa<UndefValue>(Ptr)) return "0"; - if (const Function *F = dyn_cast<Function>(Ptr)) { - return utostr(getFunctionIndex(F)); - } else if (const Constant *CV = dyn_cast<Constant>(Ptr)) { - if (const BlockAddress *BA = dyn_cast<const BlockAddress>(Ptr)) { - return utostr(getBlockAddress(BA)); - } - 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); - } - } - void checkVectorType(Type *T) { VectorType *VT = cast<VectorType>(T); assert(VT->getElementType()->getPrimitiveSizeInBits() == 32); @@ -387,7 +371,9 @@ namespace { void printType(Type* Ty); void printTypes(const Module* M); - std::string getAssign(const StringRef &, Type *); + std::string getAdHocAssign(const StringRef &, Type *); + std::string getAssign(const Instruction *I); + std::string getAssignIfNeeded(const Value *V); std::string getCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED); std::string getParenCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED); std::string getDoubleToInt(const StringRef &); @@ -397,8 +383,9 @@ namespace { void addBlock(const BasicBlock *BB, Relooper& R, LLVMToRelooperMap& LLVMToRelooper); void printFunctionBody(const Function *F); - bool generateSIMDInstruction(const std::string &iName, const Instruction *I, raw_string_ostream& Code); - void generateInstruction(const Instruction *I, raw_string_ostream& Code); + bool generateSIMDExpression(const User *I, raw_string_ostream& Code); + void generateExpression(const User *I, raw_string_ostream& Code); + std::string getOpName(const Value*); void processConstants(); @@ -522,7 +509,7 @@ std::string JSWriter::getPhiCode(const BasicBlock *From, const BasicBlock *To) { if (index < 0) continue; // we found it const std::string &name = getJSName(P); - assigns[name] = getAssign(name, P->getType()); + assigns[name] = getAssign(P); const Value *V = P->getIncomingValue(index); values[name] = V; std::string vname = getValueAsStr(V); @@ -550,7 +537,7 @@ std::string JSWriter::getPhiCode(const BasicBlock *From, const BasicBlock *To) { // break a cycle std::string depString = dep->second; std::string temp = curr + "$phi"; - pre += getAssign(temp, V->getType()) + CV + ';'; + pre += getAdHocAssign(temp, V->getType()) + CV + ';'; CV = temp; deps.erase(curr); undeps.erase(depString); @@ -584,16 +571,26 @@ const std::string &JSWriter::getJSName(const Value* val) { return ValueNames[val] = name; } -std::string JSWriter::getAssign(const StringRef &s, Type *t) { +std::string JSWriter::getAdHocAssign(const StringRef &s, Type *t) { UsedVars[s] = t->getTypeID(); return (s + " = ").str(); } +std::string JSWriter::getAssign(const Instruction *I) { + return getAdHocAssign(getJSName(I), I->getType()); +} + +std::string JSWriter::getAssignIfNeeded(const Value *V) { + if (const Instruction *I = dyn_cast<Instruction>(V)) + return getAssign(I); + return std::string(); +} + std::string JSWriter::getCast(const StringRef &s, Type *t, AsmCast sign) { switch (t->getTypeID()) { default: { // some types we cannot cast, like vectors - ignore - if (!t->isVectorTy()) assert(false && "Unsupported type"); + if (!t->isVectorTy()) { errs() << *t << "\n"; assert(false && "Unsupported type");} } case Type::FloatTyID: { if (PreciseF32 && !(sign & ASM_FFI_OUT)) { @@ -656,8 +653,8 @@ std::string JSWriter::getIMul(const Value *V1, const Value *V2) { } std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) { - std::string Assign = getAssign(getJSName(I), I->getType()); - unsigned Bytes = T->getPrimitiveSizeInBits()/8; + std::string Assign = getAssign(I); + unsigned Bytes = DL->getTypeAllocSize(T); std::string text; if (Bytes <= Alignment || Alignment == 0) { text = Assign + getPtrLoad(P); @@ -672,7 +669,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns emitDebugInfo(errs(), I); errs() << "\n"; } - std::string PS = getOpName(P); + std::string PS = getValueAsStr(P); switch (Bytes) { case 8: { switch (Alignment) { @@ -767,7 +764,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co emitDebugInfo(errs(), I); errs() << "\n"; } - std::string PS = getOpName(P); + std::string PS = getValueAsStr(P); switch (Bytes) { case 8: { text = "HEAPF64[tempDoublePtr>>3]=" + VS + ';'; @@ -894,121 +891,108 @@ std::string JSWriter::getPtrUse(const Value* Ptr) { case 1: return "HEAP8[" + utostr(Addr) + "]"; } } else { - return getHeapAccess(getPtrAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy()); + return getHeapAccess(getValueAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy()); } } -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) { +static inline std::string ftostr(const ConstantFP *CFP) { const APFloat &flt = CFP->getValueAPF(); + + // Emscripten has its own spellings for infinity and NaN. if (flt.getCategory() == APFloat::fcInfinity) return flt.isNegative() ? "-inf" : "inf"; else if (flt.getCategory() == APFloat::fcNaN) return "nan"; - 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); - if (len&1) { - // uneven, need to add a 0 to make it be entire bytes - temp = std::string("0") + raw; - raw = temp.c_str(); - len++; - } - 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; + // Request 21 digits, aka DECIMAL_DIG, to avoid rounding errors. + SmallString<29> Str; + flt.toString(Str, 21); + + // asm.js considers literals to be floating-point literals when they contain a + // dot, however our output may be processed by UglifyJS, which doesn't + // currently preserve dots in all cases. Mark floating-point literals with + // unary plus to force them to floating-point. + if (APFloat(flt).roundToIntegral(APFloat::rmNearestTiesToEven) == APFloat::opOK) { + return '+' + Str.str().str(); + } + + return Str.str().str(); } 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); - if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) { - S = "Math_fround(+" + S + ")"; // FIXME: can avoid "+" for small enough constants - } else if (S[0] != '+') { - S = '+' + S; - } - return S; - } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) { - if (sign != ASM_UNSIGNED && CI->getValue().getBitWidth() == 1) { - sign = ASM_UNSIGNED; // bools must always be unsigned: either 0 or 1 - } - return CI->getValue().toString(10, sign != ASM_UNSIGNED); - } else if (isa<UndefValue>(CV)) { - return CV->getType()->isIntegerTy() || CV->getType()->isPointerTy() ? "0" : getCast("0", CV->getType()); - } else if (isa<ConstantAggregateZero>(CV)) { - if (VectorType *VT = dyn_cast<VectorType>(CV->getType())) { - if (VT->getElementType()->isIntegerTy()) { - return "int32x4.splat(0)"; - } else { - return "float32x4.splat(0)"; - } + if (isa<ConstantPointerNull>(CV)) return "0"; + + if (const Function *F = dyn_cast<Function>(CV)) { + return utostr(getFunctionIndex(F)); + } + + if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { + if (GV->isDeclaration()) { + std::string Name = getOpName(GV); + Externals.insert(Name); + return Name; + } + return utostr(getGlobalAddress(GV->getName().str())); + } + + if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) { + std::string S = ftostr(CFP); + if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) { + S = "Math_fround(" + S + ")"; + } + return S; + } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) { + if (sign != ASM_UNSIGNED && CI->getValue().getBitWidth() == 1) { + sign = ASM_UNSIGNED; // bools must always be unsigned: either 0 or 1 + } + return CI->getValue().toString(10, sign != ASM_UNSIGNED); + } else if (isa<UndefValue>(CV)) { + std::string S = CV->getType()->isFloatingPointTy() ? "+0" : "0"; // XXX refactor this + if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) { + S = "Math_fround(" + S + ")"; + } + return S; + } else if (isa<ConstantAggregateZero>(CV)) { + if (VectorType *VT = dyn_cast<VectorType>(CV->getType())) { + if (VT->getElementType()->isIntegerTy()) { + return "int32x4.splat(0)"; } else { - // something like [0 x i8*] zeroinitializer, which clang can emit for landingpads - return "0"; + return "float32x4.splat(0)"; } - } else if (const ConstantDataVector *DV = dyn_cast<ConstantDataVector>(CV)) { - const VectorType *VT = cast<VectorType>(CV->getType()); - if (VT->getElementType()->isIntegerTy()) { - return "int32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + + } else { + // something like [0 x i8*] zeroinitializer, which clang can emit for landingpads + return "0"; + } + } else if (const ConstantDataVector *DV = dyn_cast<ConstantDataVector>(CV)) { + const VectorType *VT = cast<VectorType>(CV->getType()); + if (VT->getElementType()->isIntegerTy()) { + return "int32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + + getConstant(DV->getElementAsConstant(1)) + ',' + + getConstant(DV->getElementAsConstant(2)) + ',' + + getConstant(DV->getElementAsConstant(3)) + ')'; + } else { + return "float32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + getConstant(DV->getElementAsConstant(1)) + ',' + getConstant(DV->getElementAsConstant(2)) + ',' + getConstant(DV->getElementAsConstant(3)) + ')'; - } else { - return "float32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' + - getConstant(DV->getElementAsConstant(1)) + ',' + - getConstant(DV->getElementAsConstant(2)) + ',' + - getConstant(DV->getElementAsConstant(3)) + ')'; - } - } else if (const ConstantArray *CA = dyn_cast<const ConstantArray>(CV)) { - // handle things like [i8* bitcast (<{ i32, i32, i32 }>* @_ZTISt9bad_alloc to i8*)] which clang can emit for landingpads - assert(CA->getNumOperands() == 1); - CV = CA->getOperand(0); - const ConstantExpr *CE = cast<ConstantExpr>(CV); - CV = CE->getOperand(0); // ignore bitcast - return getPtrAsStr(CV); - } else { - CV->dump(); - llvm_unreachable("Unsupported constant kind"); } + } else if (const ConstantArray *CA = dyn_cast<const ConstantArray>(CV)) { + // handle things like [i8* bitcast (<{ i32, i32, i32 }>* @_ZTISt9bad_alloc to i8*)] which clang can emit for landingpads + assert(CA->getNumOperands() == 1); + CV = CA->getOperand(0); + const ConstantExpr *CE = cast<ConstantExpr>(CV); + CV = CE->getOperand(0); // ignore bitcast + return getConstant(CV); + } else if (const BlockAddress *BA = dyn_cast<const BlockAddress>(CV)) { + return utostr(getBlockAddress(BA)); + } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) { + std::string Code; + raw_string_ostream CodeStream(Code); + CodeStream << '('; + generateExpression(CE, CodeStream); + CodeStream << ')'; + return CodeStream.str(); + } else { + CV->dump(); + llvm_unreachable("Unsupported constant kind"); } } @@ -1021,10 +1005,10 @@ std::string JSWriter::getValueAsStr(const Value* V, AsmCast sign) { } std::string JSWriter::getValueAsCastStr(const Value* V, AsmCast sign) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV, sign); + if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) { + return getConstant(cast<Constant>(V), sign); } else { - return getCast(getJSName(V), V->getType(), sign); + return getCast(getValueAsStr(V), V->getType(), sign); } } @@ -1032,39 +1016,38 @@ std::string JSWriter::getValueAsParenStr(const Value* V) { if (const Constant *CV = dyn_cast<Constant>(V)) { return getConstant(CV); } else { - return "(" + getJSName(V) + ")"; + return "(" + getValueAsStr(V) + ")"; } } std::string JSWriter::getValueAsCastParenStr(const Value* V, AsmCast sign) { - if (const Constant *CV = dyn_cast<Constant>(V)) { - return getConstant(CV, sign); + if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) { + return getConstant(cast<Constant>(V), sign); } else { - return "(" + getCast(getJSName(V), V->getType(), sign) + ")"; + return "(" + getCast(getValueAsStr(V), V->getType(), sign) + ")"; } } -bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instruction *I, raw_string_ostream& Code) { +bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) { VectorType *VT; if ((VT = dyn_cast<VectorType>(I->getType()))) { // vector-producing instructions checkVectorType(VT); - Code << getAssign(iName, I->getType()); - - switch (I->getOpcode()) { + switch (Operator::getOpcode(I)) { default: I->dump(); error("invalid vector instr"); break; - case Instruction::FAdd: Code << "SIMD.float32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::FMul: Code << "SIMD.float32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::FDiv: Code << "SIMD.float32x4.div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Add: Code << "SIMD.int32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Sub: Code << "SIMD.int32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Mul: Code << "SIMD.int32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::And: Code << "SIMD.int32x4.and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Or: Code << "SIMD.int32x4.or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; - case Instruction::Xor: Code << "SIMD.int32x4.xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FAdd: Code << getAssignIfNeeded(I) << "SIMD.float32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FMul: Code << getAssignIfNeeded(I) << "SIMD.float32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::FDiv: Code << getAssignIfNeeded(I) << "SIMD.float32x4.div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Add: Code << getAssignIfNeeded(I) << "SIMD.int32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Sub: Code << getAssignIfNeeded(I) << "SIMD.int32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Mul: Code << getAssignIfNeeded(I) << "SIMD.int32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::And: Code << getAssignIfNeeded(I) << "SIMD.int32x4.and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Or: Code << getAssignIfNeeded(I) << "SIMD.int32x4.or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; + case Instruction::Xor: Code << getAssignIfNeeded(I) << "SIMD.int32x4.xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break; case Instruction::FSub: // LLVM represents an fneg(x) as -0.0 - x. + Code << getAssignIfNeeded(I); if (BinaryOperator::isFNeg(I)) { Code << "SIMD.float32x4.neg(" << getValueAsStr(BinaryOperator::getFNegArgument(I)) << ")"; } else { @@ -1072,6 +1055,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi } break; case Instruction::BitCast: { + Code << getAssignIfNeeded(I); if (cast<VectorType>(I->getType())->getElementType()->isIntegerTy()) { Code << "SIMD.float32x4.bitsToInt32x4(" << getValueAsStr(I->getOperand(0)) << ')'; } else { @@ -1080,7 +1064,10 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi break; } case Instruction::Load: { - std::string PS = getOpName(I->getOperand(0)); + const LoadInst *LI = cast<LoadInst>(I); + const Value *P = LI->getPointerOperand(); + std::string PS = getValueAsStr(P); + Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { Code << "int32x4(HEAPU32[" << PS << ">>2],HEAPU32[" << PS << "+4>>2],HEAPU32[" << PS << "+8>>2],HEAPU32[" << PS << "+12>>2])"; } else { @@ -1093,6 +1080,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi const ConstantInt *IndexInt = cast<const ConstantInt>(III->getOperand(2)); unsigned Index = IndexInt->getZExtValue(); assert(Index <= 3); + Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { Code << "SIMD.int32x4.with"; } else { @@ -1103,6 +1091,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi break; } case Instruction::ShuffleVector: { + Code << getAssignIfNeeded(I); if (VT->getElementType()->isIntegerTy()) { Code << "int32x4("; } else { @@ -1130,24 +1119,27 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi return true; } else { // vector-consuming instructions - if (I->getOpcode() == Instruction::Store && (VT = dyn_cast<VectorType>(I->getOperand(0)->getType())) && VT->isVectorTy()) { + if (Operator::getOpcode(I) == Instruction::Store && (VT = dyn_cast<VectorType>(I->getOperand(0)->getType())) && VT->isVectorTy()) { checkVectorType(VT); - std::string PS = getOpName(I->getOperand(1)); - std::string VS = getValueAsStr(I->getOperand(0)); + const StoreInst *SI = cast<StoreInst>(I); + const Value *P = SI->getPointerOperand(); + std::string PS = getOpName(P); + std::string VS = getValueAsStr(SI->getValueOperand()); + Code << getAdHocAssign(PS, P->getType()) << getValueAsStr(P) << ';'; if (VT->getElementType()->isIntegerTy()) { Code << "HEAPU32[" << PS << ">>2]=" << VS << ".x;HEAPU32[" << PS << "+4>>2]=" << VS << ".y;HEAPU32[" << PS << "+8>>2]=" << VS << ".z;HEAPU32[" << PS << "+12>>2]=" << VS << ".w"; } else { Code << "HEAPF32[" << PS << ">>2]=" << VS << ".x;HEAPF32[" << PS << "+4>>2]=" << VS << ".y;HEAPF32[" << PS << "+8>>2]=" << VS << ".z;HEAPF32[" << PS << "+12>>2]=" << VS << ".w"; } return true; - } else if (I->getOpcode() == Instruction::ExtractElement) { + } else if (Operator::getOpcode(I) == Instruction::ExtractElement) { const ExtractElementInst *EEI = cast<ExtractElementInst>(I); VT = cast<VectorType>(EEI->getVectorOperand()->getType()); checkVectorType(VT); const ConstantInt *IndexInt = cast<const ConstantInt>(EEI->getIndexOperand()); unsigned Index = IndexInt->getZExtValue(); assert(Index <= 3); - Code << getAssign(iName, I->getType()); + Code << getAssignIfNeeded(I); Code << getValueAsStr(EEI->getVectorOperand()) << '.' << simdLane[Index]; return true; } @@ -1159,17 +1151,15 @@ static uint64_t LSBMask(unsigned numBits) { return numBits >= 64 ? 0xFFFFFFFFFFFFFFFFULL : (1ULL << numBits) - 1; } -// generateInstruction - This member is called for each Instruction in a function. -void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Code) { - const std::string &iName(getJSName(I)); - +// Generate code for and operator, either an Instruction or a ConstantExpr. +void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) { Type *T = I->getType(); if (T->isIntegerTy() && T->getIntegerBitWidth() > 32) { errs() << *I << "\n"; report_fatal_error("legalization problem"); } - if (!generateSIMDInstruction(iName, I, Code)) switch (I->getOpcode()) { + if (!generateSIMDExpression(I, Code)) switch (Operator::getOpcode(I)) { default: { I->dump(); error("Invalid instruction"); @@ -1180,16 +1170,14 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod const Value *RV = ret->getReturnValue(); Code << "STACKTOP = sp;"; Code << "return"; - if (RV == NULL) { - Code << ";"; - } else { - Code << " " << getValueAsCastStr(RV, ASM_NONSPECIFIC) << ";"; + if (RV != NULL) { + Code << " " << getValueAsCastParenStr(RV, ASM_NONSPECIFIC); } break; } case Instruction::Br: case Instruction::IndirectBr: - case Instruction::Switch: break; // handled while relooping + case Instruction::Switch: return; // handled while relooping case Instruc |