Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: lib/Target/JSBackend/CallHandlers.h

Issue 1692803002: Remove Emscripten support (Closed) Base URL: https://chromium.googlesource.com/a/native_client/pnacl-llvm.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Target/JSBackend/CMakeLists.txt ('k') | lib/Target/JSBackend/JS.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « lib/Target/JSBackend/CMakeLists.txt ('k') | lib/Target/JSBackend/JS.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698