| Index: lib/Target/JSBackend/CallHandlers.h
|
| diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h
|
| deleted file mode 100644
|
| index c657aa51f95f5630b1091b31447b73c0342fe512..0000000000000000000000000000000000000000
|
| --- a/lib/Target/JSBackend/CallHandlers.h
|
| +++ /dev/null
|
| @@ -1,757 +0,0 @@
|
| -// Call handlers: flexible map of call targets to arbitrary handling code
|
| -//
|
| -// Each handler needs DEF_CALL_HANDLER and SETUP_CALL_HANDLER
|
| -//
|
| -
|
| -typedef std::string (JSWriter::*CallHandler)(const Instruction*, std::string Name, int NumArgs);
|
| -typedef std::map<std::string, CallHandler> CallHandlerMap;
|
| -CallHandlerMap CallHandlers;
|
| -
|
| -// Definitions
|
| -
|
| -unsigned getNumArgOperands(const Instruction *I) {
|
| - return ImmutableCallSite(I).arg_size();
|
| -}
|
| -
|
| -const Value *getActuallyCalledValue(const Instruction *I) {
|
| - const Value *CV = ImmutableCallSite(I).getCalledValue();
|
| -
|
| - // if the called value is a bitcast of a function, then we just call it directly, properly
|
| - // for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
|
| - // it to the proper form right before the call. this both causes an unnecessary indirect
|
| - // call, and it is done with the wrong type. TODO: don't even put it into the function table
|
| - if (const Function *F = dyn_cast<const Function>(CV->stripPointerCasts())) {
|
| - CV = F;
|
| - }
|
| - return CV;
|
| -}
|
| -
|
| -// We can't and shouldn't try to invoke an LLVM intrinsic which we overload with a call hander -
|
| -// it would end up in a function table, which makes no sense.
|
| -bool canInvoke(const Value *V) {
|
| - const Function *F = dyn_cast<const Function>(V);
|
| - if (F && F->isDeclaration() && F->isIntrinsic()) {
|
| - auto Intrin = F->getIntrinsicID();
|
| - if (Intrin == Intrinsic::memcpy || Intrin == Intrinsic::memset) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -#define DEF_CALL_HANDLER(Ident, Code) \
|
| - std::string CH_##Ident(const Instruction *CI, std::string Name, int NumArgs=-1) { Code }
|
| -
|
| -DEF_CALL_HANDLER(__default__, {
|
| - if (!CI) return ""; // we are just called from a handler that was called from getFunctionIndex, only to ensure the handler was run at least once
|
| - const Value *CV = getActuallyCalledValue(CI);
|
| - bool NeedCasts = true;
|
| - FunctionType *FT;
|
| - bool Invoke = false;
|
| - if (InvokeState == 1) {
|
| - InvokeState = 2;
|
| - Invoke = canInvoke(CV);
|
| - }
|
| - std::string Sig;
|
| - const Function *F = dyn_cast<const Function>(CV);
|
| - if (F) {
|
| - NeedCasts = F->isDeclaration(); // if ffi call, need casts
|
| - FT = F->getFunctionType();
|
| - } else {
|
| - FT = dyn_cast<FunctionType>(dyn_cast<PointerType>(CV->getType())->getElementType());
|
| - if (isAbsolute(CV->stripPointerCasts())) {
|
| - Name = "abort /* segfault, call an absolute addr */ ";
|
| - } else {
|
| - // function pointer call
|
| - ensureFunctionTable(FT);
|
| - if (!Invoke) {
|
| - Sig = getFunctionSignature(FT, &Name);
|
| - Name = std::string("FUNCTION_TABLE_") + Sig + "[" + Name + " & #FM_" + Sig + "#]";
|
| - NeedCasts = false; // function table call, so stays in asm module
|
| - }
|
| - }
|
| - }
|
| -
|
| - bool ForcedNumArgs = NumArgs != -1;
|
| - if (!ForcedNumArgs) NumArgs = getNumArgOperands(CI);
|
| -
|
| - if (!FT->isVarArg() && !ForcedNumArgs) {
|
| - int TypeNumArgs = FT->getNumParams();
|
| - if (TypeNumArgs != NumArgs) {
|
| - if (EmscriptenAssertions) prettyWarning() << "unexpected number of arguments " << utostr(NumArgs) << " in call to '" << F->getName() << "', should be " << utostr(TypeNumArgs) << "\n";
|
| - if (NumArgs > TypeNumArgs) NumArgs = TypeNumArgs; // lop off the extra params that will not be used and just break validation
|
| - }
|
| - if (EmscriptenAssertions) {
|
| - for (int i = 0; i < std::min(TypeNumArgs, NumArgs); i++) {
|
| - Type *TypeType = FT->getParamType(i);
|
| - Type *ActualType = CI->getOperand(i)->getType();
|
| - if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
|
| - prettyWarning() << "unexpected argument type " << *ActualType << " at index " << utostr(i) << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
|
| - }
|
| - }
|
| - }
|
| - }
|
| - if (EmscriptenAssertions) {
|
| - Type *TypeType = FT->getReturnType();
|
| - Type *ActualType = CI->getType();
|
| - if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
|
| - prettyWarning() << "unexpected return type " << *ActualType << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
|
| - }
|
| - }
|
| -
|
| - if (Invoke) {
|
| - Sig = getFunctionSignature(FT, &Name);
|
| - Name = "invoke_" + Sig;
|
| - NeedCasts = true;
|
| - }
|
| - std::string text = Name + "(";
|
| - if (Invoke) {
|
| - // add first param
|
| - if (F) {
|
| - text += utostr(getFunctionIndex(F)); // convert to function pointer
|
| - } else {
|
| - text += getValueAsCastStr(CV); // already a function pointer
|
| - }
|
| - if (NumArgs > 0) text += ",";
|
| - }
|
| - // this is an ffi call if we need casts, and it is not a special Math_ builtin
|
| - bool FFI = NeedCasts;
|
| - if (FFI && Name.find("Math_") == 0) {
|
| - if (Name == "Math_ceil" || Name == "Math_floor" || Name == "Math_min" || Name == "Math_max" || Name == "Math_sqrt" || Name == "Math_abs") {
|
| - // This special Math builtin is optimizable with all types, including floats, so can treat it as non-ffi
|
| - FFI = false;
|
| - }
|
| - }
|
| - unsigned FFI_OUT = FFI ? ASM_FFI_OUT : 0;
|
| - for (int i = 0; i < NumArgs; i++) {
|
| - if (!NeedCasts) {
|
| - text += getValueAsStr(CI->getOperand(i));
|
| - } else {
|
| - text += getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT);
|
| - }
|
| - if (i < NumArgs - 1) text += ",";
|
| - }
|
| - text += ")";
|
| - // handle return value
|
| - Type *InstRT = CI->getType();
|
| - Type *ActualRT = FT->getReturnType();
|
| - 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
|
| - 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 = getAssignIfNeeded(CI) + "(" + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN) + ")";
|
| - }
|
| - return text;
|
| -})
|
| -
|
| -// exceptions support
|
| -DEF_CALL_HANDLER(emscripten_preinvoke, {
|
| - // InvokeState is normally 0 here, but might be otherwise if a block was split apart TODO: add a function attribute for this
|
| - InvokeState = 1;
|
| - return "__THREW__ = 0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_postinvoke, {
|
| - // InvokeState is normally 2 here, but can be 1 if the call in between was optimized out, or 0 if a block was split apart
|
| - InvokeState = 0;
|
| - return getAssign(CI) + "__THREW__; __THREW__ = 0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_landingpad, {
|
| - std::string Ret = getAssign(CI) + "___cxa_find_matching_catch(";
|
| - unsigned Num = getNumArgOperands(CI);
|
| - for (unsigned i = 1; i < Num-1; i++) { // ignore personality and cleanup XXX - we probably should not be doing that!
|
| - if (i > 1) Ret += ",";
|
| - Ret += getValueAsCastStr(CI->getOperand(i));
|
| - }
|
| - Ret += ")|0";
|
| - return Ret;
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_resume, {
|
| - return "___resumeException(" + getValueAsCastStr(CI->getOperand(0)) + ")";
|
| -})
|
| -
|
| -// setjmp support
|
| -
|
| -DEF_CALL_HANDLER(emscripten_prep_setjmp, {
|
| - return getAdHocAssign("_setjmpTableSize", Type::getInt32Ty(CI->getContext())) + "4;" +
|
| - getAdHocAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "_malloc(40) | 0;" +
|
| - "HEAP32[_setjmpTable>>2]=0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_cleanup_setjmp, {
|
| - return "_free(_setjmpTable|0)";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_setjmp, {
|
| - // env, label, table
|
| - Declares.insert("saveSetjmp");
|
| - return "_setjmpTable = _saveSetjmp(" + getValueAsStr(CI->getOperand(0)) + "," + getValueAsStr(CI->getOperand(1)) + ",_setjmpTable|0,_setjmpTableSize|0)|0;_setjmpTableSize = tempRet0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_longjmp, {
|
| - Declares.insert("longjmp");
|
| - return CH___default__(CI, "_longjmp");
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_check_longjmp, {
|
| - std::string Threw = getValueAsStr(CI->getOperand(0));
|
| - std::string Target = getJSName(CI);
|
| - std::string Assign = getAssign(CI);
|
| - return "if (((" + Threw + "|0) != 0) & ((threwValue|0) != 0)) { " +
|
| - Assign + "_testSetjmp(HEAP32[" + Threw + ">>2]|0, _setjmpTable|0, _setjmpTableSize|0)|0; " +
|
| - "if ((" + Target + "|0) == 0) { _longjmp(" + Threw + "|0, threwValue|0); } " + // rethrow
|
| - "tempRet0 = threwValue; " +
|
| - "} else { " + Assign + "-1; }";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_get_longjmp_result, {
|
| - std::string Threw = getValueAsStr(CI->getOperand(0));
|
| - return getAssign(CI) + "tempRet0";
|
| -})
|
| -
|
| -// supporting async functions, see `<emscripten>/src/library_async.js` for detail.
|
| -DEF_CALL_HANDLER(emscripten_alloc_async_context, {
|
| - // insert sp as the 2nd parameter
|
| - return getAssign(CI) + "_emscripten_alloc_async_context(" + getValueAsStr(CI->getOperand(0)) + ",sp)|0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_check_async, {
|
| - return getAssign(CI) + "___async";
|
| -})
|
| -// prevent unwinding the stack
|
| -// preserve the return value of the return inst
|
| -DEF_CALL_HANDLER(emscripten_do_not_unwind, {
|
| - return "sp = STACKTOP";
|
| -})
|
| -// prevent unwinding the async stack
|
| -DEF_CALL_HANDLER(emscripten_do_not_unwind_async, {
|
| - return "___async_unwind = 0";
|
| -})
|
| -DEF_CALL_HANDLER(emscripten_get_async_return_value_addr, {
|
| - return getAssign(CI) + "___async_retval";
|
| -})
|
| -
|
| -// emscripten instrinsics
|
| -DEF_CALL_HANDLER(emscripten_debugger, {
|
| - CantValidate = "emscripten_debugger is used";
|
| - return "debugger";
|
| -})
|
| -
|
| -// i64 support
|
| -
|
| -DEF_CALL_HANDLER(getHigh32, {
|
| - return getAssign(CI) + "tempRet0";
|
| -})
|
| -DEF_CALL_HANDLER(setHigh32, {
|
| - return "tempRet0 = " + getValueAsStr(CI->getOperand(0));
|
| -})
|
| -// XXX float handling here is not optimal
|
| -#define TO_I(low, high) \
|
| -DEF_CALL_HANDLER(low, { \
|
| - std::string Input = getValueAsStr(CI->getOperand(0)); \
|
| - if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Input; \
|
| - 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(CI) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (~~+Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295)) >>> 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(CI) + "HEAP32[tempDoublePtr>>2]|0";
|
| -})
|
| -DEF_CALL_HANDLER(BDtoIHigh, {
|
| - return getAssign(CI) + "HEAP32[tempDoublePtr+4>>2]|0";
|
| -})
|
| -DEF_CALL_HANDLER(SItoF, {
|
| - std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
|
| - "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
|
| - if (PreciseF32 && CI->getType()->isFloatTy()) {
|
| - Ret = "Math_fround(" + Ret + ")";
|
| - }
|
| - return getAssign(CI) + Ret;
|
| -})
|
| -DEF_CALL_HANDLER(UItoF, {
|
| - std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
|
| - "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
|
| - if (PreciseF32 && CI->getType()->isFloatTy()) {
|
| - Ret = "Math_fround(" + Ret + ")";
|
| - }
|
| - return getAssign(CI) + Ret;
|
| -})
|
| -DEF_CALL_HANDLER(SItoD, {
|
| - return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
|
| - "(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
|
| -})
|
| -DEF_CALL_HANDLER(UItoD, {
|
| - 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(CI) + "+HEAPF64[tempDoublePtr>>3]";
|
| -})
|
| -
|
| -// misc
|
| -
|
| -DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, {
|
| - return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(CI->getOperand(1));
|
| -})
|
| -
|
| -#define CMPXCHG_HANDLER(name) \
|
| -DEF_CALL_HANDLER(name, { \
|
| - const Value *P = CI->getOperand(0); \
|
| - return getLoad(CI, P, CI->getType(), 0) + ';' + \
|
| - "if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsCastParenStr(CI->getOperand(1)) + ") " + \
|
| - getStore(CI, P, CI->getType(), getValueAsStr(CI->getOperand(2)), 0); \
|
| -})
|
| -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i8);
|
| -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i16);
|
| -CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i32);
|
| -
|
| -#define UNROLL_LOOP_MAX 8
|
| -#define WRITE_LOOP_MAX 128
|
| -
|
| -DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, {
|
| - if (CI) {
|
| - ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3));
|
| - if (AlignInt) {
|
| - ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2));
|
| - if (LenInt) {
|
| - // we can emit inline code for this
|
| - unsigned Len = LenInt->getZExtValue();
|
| - if (Len <= WRITE_LOOP_MAX) {
|
| - unsigned Align = AlignInt->getZExtValue();
|
| - if (Align > 4) Align = 4;
|
| - else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default/4')
|
| - if (Align == 1 && Len > 1 && WarnOnUnaligned) {
|
| - errs() << "emcc: warning: unaligned memcpy in " << CI->getParent()->getParent()->getName() << ":" << *CI << " (compiler's fault?)\n";
|
| - }
|
| - unsigned Pos = 0;
|
| - std::string Ret;
|
| - std::string Dest = getValueAsStr(CI->getOperand(0));
|
| - std::string Src = getValueAsStr(CI->getOperand(1));
|
| - while (Len > 0) {
|
| - // handle as much as we can in the current alignment
|
| - unsigned CurrLen = Align*(Len/Align);
|
| - unsigned Factor = CurrLen/Align;
|
| - if (Factor <= UNROLL_LOOP_MAX) {
|
| - // unroll
|
| - for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) {
|
| - std::string Add = "+" + utostr(Pos + Offset);
|
| - Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + getHeapAccess(Src + Add, Align) + "|0";
|
| - }
|
| - } else {
|
| - // emit a loop
|
| - UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext());
|
| - Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; src=" + Src + "+" + utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))";
|
| - }
|
| - Pos += CurrLen;
|
| - Len -= CurrLen;
|
| - Align /= 2;
|
| - }
|
| - return Ret;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - Declares.insert("memcpy");
|
| - return CH___default__(CI, "_memcpy", 3) + "|0";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_memset_p0i8_i32, {
|
| - if (CI) {
|
| - ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3));
|
| - if (AlignInt) {
|
| - ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2));
|
| - if (LenInt) {
|
| - ConstantInt *ValInt = dyn_cast<ConstantInt>(CI->getOperand(1));
|
| - if (ValInt) {
|
| - // we can emit inline code for this
|
| - unsigned Len = LenInt->getZExtValue();
|
| - if (Len <= WRITE_LOOP_MAX) {
|
| - unsigned Align = AlignInt->getZExtValue();
|
| - unsigned Val = ValInt->getZExtValue();
|
| - if (Align > 4) Align = 4;
|
| - else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default/4')
|
| - if (Align == 1 && Len > 1 && WarnOnUnaligned) {
|
| - errs() << "emcc: warning: unaligned memcpy in " << CI->getParent()->getParent()->getName() << ":" << *CI << " (compiler's fault?)\n";
|
| - }
|
| - unsigned Pos = 0;
|
| - std::string Ret;
|
| - std::string Dest = getValueAsStr(CI->getOperand(0));
|
| - while (Len > 0) {
|
| - // handle as much as we can in the current alignment
|
| - unsigned CurrLen = Align*(Len/Align);
|
| - unsigned FullVal = 0;
|
| - for (unsigned i = 0; i < Align; i++) {
|
| - FullVal <<= 8;
|
| - FullVal |= Val;
|
| - }
|
| - unsigned Factor = CurrLen/Align;
|
| - if (Factor <= UNROLL_LOOP_MAX) {
|
| - // unroll
|
| - for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) {
|
| - std::string Add = "+" + utostr(Pos + Offset);
|
| - Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + utostr(FullVal) + "|0";
|
| - }
|
| - } else {
|
| - // emit a loop
|
| - UsedVars["dest"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext());
|
| - Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + utostr(FullVal) + "|0; dest=dest+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))";
|
| - }
|
| - Pos += CurrLen;
|
| - Len -= CurrLen;
|
| - Align /= 2;
|
| - }
|
| - return Ret;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - Declares.insert("memset");
|
| - return CH___default__(CI, "_memset", 3) + "|0";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, {
|
| - Declares.insert("memmove");
|
| - return CH___default__(CI, "_memmove", 3) + "|0";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_expect_i32, {
|
| - return getAssign(CI) + getValueAsStr(CI->getOperand(0));
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_dbg_declare, {
|
| - return "";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_dbg_value, {
|
| - return "";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_lifetime_start, {
|
| - return "";
|
| -})
|
| -
|
| -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(llvm_objectsize_i32_p0i8, {
|
| - return getAssign(CI) + ((cast<ConstantInt>(CI->getOperand(1)))->getZExtValue() == 0 ? "-1" : "0");
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_flt_rounds, {
|
| - // FLT_ROUNDS helper. We don't support setting the rounding mode dynamically,
|
| - // so it's always round-to-nearest (1).
|
| - return getAssign(CI) + "1";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(bitshift64Lshr, {
|
| - return CH___default__(CI, "_bitshift64Lshr", 3);
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(bitshift64Ashr, {
|
| - return CH___default__(CI, "_bitshift64Ashr", 3);
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(bitshift64Shl, {
|
| - return CH___default__(CI, "_bitshift64Shl", 3);
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_ctlz_i32, {
|
| - return CH___default__(CI, "Math_clz32", 1);
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(llvm_cttz_i32, {
|
| - return CH___default__(CI, "_llvm_cttz_i32", 1);
|
| -})
|
| -
|
| -// vector ops
|
| -DEF_CALL_HANDLER(emscripten_float32x4_signmask, {
|
| - return getAssign(CI) + getValueAsStr(CI->getOperand(0)) + ".signMask";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(emscripten_float32x4_loadx, {
|
| - return getAssign(CI) + "SIMD_float32x4_loadX(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ")";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(emscripten_float32x4_loadxy, {
|
| - return getAssign(CI) + "SIMD_float32x4_loadXY(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ")";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(emscripten_float32x4_storex, {
|
| - return "SIMD_float32x4_storeX(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")";
|
| -})
|
| -
|
| -DEF_CALL_HANDLER(emscripten_float32x4_storexy, {
|
| - return "SIMD_float32x4_storeXY(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ", " + getValueAsStr(CI->getOperand(1)) + ")";
|
| -})
|
| -
|
| -#define DEF_BUILTIN_HANDLER(name, to) \
|
| -DEF_CALL_HANDLER(name, { \
|
| - return CH___default__(CI, #to); \
|
| -})
|
| -
|
| -// Various simple redirects for our js libc, see library.js and LibraryManager.load
|
| -DEF_BUILTIN_HANDLER(abs, Math_abs);
|
| -DEF_BUILTIN_HANDLER(labs, Math_abs);
|
| -DEF_BUILTIN_HANDLER(cos, Math_cos);
|
| -DEF_BUILTIN_HANDLER(cosf, Math_cos);
|
| -DEF_BUILTIN_HANDLER(cosl, Math_cos);
|
| -DEF_BUILTIN_HANDLER(sin, Math_sin);
|
| -DEF_BUILTIN_HANDLER(sinf, Math_sin);
|
| -DEF_BUILTIN_HANDLER(sinl, Math_sin);
|
| -DEF_BUILTIN_HANDLER(tan, Math_tan);
|
| -DEF_BUILTIN_HANDLER(tanf, Math_tan);
|
| -DEF_BUILTIN_HANDLER(tanl, Math_tan);
|
| -DEF_BUILTIN_HANDLER(acos, Math_acos);
|
| -DEF_BUILTIN_HANDLER(acosf, Math_acos);
|
| -DEF_BUILTIN_HANDLER(acosl, Math_acos);
|
| -DEF_BUILTIN_HANDLER(asin, Math_asin);
|
| -DEF_BUILTIN_HANDLER(asinf, Math_asin);
|
| -DEF_BUILTIN_HANDLER(asinl, Math_asin);
|
| -DEF_BUILTIN_HANDLER(atan, Math_atan);
|
| -DEF_BUILTIN_HANDLER(atanf, Math_atan);
|
| -DEF_BUILTIN_HANDLER(atanl, Math_atan);
|
| -DEF_BUILTIN_HANDLER(atan2, Math_atan2);
|
| -DEF_BUILTIN_HANDLER(atan2f, Math_atan2);
|
| -DEF_BUILTIN_HANDLER(atan2l, Math_atan2);
|
| -DEF_BUILTIN_HANDLER(exp, Math_exp);
|
| -DEF_BUILTIN_HANDLER(expf, Math_exp);
|
| -DEF_BUILTIN_HANDLER(expl, Math_exp);
|
| -DEF_BUILTIN_HANDLER(log, Math_log);
|
| -DEF_BUILTIN_HANDLER(logf, Math_log);
|
| -DEF_BUILTIN_HANDLER(logl, Math_log);
|
| -DEF_BUILTIN_HANDLER(sqrt, Math_sqrt);
|
| -DEF_BUILTIN_HANDLER(sqrtf, Math_sqrt);
|
| -DEF_BUILTIN_HANDLER(sqrtl, Math_sqrt);
|
| -DEF_BUILTIN_HANDLER(fabs, Math_abs);
|
| -DEF_BUILTIN_HANDLER(fabsf, Math_abs);
|
| -DEF_BUILTIN_HANDLER(fabsl, Math_abs);
|
| -DEF_BUILTIN_HANDLER(llvm_fabs_f64, Math_abs);
|
| -DEF_BUILTIN_HANDLER(ceil, Math_ceil);
|
| -DEF_BUILTIN_HANDLER(ceilf, Math_ceil);
|
| -DEF_BUILTIN_HANDLER(ceill, Math_ceil);
|
| -DEF_BUILTIN_HANDLER(floor, Math_floor);
|
| -DEF_BUILTIN_HANDLER(floorf, Math_floor);
|
| -DEF_BUILTIN_HANDLER(floorl, Math_floor);
|
| -DEF_BUILTIN_HANDLER(pow, Math_pow);
|
| -DEF_BUILTIN_HANDLER(powf, Math_pow);
|
| -DEF_BUILTIN_HANDLER(powl, Math_pow);
|
| -DEF_BUILTIN_HANDLER(llvm_sqrt_f32, Math_sqrt);
|
| -DEF_BUILTIN_HANDLER(llvm_sqrt_f64, Math_sqrt);
|
| -DEF_BUILTIN_HANDLER(llvm_pow_f32, Math_pow);
|
| -DEF_BUILTIN_HANDLER(llvm_pow_f64, Math_pow);
|
| -DEF_BUILTIN_HANDLER(llvm_log_f32, Math_log);
|
| -DEF_BUILTIN_HANDLER(llvm_log_f64, Math_log);
|
| -DEF_BUILTIN_HANDLER(llvm_exp_f32, Math_exp);
|
| -DEF_BUILTIN_HANDLER(llvm_exp_f64, Math_exp);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_equal, SIMD_float32x4_equal);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_notEqual, SIMD_float32x4_notEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThan, SIMD_float32x4_lessThan);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThanOrEqual, SIMD_float32x4_lessThanOrEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThan, SIMD_float32x4_greaterThan);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThanOrEqual, SIMD_float32x4_greaterThanOrEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_select, SIMD_float32x4_select);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_min, SIMD_float32x4_min);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_max, SIMD.float32x4_max);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_abs, SIMD_float32x4_abs);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_sqrt, SIMD_float32x4_sqrt);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalApproximation, SIMD_float32x4_reciprocalApproximation);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation, SIMD_float32x4_reciprocalSqrtApproximation);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_and, SIMD_float32x4_and);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_or, SIMD_float32x4_or);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_xor, SIMD_float32x4_xor);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_not, SIMD_float32x4_not);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4Bits, SIMD_float32x4_fromInt32x4Bits);
|
| -DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4, SIMD_float32x4_fromInt32x4);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_equal, SIMD_int32x4_equal);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_notEqual, SIMD_int32x4_notEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThan, SIMD_int32x4_lessThan);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThanOrEqual, SIMD_int32x4_lessThanOrEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThan, SIMD_int32x4_greaterThan);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThanOrEqual, SIMD_int32x4_greaterThanOrEqual);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_select, SIMD_int32x4_select);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4Bits, SIMD_int32x4_fromFloat32x4Bits);
|
| -DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4, SIMD_int32x4_fromFloat32x4);
|
| -
|
| -// Setups
|
| -
|
| -void setupCallHandlers() {
|
| - assert(CallHandlers.empty());
|
| - #define SETUP_CALL_HANDLER(Ident) \
|
| - CallHandlers["_" #Ident] = &JSWriter::CH_##Ident;
|
| -
|
| - SETUP_CALL_HANDLER(__default__);
|
| - SETUP_CALL_HANDLER(emscripten_preinvoke);
|
| - SETUP_CALL_HANDLER(emscripten_postinvoke);
|
| - SETUP_CALL_HANDLER(emscripten_landingpad);
|
| - SETUP_CALL_HANDLER(emscripten_resume);
|
| - SETUP_CALL_HANDLER(emscripten_prep_setjmp);
|
| - SETUP_CALL_HANDLER(emscripten_cleanup_setjmp);
|
| - SETUP_CALL_HANDLER(emscripten_setjmp);
|
| - SETUP_CALL_HANDLER(emscripten_longjmp);
|
| - SETUP_CALL_HANDLER(emscripten_check_longjmp);
|
| - SETUP_CALL_HANDLER(emscripten_get_longjmp_result);
|
| - SETUP_CALL_HANDLER(emscripten_alloc_async_context);
|
| - SETUP_CALL_HANDLER(emscripten_check_async);
|
| - SETUP_CALL_HANDLER(emscripten_do_not_unwind);
|
| - SETUP_CALL_HANDLER(emscripten_do_not_unwind_async);
|
| - SETUP_CALL_HANDLER(emscripten_get_async_return_value_addr);
|
| - SETUP_CALL_HANDLER(emscripten_debugger);
|
| - SETUP_CALL_HANDLER(getHigh32);
|
| - SETUP_CALL_HANDLER(setHigh32);
|
| - SETUP_CALL_HANDLER(FtoILow);
|
| - SETUP_CALL_HANDLER(FtoIHigh);
|
| - SETUP_CALL_HANDLER(DtoILow);
|
| - SETUP_CALL_HANDLER(DtoIHigh);
|
| - SETUP_CALL_HANDLER(BDtoILow);
|
| - SETUP_CALL_HANDLER(BDtoIHigh);
|
| - SETUP_CALL_HANDLER(SItoF);
|
| - SETUP_CALL_HANDLER(UItoF);
|
| - SETUP_CALL_HANDLER(SItoD);
|
| - SETUP_CALL_HANDLER(UItoD);
|
| - SETUP_CALL_HANDLER(BItoD);
|
| - SETUP_CALL_HANDLER(llvm_nacl_atomic_store_i32);
|
| - SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i8);
|
| - SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i16);
|
| - SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i32);
|
| - SETUP_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32);
|
| - SETUP_CALL_HANDLER(llvm_memset_p0i8_i32);
|
| - SETUP_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32);
|
| - SETUP_CALL_HANDLER(llvm_expect_i32);
|
| - SETUP_CALL_HANDLER(llvm_dbg_declare);
|
| - 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(llvm_objectsize_i32_p0i8);
|
| - SETUP_CALL_HANDLER(llvm_flt_rounds);
|
| - SETUP_CALL_HANDLER(bitshift64Lshr);
|
| - SETUP_CALL_HANDLER(bitshift64Ashr);
|
| - SETUP_CALL_HANDLER(bitshift64Shl);
|
| - SETUP_CALL_HANDLER(llvm_ctlz_i32);
|
| - SETUP_CALL_HANDLER(llvm_cttz_i32);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_signmask);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_min);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_max);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_abs);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_sqrt);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalApproximation);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_equal);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_notEqual);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_lessThan);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_greaterThan);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_and);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_or);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_xor);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_not);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_select);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4);
|
| - SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits);
|
| - SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_loadx);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_loadxy);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_storex);
|
| - SETUP_CALL_HANDLER(emscripten_float32x4_storexy);
|
| -
|
| - SETUP_CALL_HANDLER(abs);
|
| - SETUP_CALL_HANDLER(labs);
|
| - SETUP_CALL_HANDLER(cos);
|
| - SETUP_CALL_HANDLER(cosf);
|
| - SETUP_CALL_HANDLER(cosl);
|
| - SETUP_CALL_HANDLER(sin);
|
| - SETUP_CALL_HANDLER(sinf);
|
| - SETUP_CALL_HANDLER(sinl);
|
| - SETUP_CALL_HANDLER(tan);
|
| - SETUP_CALL_HANDLER(tanf);
|
| - SETUP_CALL_HANDLER(tanl);
|
| - SETUP_CALL_HANDLER(acos);
|
| - SETUP_CALL_HANDLER(acosf);
|
| - SETUP_CALL_HANDLER(acosl);
|
| - SETUP_CALL_HANDLER(asin);
|
| - SETUP_CALL_HANDLER(asinf);
|
| - SETUP_CALL_HANDLER(asinl);
|
| - SETUP_CALL_HANDLER(atan);
|
| - SETUP_CALL_HANDLER(atanf);
|
| - SETUP_CALL_HANDLER(atanl);
|
| - SETUP_CALL_HANDLER(atan2);
|
| - SETUP_CALL_HANDLER(atan2f);
|
| - SETUP_CALL_HANDLER(atan2l);
|
| - SETUP_CALL_HANDLER(exp);
|
| - SETUP_CALL_HANDLER(expf);
|
| - SETUP_CALL_HANDLER(expl);
|
| - SETUP_CALL_HANDLER(log);
|
| - SETUP_CALL_HANDLER(logf);
|
| - SETUP_CALL_HANDLER(logl);
|
| - SETUP_CALL_HANDLER(sqrt);
|
| - SETUP_CALL_HANDLER(sqrtf);
|
| - SETUP_CALL_HANDLER(sqrtl);
|
| - SETUP_CALL_HANDLER(fabs);
|
| - SETUP_CALL_HANDLER(fabsf);
|
| - SETUP_CALL_HANDLER(fabsl);
|
| - SETUP_CALL_HANDLER(llvm_fabs_f64);
|
| - SETUP_CALL_HANDLER(ceil);
|
| - SETUP_CALL_HANDLER(ceilf);
|
| - SETUP_CALL_HANDLER(ceill);
|
| - SETUP_CALL_HANDLER(floor);
|
| - SETUP_CALL_HANDLER(floorf);
|
| - SETUP_CALL_HANDLER(floorl);
|
| - SETUP_CALL_HANDLER(pow);
|
| - SETUP_CALL_HANDLER(powf);
|
| - SETUP_CALL_HANDLER(powl);
|
| - SETUP_CALL_HANDLER(llvm_sqrt_f32);
|
| - SETUP_CALL_HANDLER(llvm_sqrt_f64);
|
| - SETUP_CALL_HANDLER(llvm_pow_f32);
|
| - SETUP_CALL_HANDLER(llvm_pow_f64);
|
| - SETUP_CALL_HANDLER(llvm_log_f32);
|
| - SETUP_CALL_HANDLER(llvm_log_f64);
|
| - SETUP_CALL_HANDLER(llvm_exp_f32);
|
| - SETUP_CALL_HANDLER(llvm_exp_f64);
|
| -}
|
| -
|
| -std::string handleCall(const Instruction *CI) {
|
| - const Value *CV = getActuallyCalledValue(CI);
|
| - if (const InlineAsm* IA = dyn_cast<const InlineAsm>(CV)) {
|
| - if (IA->hasSideEffects() && IA->getAsmString() == "") {
|
| - return "/* asm() memory 'barrier' */";
|
| - } else {
|
| - errs() << "In function " << CI->getParent()->getParent()->getName() << "()\n";
|
| - errs() << *IA << "\n";
|
| - report_fatal_error("asm() with non-empty content not supported, use EM_ASM() (see emscripten.h)");
|
| - }
|
| - }
|
| -
|
| - // 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);
|
| -
|
| - CallHandlerMap::iterator CH = CallHandlers.find("___default__");
|
| - if (isa<Function>(CV)) {
|
| - CallHandlerMap::iterator Custom = CallHandlers.find(Name);
|
| - if (Custom != CallHandlers.end()) CH = Custom;
|
| - }
|
| - return (this->*(CH->second))(CI, Name, -1);
|
| -}
|
| -
|
|
|