| OLD | NEW |
| (Empty) |
| 1 // Call handlers: flexible map of call targets to arbitrary handling code | |
| 2 // | |
| 3 // Each handler needs DEF_CALL_HANDLER and SETUP_CALL_HANDLER | |
| 4 // | |
| 5 | |
| 6 typedef std::string (JSWriter::*CallHandler)(const Instruction*, std::string Nam
e, int NumArgs); | |
| 7 typedef std::map<std::string, CallHandler> CallHandlerMap; | |
| 8 CallHandlerMap CallHandlers; | |
| 9 | |
| 10 // Definitions | |
| 11 | |
| 12 unsigned getNumArgOperands(const Instruction *I) { | |
| 13 return ImmutableCallSite(I).arg_size(); | |
| 14 } | |
| 15 | |
| 16 const Value *getActuallyCalledValue(const Instruction *I) { | |
| 17 const Value *CV = ImmutableCallSite(I).getCalledValue(); | |
| 18 | |
| 19 // if the called value is a bitcast of a function, then we just call it direct
ly, properly | |
| 20 // for example, extern void x() in C will turn into void x(...) in LLVM IR, th
en the IR bitcasts | |
| 21 // it to the proper form right before the call. this both causes an unnecessar
y indirect | |
| 22 // call, and it is done with the wrong type. TODO: don't even put it into the
function table | |
| 23 if (const Function *F = dyn_cast<const Function>(CV->stripPointerCasts())) { | |
| 24 CV = F; | |
| 25 } | |
| 26 return CV; | |
| 27 } | |
| 28 | |
| 29 // We can't and shouldn't try to invoke an LLVM intrinsic which we overload with
a call hander - | |
| 30 // it would end up in a function table, which makes no sense. | |
| 31 bool canInvoke(const Value *V) { | |
| 32 const Function *F = dyn_cast<const Function>(V); | |
| 33 if (F && F->isDeclaration() && F->isIntrinsic()) { | |
| 34 auto Intrin = F->getIntrinsicID(); | |
| 35 if (Intrin == Intrinsic::memcpy || Intrin == Intrinsic::memset) { | |
| 36 return false; | |
| 37 } | |
| 38 } | |
| 39 return true; | |
| 40 } | |
| 41 | |
| 42 #define DEF_CALL_HANDLER(Ident, Code) \ | |
| 43 std::string CH_##Ident(const Instruction *CI, std::string Name, int NumArgs=-1
) { Code } | |
| 44 | |
| 45 DEF_CALL_HANDLER(__default__, { | |
| 46 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 | |
| 47 const Value *CV = getActuallyCalledValue(CI); | |
| 48 bool NeedCasts = true; | |
| 49 FunctionType *FT; | |
| 50 bool Invoke = false; | |
| 51 if (InvokeState == 1) { | |
| 52 InvokeState = 2; | |
| 53 Invoke = canInvoke(CV); | |
| 54 } | |
| 55 std::string Sig; | |
| 56 const Function *F = dyn_cast<const Function>(CV); | |
| 57 if (F) { | |
| 58 NeedCasts = F->isDeclaration(); // if ffi call, need casts | |
| 59 FT = F->getFunctionType(); | |
| 60 } else { | |
| 61 FT = dyn_cast<FunctionType>(dyn_cast<PointerType>(CV->getType())->getElement
Type()); | |
| 62 if (isAbsolute(CV->stripPointerCasts())) { | |
| 63 Name = "abort /* segfault, call an absolute addr */ "; | |
| 64 } else { | |
| 65 // function pointer call | |
| 66 ensureFunctionTable(FT); | |
| 67 if (!Invoke) { | |
| 68 Sig = getFunctionSignature(FT, &Name); | |
| 69 Name = std::string("FUNCTION_TABLE_") + Sig + "[" + Name + " & #FM_" + S
ig + "#]"; | |
| 70 NeedCasts = false; // function table call, so stays in asm module | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 bool ForcedNumArgs = NumArgs != -1; | |
| 76 if (!ForcedNumArgs) NumArgs = getNumArgOperands(CI); | |
| 77 | |
| 78 if (!FT->isVarArg() && !ForcedNumArgs) { | |
| 79 int TypeNumArgs = FT->getNumParams(); | |
| 80 if (TypeNumArgs != NumArgs) { | |
| 81 if (EmscriptenAssertions) prettyWarning() << "unexpected number of argumen
ts " << utostr(NumArgs) << " in call to '" << F->getName() << "', should be " <<
utostr(TypeNumArgs) << "\n"; | |
| 82 if (NumArgs > TypeNumArgs) NumArgs = TypeNumArgs; // lop off the extra par
ams that will not be used and just break validation | |
| 83 } | |
| 84 if (EmscriptenAssertions) { | |
| 85 for (int i = 0; i < std::min(TypeNumArgs, NumArgs); i++) { | |
| 86 Type *TypeType = FT->getParamType(i); | |
| 87 Type *ActualType = CI->getOperand(i)->getType(); | |
| 88 if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(A
ctualType)) { | |
| 89 prettyWarning() << "unexpected argument type " << *ActualType << " at
index " << utostr(i) << " in call to '" << F->getName() << "', should be " << *T
ypeType << "\n"; | |
| 90 } | |
| 91 } | |
| 92 } | |
| 93 } | |
| 94 if (EmscriptenAssertions) { | |
| 95 Type *TypeType = FT->getReturnType(); | |
| 96 Type *ActualType = CI->getType(); | |
| 97 if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(Actua
lType)) { | |
| 98 prettyWarning() << "unexpected return type " << *ActualType << " in call t
o '" << F->getName() << "', should be " << *TypeType << "\n"; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 if (Invoke) { | |
| 103 Sig = getFunctionSignature(FT, &Name); | |
| 104 Name = "invoke_" + Sig; | |
| 105 NeedCasts = true; | |
| 106 } | |
| 107 std::string text = Name + "("; | |
| 108 if (Invoke) { | |
| 109 // add first param | |
| 110 if (F) { | |
| 111 text += utostr(getFunctionIndex(F)); // convert to function pointer | |
| 112 } else { | |
| 113 text += getValueAsCastStr(CV); // already a function pointer | |
| 114 } | |
| 115 if (NumArgs > 0) text += ","; | |
| 116 } | |
| 117 // this is an ffi call if we need casts, and it is not a special Math_ builtin | |
| 118 bool FFI = NeedCasts; | |
| 119 if (FFI && Name.find("Math_") == 0) { | |
| 120 if (Name == "Math_ceil" || Name == "Math_floor" || Name == "Math_min" || Nam
e == "Math_max" || Name == "Math_sqrt" || Name == "Math_abs") { | |
| 121 // This special Math builtin is optimizable with all types, including floa
ts, so can treat it as non-ffi | |
| 122 FFI = false; | |
| 123 } | |
| 124 } | |
| 125 unsigned FFI_OUT = FFI ? ASM_FFI_OUT : 0; | |
| 126 for (int i = 0; i < NumArgs; i++) { | |
| 127 if (!NeedCasts) { | |
| 128 text += getValueAsStr(CI->getOperand(i)); | |
| 129 } else { | |
| 130 text += getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OU
T); | |
| 131 } | |
| 132 if (i < NumArgs - 1) text += ","; | |
| 133 } | |
| 134 text += ")"; | |
| 135 // handle return value | |
| 136 Type *InstRT = CI->getType(); | |
| 137 Type *ActualRT = FT->getReturnType(); | |
| 138 if (!InstRT->isVoidTy() && ActualRT->isVoidTy()) { | |
| 139 // the function we are calling was cast to something returning a value, but
it really | |
| 140 // does not return a value | |
| 141 getAssignIfNeeded(CI); // ensure the variable is defined, but do not emit it
here | |
| 142 // it should have 0 uses, but just to be safe | |
| 143 } else if (!ActualRT->isVoidTy()) { | |
| 144 unsigned FFI_IN = FFI ? ASM_FFI_IN : 0; | |
| 145 text = getAssignIfNeeded(CI) + "(" + getCast(text, ActualRT, ASM_NONSPECIFIC
| FFI_IN) + ")"; | |
| 146 } | |
| 147 return text; | |
| 148 }) | |
| 149 | |
| 150 // exceptions support | |
| 151 DEF_CALL_HANDLER(emscripten_preinvoke, { | |
| 152 // InvokeState is normally 0 here, but might be otherwise if a block was split
apart TODO: add a function attribute for this | |
| 153 InvokeState = 1; | |
| 154 return "__THREW__ = 0"; | |
| 155 }) | |
| 156 DEF_CALL_HANDLER(emscripten_postinvoke, { | |
| 157 // InvokeState is normally 2 here, but can be 1 if the call in between was opt
imized out, or 0 if a block was split apart | |
| 158 InvokeState = 0; | |
| 159 return getAssign(CI) + "__THREW__; __THREW__ = 0"; | |
| 160 }) | |
| 161 DEF_CALL_HANDLER(emscripten_landingpad, { | |
| 162 std::string Ret = getAssign(CI) + "___cxa_find_matching_catch("; | |
| 163 unsigned Num = getNumArgOperands(CI); | |
| 164 for (unsigned i = 1; i < Num-1; i++) { // ignore personality and cleanup XXX -
we probably should not be doing that! | |
| 165 if (i > 1) Ret += ","; | |
| 166 Ret += getValueAsCastStr(CI->getOperand(i)); | |
| 167 } | |
| 168 Ret += ")|0"; | |
| 169 return Ret; | |
| 170 }) | |
| 171 DEF_CALL_HANDLER(emscripten_resume, { | |
| 172 return "___resumeException(" + getValueAsCastStr(CI->getOperand(0)) + ")"; | |
| 173 }) | |
| 174 | |
| 175 // setjmp support | |
| 176 | |
| 177 DEF_CALL_HANDLER(emscripten_prep_setjmp, { | |
| 178 return getAdHocAssign("_setjmpTableSize", Type::getInt32Ty(CI->getContext()))
+ "4;" + | |
| 179 getAdHocAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "_
malloc(40) | 0;" + | |
| 180 "HEAP32[_setjmpTable>>2]=0"; | |
| 181 }) | |
| 182 DEF_CALL_HANDLER(emscripten_cleanup_setjmp, { | |
| 183 return "_free(_setjmpTable|0)"; | |
| 184 }) | |
| 185 DEF_CALL_HANDLER(emscripten_setjmp, { | |
| 186 // env, label, table | |
| 187 Declares.insert("saveSetjmp"); | |
| 188 return "_setjmpTable = _saveSetjmp(" + getValueAsStr(CI->getOperand(0)) + ","
+ getValueAsStr(CI->getOperand(1)) + ",_setjmpTable|0,_setjmpTableSize|0)|0;_set
jmpTableSize = tempRet0"; | |
| 189 }) | |
| 190 DEF_CALL_HANDLER(emscripten_longjmp, { | |
| 191 Declares.insert("longjmp"); | |
| 192 return CH___default__(CI, "_longjmp"); | |
| 193 }) | |
| 194 DEF_CALL_HANDLER(emscripten_check_longjmp, { | |
| 195 std::string Threw = getValueAsStr(CI->getOperand(0)); | |
| 196 std::string Target = getJSName(CI); | |
| 197 std::string Assign = getAssign(CI); | |
| 198 return "if (((" + Threw + "|0) != 0) & ((threwValue|0) != 0)) { " + | |
| 199 Assign + "_testSetjmp(HEAP32[" + Threw + ">>2]|0, _setjmpTable|0, _se
tjmpTableSize|0)|0; " + | |
| 200 "if ((" + Target + "|0) == 0) { _longjmp(" + Threw + "|0, threwValue|
0); } " + // rethrow | |
| 201 "tempRet0 = threwValue; " + | |
| 202 "} else { " + Assign + "-1; }"; | |
| 203 }) | |
| 204 DEF_CALL_HANDLER(emscripten_get_longjmp_result, { | |
| 205 std::string Threw = getValueAsStr(CI->getOperand(0)); | |
| 206 return getAssign(CI) + "tempRet0"; | |
| 207 }) | |
| 208 | |
| 209 // supporting async functions, see `<emscripten>/src/library_async.js` for detai
l. | |
| 210 DEF_CALL_HANDLER(emscripten_alloc_async_context, { | |
| 211 // insert sp as the 2nd parameter | |
| 212 return getAssign(CI) + "_emscripten_alloc_async_context(" + getValueAsStr(CI->
getOperand(0)) + ",sp)|0"; | |
| 213 }) | |
| 214 DEF_CALL_HANDLER(emscripten_check_async, { | |
| 215 return getAssign(CI) + "___async"; | |
| 216 }) | |
| 217 // prevent unwinding the stack | |
| 218 // preserve the return value of the return inst | |
| 219 DEF_CALL_HANDLER(emscripten_do_not_unwind, { | |
| 220 return "sp = STACKTOP"; | |
| 221 }) | |
| 222 // prevent unwinding the async stack | |
| 223 DEF_CALL_HANDLER(emscripten_do_not_unwind_async, { | |
| 224 return "___async_unwind = 0"; | |
| 225 }) | |
| 226 DEF_CALL_HANDLER(emscripten_get_async_return_value_addr, { | |
| 227 return getAssign(CI) + "___async_retval"; | |
| 228 }) | |
| 229 | |
| 230 // emscripten instrinsics | |
| 231 DEF_CALL_HANDLER(emscripten_debugger, { | |
| 232 CantValidate = "emscripten_debugger is used"; | |
| 233 return "debugger"; | |
| 234 }) | |
| 235 | |
| 236 // i64 support | |
| 237 | |
| 238 DEF_CALL_HANDLER(getHigh32, { | |
| 239 return getAssign(CI) + "tempRet0"; | |
| 240 }) | |
| 241 DEF_CALL_HANDLER(setHigh32, { | |
| 242 return "tempRet0 = " + getValueAsStr(CI->getOperand(0)); | |
| 243 }) | |
| 244 // XXX float handling here is not optimal | |
| 245 #define TO_I(low, high) \ | |
| 246 DEF_CALL_HANDLER(low, { \ | |
| 247 std::string Input = getValueAsStr(CI->getOperand(0)); \ | |
| 248 if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Inp
ut; \ | |
| 249 return getAssign(CI) + "(~~" + Input + ")>>>0"; \ | |
| 250 }) \ | |
| 251 DEF_CALL_HANDLER(high, { \ | |
| 252 std::string Input = getValueAsStr(CI->getOperand(0)); \ | |
| 253 if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Inp
ut; \ | |
| 254 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";
\ | |
| 255 }) | |
| 256 TO_I(FtoILow, FtoIHigh); | |
| 257 TO_I(DtoILow, DtoIHigh); | |
| 258 DEF_CALL_HANDLER(BDtoILow, { | |
| 259 return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";"
+ getAssign(CI) + "HEAP32[tempDoublePtr>>2]|0"; | |
| 260 }) | |
| 261 DEF_CALL_HANDLER(BDtoIHigh, { | |
| 262 return getAssign(CI) + "HEAP32[tempDoublePtr+4>>2]|0"; | |
| 263 }) | |
| 264 DEF_CALL_HANDLER(SItoF, { | |
| 265 std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNE
D) + ") + " + | |
| 266 "(+4294967296*(+" + getValueAsCastParenSt
r(CI->getOperand(1), ASM_SIGNED) + "))"; | |
| 267 if (PreciseF32 && CI->getType()->isFloatTy()) { | |
| 268 Ret = "Math_fround(" + Ret + ")"; | |
| 269 } | |
| 270 return getAssign(CI) + Ret; | |
| 271 }) | |
| 272 DEF_CALL_HANDLER(UItoF, { | |
| 273 std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNE
D) + ") + " + | |
| 274 "(+4294967296*(+" + getValueAsCastParenSt
r(CI->getOperand(1), ASM_UNSIGNED) + "))"; | |
| 275 if (PreciseF32 && CI->getType()->isFloatTy()) { | |
| 276 Ret = "Math_fround(" + Ret + ")"; | |
| 277 } | |
| 278 return getAssign(CI) + Ret; | |
| 279 }) | |
| 280 DEF_CALL_HANDLER(SItoD, { | |
| 281 return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UN
SIGNED) + ") + " + | |
| 282 "(+4294967296*(+" + getValueAsCastParenSt
r(CI->getOperand(1), ASM_SIGNED) + "))"; | |
| 283 }) | |
| 284 DEF_CALL_HANDLER(UItoD, { | |
| 285 return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UN
SIGNED) + ") + " + | |
| 286 "(+4294967296*(+" + getValueAsCastParenSt
r(CI->getOperand(1), ASM_UNSIGNED) + "))"; | |
| 287 }) | |
| 288 DEF_CALL_HANDLER(BItoD, { | |
| 289 return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getOperand(0)) + ";
" + | |
| 290 "HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getOperand(1)) + ";
" + | |
| 291 getAssign(CI) + "+HEAPF64[tempDoublePtr>>3]"; | |
| 292 }) | |
| 293 | |
| 294 // misc | |
| 295 | |
| 296 DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, { | |
| 297 return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(
CI->getOperand(1)); | |
| 298 }) | |
| 299 | |
| 300 #define CMPXCHG_HANDLER(name) \ | |
| 301 DEF_CALL_HANDLER(name, { \ | |
| 302 const Value *P = CI->getOperand(0); \ | |
| 303 return getLoad(CI, P, CI->getType(), 0) + ';' + \ | |
| 304 "if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsC
astParenStr(CI->getOperand(1)) + ") " + \ | |
| 305 getStore(CI, P, CI->getType(), getValueAsStr(CI->getOperand(2)), 0);
\ | |
| 306 }) | |
| 307 CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i8); | |
| 308 CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i16); | |
| 309 CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i32); | |
| 310 | |
| 311 #define UNROLL_LOOP_MAX 8 | |
| 312 #define WRITE_LOOP_MAX 128 | |
| 313 | |
| 314 DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, { | |
| 315 if (CI) { | |
| 316 ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3)); | |
| 317 if (AlignInt) { | |
| 318 ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2)); | |
| 319 if (LenInt) { | |
| 320 // we can emit inline code for this | |
| 321 unsigned Len = LenInt->getZExtValue(); | |
| 322 if (Len <= WRITE_LOOP_MAX) { | |
| 323 unsigned Align = AlignInt->getZExtValue(); | |
| 324 if (Align > 4) Align = 4; | |
| 325 else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memse
t (unlike other places where it means 'default/4') | |
| 326 if (Align == 1 && Len > 1 && WarnOnUnaligned) { | |
| 327 errs() << "emcc: warning: unaligned memcpy in " << CI->getParent()-
>getParent()->getName() << ":" << *CI << " (compiler's fault?)\n"; | |
| 328 } | |
| 329 unsigned Pos = 0; | |
| 330 std::string Ret; | |
| 331 std::string Dest = getValueAsStr(CI->getOperand(0)); | |
| 332 std::string Src = getValueAsStr(CI->getOperand(1)); | |
| 333 while (Len > 0) { | |
| 334 // handle as much as we can in the current alignment | |
| 335 unsigned CurrLen = Align*(Len/Align); | |
| 336 unsigned Factor = CurrLen/Align; | |
| 337 if (Factor <= UNROLL_LOOP_MAX) { | |
| 338 // unroll | |
| 339 for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) { | |
| 340 std::string Add = "+" + utostr(Pos + Offset); | |
| 341 Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + getHeapAcc
ess(Src + Add, Align) + "|0"; | |
| 342 } | |
| 343 } else { | |
| 344 // emit a loop | |
| 345 UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getI
nt32Ty(TheModule->getContext()); | |
| 346 Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; src=" + Src + "+"
+ utostr(Pos) + "|0; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAcces
s("dest", Align) + "=" + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr
(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))"; | |
| 347 } | |
| 348 Pos += CurrLen; | |
| 349 Len -= CurrLen; | |
| 350 Align /= 2; | |
| 351 } | |
| 352 return Ret; | |
| 353 } | |
| 354 } | |
| 355 } | |
| 356 } | |
| 357 Declares.insert("memcpy"); | |
| 358 return CH___default__(CI, "_memcpy", 3) + "|0"; | |
| 359 }) | |
| 360 | |
| 361 DEF_CALL_HANDLER(llvm_memset_p0i8_i32, { | |
| 362 if (CI) { | |
| 363 ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3)); | |
| 364 if (AlignInt) { | |
| 365 ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2)); | |
| 366 if (LenInt) { | |
| 367 ConstantInt *ValInt = dyn_cast<ConstantInt>(CI->getOperand(1)); | |
| 368 if (ValInt) { | |
| 369 // we can emit inline code for this | |
| 370 unsigned Len = LenInt->getZExtValue(); | |
| 371 if (Len <= WRITE_LOOP_MAX) { | |
| 372 unsigned Align = AlignInt->getZExtValue(); | |
| 373 unsigned Val = ValInt->getZExtValue(); | |
| 374 if (Align > 4) Align = 4; | |
| 375 else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and mem
set (unlike other places where it means 'default/4') | |
| 376 if (Align == 1 && Len > 1 && WarnOnUnaligned) { | |
| 377 errs() << "emcc: warning: unaligned memcpy in " << CI->getParent(
)->getParent()->getName() << ":" << *CI << " (compiler's fault?)\n"; | |
| 378 } | |
| 379 unsigned Pos = 0; | |
| 380 std::string Ret; | |
| 381 std::string Dest = getValueAsStr(CI->getOperand(0)); | |
| 382 while (Len > 0) { | |
| 383 // handle as much as we can in the current alignment | |
| 384 unsigned CurrLen = Align*(Len/Align); | |
| 385 unsigned FullVal = 0; | |
| 386 for (unsigned i = 0; i < Align; i++) { | |
| 387 FullVal <<= 8; | |
| 388 FullVal |= Val; | |
| 389 } | |
| 390 unsigned Factor = CurrLen/Align; | |
| 391 if (Factor <= UNROLL_LOOP_MAX) { | |
| 392 // unroll | |
| 393 for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) { | |
| 394 std::string Add = "+" + utostr(Pos + Offset); | |
| 395 Ret += ";" + getHeapAccess(Dest + Add, Align) + "=" + utostr(F
ullVal) + "|0"; | |
| 396 } | |
| 397 } else { | |
| 398 // emit a loop | |
| 399 UsedVars["dest"] = UsedVars["stop"] = Type::getInt32Ty(TheModule
->getContext()); | |
| 400 Ret += "dest=" + Dest + "+" + utostr(Pos) + "|0; stop=dest+" + u
tostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + "=" + utostr(FullV
al) + "|0; dest=dest+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))"; | |
| 401 } | |
| 402 Pos += CurrLen; | |
| 403 Len -= CurrLen; | |
| 404 Align /= 2; | |
| 405 } | |
| 406 return Ret; | |
| 407 } | |
| 408 } | |
| 409 } | |
| 410 } | |
| 411 } | |
| 412 Declares.insert("memset"); | |
| 413 return CH___default__(CI, "_memset", 3) + "|0"; | |
| 414 }) | |
| 415 | |
| 416 DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, { | |
| 417 Declares.insert("memmove"); | |
| 418 return CH___default__(CI, "_memmove", 3) + "|0"; | |
| 419 }) | |
| 420 | |
| 421 DEF_CALL_HANDLER(llvm_expect_i32, { | |
| 422 return getAssign(CI) + getValueAsStr(CI->getOperand(0)); | |
| 423 }) | |
| 424 | |
| 425 DEF_CALL_HANDLER(llvm_dbg_declare, { | |
| 426 return ""; | |
| 427 }) | |
| 428 | |
| 429 DEF_CALL_HANDLER(llvm_dbg_value, { | |
| 430 return ""; | |
| 431 }) | |
| 432 | |
| 433 DEF_CALL_HANDLER(llvm_lifetime_start, { | |
| 434 return ""; | |
| 435 }) | |
| 436 | |
| 437 DEF_CALL_HANDLER(llvm_lifetime_end, { | |
| 438 return ""; | |
| 439 }) | |
| 440 | |
| 441 DEF_CALL_HANDLER(llvm_invariant_start, { | |
| 442 return ""; | |
| 443 }) | |
| 444 | |
| 445 DEF_CALL_HANDLER(llvm_invariant_end, { | |
| 446 return ""; | |
| 447 }) | |
| 448 | |
| 449 DEF_CALL_HANDLER(llvm_prefetch, { | |
| 450 return ""; | |
| 451 }) | |
| 452 | |
| 453 DEF_CALL_HANDLER(llvm_objectsize_i32_p0i8, { | |
| 454 return getAssign(CI) + ((cast<ConstantInt>(CI->getOperand(1)))->getZExtValue(
) == 0 ? "-1" : "0"); | |
| 455 }) | |
| 456 | |
| 457 DEF_CALL_HANDLER(llvm_flt_rounds, { | |
| 458 // FLT_ROUNDS helper. We don't support setting the rounding mode dynamically, | |
| 459 // so it's always round-to-nearest (1). | |
| 460 return getAssign(CI) + "1"; | |
| 461 }) | |
| 462 | |
| 463 DEF_CALL_HANDLER(bitshift64Lshr, { | |
| 464 return CH___default__(CI, "_bitshift64Lshr", 3); | |
| 465 }) | |
| 466 | |
| 467 DEF_CALL_HANDLER(bitshift64Ashr, { | |
| 468 return CH___default__(CI, "_bitshift64Ashr", 3); | |
| 469 }) | |
| 470 | |
| 471 DEF_CALL_HANDLER(bitshift64Shl, { | |
| 472 return CH___default__(CI, "_bitshift64Shl", 3); | |
| 473 }) | |
| 474 | |
| 475 DEF_CALL_HANDLER(llvm_ctlz_i32, { | |
| 476 return CH___default__(CI, "Math_clz32", 1); | |
| 477 }) | |
| 478 | |
| 479 DEF_CALL_HANDLER(llvm_cttz_i32, { | |
| 480 return CH___default__(CI, "_llvm_cttz_i32", 1); | |
| 481 }) | |
| 482 | |
| 483 // vector ops | |
| 484 DEF_CALL_HANDLER(emscripten_float32x4_signmask, { | |
| 485 return getAssign(CI) + getValueAsStr(CI->getOperand(0)) + ".signMask"; | |
| 486 }) | |
| 487 | |
| 488 DEF_CALL_HANDLER(emscripten_float32x4_loadx, { | |
| 489 return getAssign(CI) + "SIMD_float32x4_loadX(HEAPU8, " + getValueAsStr(CI->get
Operand(0)) + ")"; | |
| 490 }) | |
| 491 | |
| 492 DEF_CALL_HANDLER(emscripten_float32x4_loadxy, { | |
| 493 return getAssign(CI) + "SIMD_float32x4_loadXY(HEAPU8, " + getValueAsStr(CI->ge
tOperand(0)) + ")"; | |
| 494 }) | |
| 495 | |
| 496 DEF_CALL_HANDLER(emscripten_float32x4_storex, { | |
| 497 return "SIMD_float32x4_storeX(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + "
, " + getValueAsStr(CI->getOperand(1)) + ")"; | |
| 498 }) | |
| 499 | |
| 500 DEF_CALL_HANDLER(emscripten_float32x4_storexy, { | |
| 501 return "SIMD_float32x4_storeXY(HEAPU8, " + getValueAsStr(CI->getOperand(0)) +
", " + getValueAsStr(CI->getOperand(1)) + ")"; | |
| 502 }) | |
| 503 | |
| 504 #define DEF_BUILTIN_HANDLER(name, to) \ | |
| 505 DEF_CALL_HANDLER(name, { \ | |
| 506 return CH___default__(CI, #to); \ | |
| 507 }) | |
| 508 | |
| 509 // Various simple redirects for our js libc, see library.js and LibraryManager.l
oad | |
| 510 DEF_BUILTIN_HANDLER(abs, Math_abs); | |
| 511 DEF_BUILTIN_HANDLER(labs, Math_abs); | |
| 512 DEF_BUILTIN_HANDLER(cos, Math_cos); | |
| 513 DEF_BUILTIN_HANDLER(cosf, Math_cos); | |
| 514 DEF_BUILTIN_HANDLER(cosl, Math_cos); | |
| 515 DEF_BUILTIN_HANDLER(sin, Math_sin); | |
| 516 DEF_BUILTIN_HANDLER(sinf, Math_sin); | |
| 517 DEF_BUILTIN_HANDLER(sinl, Math_sin); | |
| 518 DEF_BUILTIN_HANDLER(tan, Math_tan); | |
| 519 DEF_BUILTIN_HANDLER(tanf, Math_tan); | |
| 520 DEF_BUILTIN_HANDLER(tanl, Math_tan); | |
| 521 DEF_BUILTIN_HANDLER(acos, Math_acos); | |
| 522 DEF_BUILTIN_HANDLER(acosf, Math_acos); | |
| 523 DEF_BUILTIN_HANDLER(acosl, Math_acos); | |
| 524 DEF_BUILTIN_HANDLER(asin, Math_asin); | |
| 525 DEF_BUILTIN_HANDLER(asinf, Math_asin); | |
| 526 DEF_BUILTIN_HANDLER(asinl, Math_asin); | |
| 527 DEF_BUILTIN_HANDLER(atan, Math_atan); | |
| 528 DEF_BUILTIN_HANDLER(atanf, Math_atan); | |
| 529 DEF_BUILTIN_HANDLER(atanl, Math_atan); | |
| 530 DEF_BUILTIN_HANDLER(atan2, Math_atan2); | |
| 531 DEF_BUILTIN_HANDLER(atan2f, Math_atan2); | |
| 532 DEF_BUILTIN_HANDLER(atan2l, Math_atan2); | |
| 533 DEF_BUILTIN_HANDLER(exp, Math_exp); | |
| 534 DEF_BUILTIN_HANDLER(expf, Math_exp); | |
| 535 DEF_BUILTIN_HANDLER(expl, Math_exp); | |
| 536 DEF_BUILTIN_HANDLER(log, Math_log); | |
| 537 DEF_BUILTIN_HANDLER(logf, Math_log); | |
| 538 DEF_BUILTIN_HANDLER(logl, Math_log); | |
| 539 DEF_BUILTIN_HANDLER(sqrt, Math_sqrt); | |
| 540 DEF_BUILTIN_HANDLER(sqrtf, Math_sqrt); | |
| 541 DEF_BUILTIN_HANDLER(sqrtl, Math_sqrt); | |
| 542 DEF_BUILTIN_HANDLER(fabs, Math_abs); | |
| 543 DEF_BUILTIN_HANDLER(fabsf, Math_abs); | |
| 544 DEF_BUILTIN_HANDLER(fabsl, Math_abs); | |
| 545 DEF_BUILTIN_HANDLER(llvm_fabs_f64, Math_abs); | |
| 546 DEF_BUILTIN_HANDLER(ceil, Math_ceil); | |
| 547 DEF_BUILTIN_HANDLER(ceilf, Math_ceil); | |
| 548 DEF_BUILTIN_HANDLER(ceill, Math_ceil); | |
| 549 DEF_BUILTIN_HANDLER(floor, Math_floor); | |
| 550 DEF_BUILTIN_HANDLER(floorf, Math_floor); | |
| 551 DEF_BUILTIN_HANDLER(floorl, Math_floor); | |
| 552 DEF_BUILTIN_HANDLER(pow, Math_pow); | |
| 553 DEF_BUILTIN_HANDLER(powf, Math_pow); | |
| 554 DEF_BUILTIN_HANDLER(powl, Math_pow); | |
| 555 DEF_BUILTIN_HANDLER(llvm_sqrt_f32, Math_sqrt); | |
| 556 DEF_BUILTIN_HANDLER(llvm_sqrt_f64, Math_sqrt); | |
| 557 DEF_BUILTIN_HANDLER(llvm_pow_f32, Math_pow); | |
| 558 DEF_BUILTIN_HANDLER(llvm_pow_f64, Math_pow); | |
| 559 DEF_BUILTIN_HANDLER(llvm_log_f32, Math_log); | |
| 560 DEF_BUILTIN_HANDLER(llvm_log_f64, Math_log); | |
| 561 DEF_BUILTIN_HANDLER(llvm_exp_f32, Math_exp); | |
| 562 DEF_BUILTIN_HANDLER(llvm_exp_f64, Math_exp); | |
| 563 DEF_BUILTIN_HANDLER(emscripten_float32x4_equal, SIMD_float32x4_equal); | |
| 564 DEF_BUILTIN_HANDLER(emscripten_float32x4_notEqual, SIMD_float32x4_notEqual); | |
| 565 DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThan, SIMD_float32x4_lessThan); | |
| 566 DEF_BUILTIN_HANDLER(emscripten_float32x4_lessThanOrEqual, SIMD_float32x4_lessTha
nOrEqual); | |
| 567 DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThan, SIMD_float32x4_greaterThan
); | |
| 568 DEF_BUILTIN_HANDLER(emscripten_float32x4_greaterThanOrEqual, SIMD_float32x4_grea
terThanOrEqual); | |
| 569 DEF_BUILTIN_HANDLER(emscripten_float32x4_select, SIMD_float32x4_select); | |
| 570 DEF_BUILTIN_HANDLER(emscripten_float32x4_min, SIMD_float32x4_min); | |
| 571 DEF_BUILTIN_HANDLER(emscripten_float32x4_max, SIMD.float32x4_max); | |
| 572 DEF_BUILTIN_HANDLER(emscripten_float32x4_abs, SIMD_float32x4_abs); | |
| 573 DEF_BUILTIN_HANDLER(emscripten_float32x4_sqrt, SIMD_float32x4_sqrt); | |
| 574 DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalApproximation, SIMD_float32x4
_reciprocalApproximation); | |
| 575 DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation, SIMD_float
32x4_reciprocalSqrtApproximation); | |
| 576 DEF_BUILTIN_HANDLER(emscripten_float32x4_and, SIMD_float32x4_and); | |
| 577 DEF_BUILTIN_HANDLER(emscripten_float32x4_or, SIMD_float32x4_or); | |
| 578 DEF_BUILTIN_HANDLER(emscripten_float32x4_xor, SIMD_float32x4_xor); | |
| 579 DEF_BUILTIN_HANDLER(emscripten_float32x4_not, SIMD_float32x4_not); | |
| 580 DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4Bits, SIMD_float32x4_fromInt
32x4Bits); | |
| 581 DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4, SIMD_float32x4_fromInt32x4
); | |
| 582 DEF_BUILTIN_HANDLER(emscripten_int32x4_equal, SIMD_int32x4_equal); | |
| 583 DEF_BUILTIN_HANDLER(emscripten_int32x4_notEqual, SIMD_int32x4_notEqual); | |
| 584 DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThan, SIMD_int32x4_lessThan); | |
| 585 DEF_BUILTIN_HANDLER(emscripten_int32x4_lessThanOrEqual, SIMD_int32x4_lessThanOrE
qual); | |
| 586 DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThan, SIMD_int32x4_greaterThan); | |
| 587 DEF_BUILTIN_HANDLER(emscripten_int32x4_greaterThanOrEqual, SIMD_int32x4_greaterT
hanOrEqual); | |
| 588 DEF_BUILTIN_HANDLER(emscripten_int32x4_select, SIMD_int32x4_select); | |
| 589 DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4Bits, SIMD_int32x4_fromFloat
32x4Bits); | |
| 590 DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4, SIMD_int32x4_fromFloat32x4
); | |
| 591 | |
| 592 // Setups | |
| 593 | |
| 594 void setupCallHandlers() { | |
| 595 assert(CallHandlers.empty()); | |
| 596 #define SETUP_CALL_HANDLER(Ident) \ | |
| 597 CallHandlers["_" #Ident] = &JSWriter::CH_##Ident; | |
| 598 | |
| 599 SETUP_CALL_HANDLER(__default__); | |
| 600 SETUP_CALL_HANDLER(emscripten_preinvoke); | |
| 601 SETUP_CALL_HANDLER(emscripten_postinvoke); | |
| 602 SETUP_CALL_HANDLER(emscripten_landingpad); | |
| 603 SETUP_CALL_HANDLER(emscripten_resume); | |
| 604 SETUP_CALL_HANDLER(emscripten_prep_setjmp); | |
| 605 SETUP_CALL_HANDLER(emscripten_cleanup_setjmp); | |
| 606 SETUP_CALL_HANDLER(emscripten_setjmp); | |
| 607 SETUP_CALL_HANDLER(emscripten_longjmp); | |
| 608 SETUP_CALL_HANDLER(emscripten_check_longjmp); | |
| 609 SETUP_CALL_HANDLER(emscripten_get_longjmp_result); | |
| 610 SETUP_CALL_HANDLER(emscripten_alloc_async_context); | |
| 611 SETUP_CALL_HANDLER(emscripten_check_async); | |
| 612 SETUP_CALL_HANDLER(emscripten_do_not_unwind); | |
| 613 SETUP_CALL_HANDLER(emscripten_do_not_unwind_async); | |
| 614 SETUP_CALL_HANDLER(emscripten_get_async_return_value_addr); | |
| 615 SETUP_CALL_HANDLER(emscripten_debugger); | |
| 616 SETUP_CALL_HANDLER(getHigh32); | |
| 617 SETUP_CALL_HANDLER(setHigh32); | |
| 618 SETUP_CALL_HANDLER(FtoILow); | |
| 619 SETUP_CALL_HANDLER(FtoIHigh); | |
| 620 SETUP_CALL_HANDLER(DtoILow); | |
| 621 SETUP_CALL_HANDLER(DtoIHigh); | |
| 622 SETUP_CALL_HANDLER(BDtoILow); | |
| 623 SETUP_CALL_HANDLER(BDtoIHigh); | |
| 624 SETUP_CALL_HANDLER(SItoF); | |
| 625 SETUP_CALL_HANDLER(UItoF); | |
| 626 SETUP_CALL_HANDLER(SItoD); | |
| 627 SETUP_CALL_HANDLER(UItoD); | |
| 628 SETUP_CALL_HANDLER(BItoD); | |
| 629 SETUP_CALL_HANDLER(llvm_nacl_atomic_store_i32); | |
| 630 SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i8); | |
| 631 SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i16); | |
| 632 SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i32); | |
| 633 SETUP_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32); | |
| 634 SETUP_CALL_HANDLER(llvm_memset_p0i8_i32); | |
| 635 SETUP_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32); | |
| 636 SETUP_CALL_HANDLER(llvm_expect_i32); | |
| 637 SETUP_CALL_HANDLER(llvm_dbg_declare); | |
| 638 SETUP_CALL_HANDLER(llvm_dbg_value); | |
| 639 SETUP_CALL_HANDLER(llvm_lifetime_start); | |
| 640 SETUP_CALL_HANDLER(llvm_lifetime_end); | |
| 641 SETUP_CALL_HANDLER(llvm_invariant_start); | |
| 642 SETUP_CALL_HANDLER(llvm_invariant_end); | |
| 643 SETUP_CALL_HANDLER(llvm_prefetch); | |
| 644 SETUP_CALL_HANDLER(llvm_objectsize_i32_p0i8); | |
| 645 SETUP_CALL_HANDLER(llvm_flt_rounds); | |
| 646 SETUP_CALL_HANDLER(bitshift64Lshr); | |
| 647 SETUP_CALL_HANDLER(bitshift64Ashr); | |
| 648 SETUP_CALL_HANDLER(bitshift64Shl); | |
| 649 SETUP_CALL_HANDLER(llvm_ctlz_i32); | |
| 650 SETUP_CALL_HANDLER(llvm_cttz_i32); | |
| 651 SETUP_CALL_HANDLER(emscripten_float32x4_signmask); | |
| 652 SETUP_CALL_HANDLER(emscripten_float32x4_min); | |
| 653 SETUP_CALL_HANDLER(emscripten_float32x4_max); | |
| 654 SETUP_CALL_HANDLER(emscripten_float32x4_abs); | |
| 655 SETUP_CALL_HANDLER(emscripten_float32x4_sqrt); | |
| 656 SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalApproximation); | |
| 657 SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation); | |
| 658 SETUP_CALL_HANDLER(emscripten_float32x4_equal); | |
| 659 SETUP_CALL_HANDLER(emscripten_float32x4_notEqual); | |
| 660 SETUP_CALL_HANDLER(emscripten_float32x4_lessThan); | |
| 661 SETUP_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual); | |
| 662 SETUP_CALL_HANDLER(emscripten_float32x4_greaterThan); | |
| 663 SETUP_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual); | |
| 664 SETUP_CALL_HANDLER(emscripten_float32x4_and); | |
| 665 SETUP_CALL_HANDLER(emscripten_float32x4_or); | |
| 666 SETUP_CALL_HANDLER(emscripten_float32x4_xor); | |
| 667 SETUP_CALL_HANDLER(emscripten_float32x4_not); | |
| 668 SETUP_CALL_HANDLER(emscripten_float32x4_select); | |
| 669 SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits); | |
| 670 SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4); | |
| 671 SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits); | |
| 672 SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4); | |
| 673 SETUP_CALL_HANDLER(emscripten_float32x4_loadx); | |
| 674 SETUP_CALL_HANDLER(emscripten_float32x4_loadxy); | |
| 675 SETUP_CALL_HANDLER(emscripten_float32x4_storex); | |
| 676 SETUP_CALL_HANDLER(emscripten_float32x4_storexy); | |
| 677 | |
| 678 SETUP_CALL_HANDLER(abs); | |
| 679 SETUP_CALL_HANDLER(labs); | |
| 680 SETUP_CALL_HANDLER(cos); | |
| 681 SETUP_CALL_HANDLER(cosf); | |
| 682 SETUP_CALL_HANDLER(cosl); | |
| 683 SETUP_CALL_HANDLER(sin); | |
| 684 SETUP_CALL_HANDLER(sinf); | |
| 685 SETUP_CALL_HANDLER(sinl); | |
| 686 SETUP_CALL_HANDLER(tan); | |
| 687 SETUP_CALL_HANDLER(tanf); | |
| 688 SETUP_CALL_HANDLER(tanl); | |
| 689 SETUP_CALL_HANDLER(acos); | |
| 690 SETUP_CALL_HANDLER(acosf); | |
| 691 SETUP_CALL_HANDLER(acosl); | |
| 692 SETUP_CALL_HANDLER(asin); | |
| 693 SETUP_CALL_HANDLER(asinf); | |
| 694 SETUP_CALL_HANDLER(asinl); | |
| 695 SETUP_CALL_HANDLER(atan); | |
| 696 SETUP_CALL_HANDLER(atanf); | |
| 697 SETUP_CALL_HANDLER(atanl); | |
| 698 SETUP_CALL_HANDLER(atan2); | |
| 699 SETUP_CALL_HANDLER(atan2f); | |
| 700 SETUP_CALL_HANDLER(atan2l); | |
| 701 SETUP_CALL_HANDLER(exp); | |
| 702 SETUP_CALL_HANDLER(expf); | |
| 703 SETUP_CALL_HANDLER(expl); | |
| 704 SETUP_CALL_HANDLER(log); | |
| 705 SETUP_CALL_HANDLER(logf); | |
| 706 SETUP_CALL_HANDLER(logl); | |
| 707 SETUP_CALL_HANDLER(sqrt); | |
| 708 SETUP_CALL_HANDLER(sqrtf); | |
| 709 SETUP_CALL_HANDLER(sqrtl); | |
| 710 SETUP_CALL_HANDLER(fabs); | |
| 711 SETUP_CALL_HANDLER(fabsf); | |
| 712 SETUP_CALL_HANDLER(fabsl); | |
| 713 SETUP_CALL_HANDLER(llvm_fabs_f64); | |
| 714 SETUP_CALL_HANDLER(ceil); | |
| 715 SETUP_CALL_HANDLER(ceilf); | |
| 716 SETUP_CALL_HANDLER(ceill); | |
| 717 SETUP_CALL_HANDLER(floor); | |
| 718 SETUP_CALL_HANDLER(floorf); | |
| 719 SETUP_CALL_HANDLER(floorl); | |
| 720 SETUP_CALL_HANDLER(pow); | |
| 721 SETUP_CALL_HANDLER(powf); | |
| 722 SETUP_CALL_HANDLER(powl); | |
| 723 SETUP_CALL_HANDLER(llvm_sqrt_f32); | |
| 724 SETUP_CALL_HANDLER(llvm_sqrt_f64); | |
| 725 SETUP_CALL_HANDLER(llvm_pow_f32); | |
| 726 SETUP_CALL_HANDLER(llvm_pow_f64); | |
| 727 SETUP_CALL_HANDLER(llvm_log_f32); | |
| 728 SETUP_CALL_HANDLER(llvm_log_f64); | |
| 729 SETUP_CALL_HANDLER(llvm_exp_f32); | |
| 730 SETUP_CALL_HANDLER(llvm_exp_f64); | |
| 731 } | |
| 732 | |
| 733 std::string handleCall(const Instruction *CI) { | |
| 734 const Value *CV = getActuallyCalledValue(CI); | |
| 735 if (const InlineAsm* IA = dyn_cast<const InlineAsm>(CV)) { | |
| 736 if (IA->hasSideEffects() && IA->getAsmString() == "") { | |
| 737 return "/* asm() memory 'barrier' */"; | |
| 738 } else { | |
| 739 errs() << "In function " << CI->getParent()->getParent()->getName() << "()
\n"; | |
| 740 errs() << *IA << "\n"; | |
| 741 report_fatal_error("asm() with non-empty content not supported, use EM_ASM
() (see emscripten.h)"); | |
| 742 } | |
| 743 } | |
| 744 | |
| 745 // Get the name to call this function by. If it's a direct call, meaning | |
| 746 // which know which Function we're calling, avoid calling getValueAsStr, as | |
| 747 // we don't need to use a function index. | |
| 748 const std::string &Name = isa<Function>(CV) ? getJSName(CV) : getValueAsStr(CV
); | |
| 749 | |
| 750 CallHandlerMap::iterator CH = CallHandlers.find("___default__"); | |
| 751 if (isa<Function>(CV)) { | |
| 752 CallHandlerMap::iterator Custom = CallHandlers.find(Name); | |
| 753 if (Custom != CallHandlers.end()) CH = Custom; | |
| 754 } | |
| 755 return (this->*(CH->second))(CI, Name, -1); | |
| 756 } | |
| 757 | |
| OLD | NEW |