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 |