blob: 9c3ae3bf28886885ba10818a565d636a40afae7d [file] [log] [blame]
// Call handlers: flexible map of call targets to arbitrary handling code
//
// Each handler needs DEF_CALL_HANDLER and SETUP_CALL_HANDLER
//
// Call handlers emit the code that the call will be replaced by. If that
// emitted code contains calls, it must add the targets to Declares,
// which are reported as declared but not implemented symbols, so that
// JS linking brings them in.
#include "llvm/Support/ScopedPrinter.h"
typedef std::string (JSWriter::*CallHandler)(const Instruction*, std::string Name, int NumArgs);
typedef std::map<std::string, CallHandler> CallHandlerMap;
CallHandlerMap CallHandlers;
// Definitions
unsigned getNumArgOperands(const Instruction *I) {
return ImmutableCallSite(I).arg_size();
}
const Value *getActuallyCalledValue(const Instruction *I) {
const Value *CV = ImmutableCallSite(I).getCalledValue();
// if the called value is a bitcast of a function, then we just call it directly, properly
// for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
// it to the proper form right before the call. this both causes an unnecessary indirect
// call, and it is done with the wrong type. TODO: don't even put it into the function table
if (const Function *F = dyn_cast<const Function>(stripPointerCastsWithoutSideEffects(CV))) {
CV = F;
}
return CV;
}
// We can't and shouldn't try to invoke an LLVM intrinsic which we overload with a call hander -
// it would end up in a function table, which makes no sense.
bool canInvoke(const Value *V) {
const Function *F = dyn_cast<const Function>(V);
if (F && F->isDeclaration() && F->isIntrinsic()) {
auto Intrin = F->getIntrinsicID();
if (Intrin == Intrinsic::memcpy || Intrin == Intrinsic::memset || Intrin == Intrinsic::memmove) {
return false;
}
}
return true;
}
#define DEF_CALL_HANDLER(Ident, Code) \
std::string CH_##Ident(const Instruction *CI, std::string Name, int NumArgs=-1) { Code }
void RegisterMathUse(const std::string &Name) {
if (Name == "Math_floor") JSWriter::UsesMathFloor = true;
else if (Name == "Math_abs") JSWriter::UsesMathAbs = true;
else if (Name == "Math_sqrt") JSWriter::UsesMathSqrt = true;
else if (Name == "Math_pow") JSWriter::UsesMathPow = true;
else if (Name == "Math_cos") JSWriter::UsesMathCos = true;
else if (Name == "Math_sin") JSWriter::UsesMathSin = true;
else if (Name == "Math_tan") JSWriter::UsesMathAcos = true;
else if (Name == "Math_asin") JSWriter::UsesMathAsin = true;
else if (Name == "Math_atan") JSWriter::UsesMathAtan = true;
else if (Name == "Math_atan2") JSWriter::UsesMathAtan2 = true;
else if (Name == "Math_exp") JSWriter::UsesMathExp = true;
else if (Name == "Math_log") JSWriter::UsesMathLog = true;
else if (Name == "Math_ceil") JSWriter::UsesMathCeil = true;
else if (Name == "Math_imul") JSWriter::UsesMathImul = true;
else if (Name == "Math_min") JSWriter::UsesMathMin = true;
else if (Name == "Math_max") JSWriter::UsesMathMax = true;
else if (Name == "Math_clz32") JSWriter::UsesMathClz32 = true;
else if (Name == "Math_fround") JSWriter::UsesMathFround = true;
}
DEF_CALL_HANDLER(__default__, {
if (!CI) return ""; // we are just called from a handler that was called from getFunctionIndex, only to ensure the handler was run at least once
const Value *CV = getActuallyCalledValue(CI);
bool NeedCasts = true;
FunctionType *FT;
bool Invoke = false;
bool Emulated = false;
if (InvokeState == 1) {
InvokeState = 2;
Invoke = canInvoke(CV);
}
std::string Sig;
bool IsMath = Name.find("Math_") == 0;
if (IsMath) RegisterMathUse(Name);
bool ForcedNumArgs = NumArgs != -1;
if (!ForcedNumArgs) NumArgs = getNumArgOperands(CI);
const Function *F = dyn_cast<const Function>(CV);
if (F) {
NeedCasts = F->isDeclaration(); // if ffi call, need casts
if (IsMath && !NeedCasts) {
// this was renamed to a math function, but the actual function is implemented, presumably from libc; use that
IsMath = false;
Name = getJSName(F);
}
FT = F->getFunctionType();
} else {
FT = dyn_cast<FunctionType>(dyn_cast<PointerType>(CV->getType())->getElementType());
if (isAbsolute(CV->stripPointerCasts())) {
Name = "abort /* segfault, call an absolute addr */ ";
} else {
// function pointer call
ensureFunctionTable(FT);
if (!Invoke) {
Sig = getFunctionSignature(FT);
if (!EmulatedFunctionPointers) {
Name = std::string("FUNCTION_TABLE_") + Sig + '[' + Name + " & #FM_" + Sig + "#]";
NeedCasts = false; // function table call, so stays in asm module
} else {
Name = std::string(Relocatable ? "mftCall_" : "ftCall_") + Sig + '(' + getCast(Name, Type::getInt32Ty(CI->getContext()));
if (NumArgs > 0) Name += ',';
Emulated = true;
if (WebAssembly) {
// this call uses the wasm Table
NeedCasts = false;
}
}
}
}
}
if (!FT->isVarArg() && !ForcedNumArgs) {
int TypeNumArgs = FT->getNumParams();
if (TypeNumArgs != NumArgs) {
if (EmscriptenAssertions) prettyWarning() << "unexpected number of arguments " << utostr(NumArgs) << " in call to '" << F->getName() << "', should be " << utostr(TypeNumArgs) << "\n";
if (NumArgs > TypeNumArgs) NumArgs = TypeNumArgs; // lop off the extra params that will not be used and just break validation
}
if (EmscriptenAssertions) {
for (int i = 0; i < std::min(TypeNumArgs, NumArgs); i++) {
Type *TypeType = FT->getParamType(i);
Type *ActualType = CI->getOperand(i)->getType();
if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
prettyWarning() << "unexpected argument type " << *ActualType << " at index " << utostr(i) << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
}
}
}
}
if (EmscriptenAssertions) {
Type *TypeType = FT->getReturnType();
Type *ActualType = CI->getType();
if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
prettyWarning() << "unexpected return type " << *ActualType << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
}
}
if (Invoke) {
Sig = getFunctionSignature(FT);
Name = "invoke_" + Sig;
rememberUsedInvokeFunction(Name);
NeedCasts = true;
}
std::string text = Name;
if (!Emulated) text += '(';
if (Invoke) {
// add first param
if (F) {
text += relocateFunctionPointer(utostr(getFunctionIndex(F))); // convert to function pointer
} else {
text += getValueAsCastStr(CV); // already a function pointer
}
if (NumArgs > 0) text += ',';
}
// this is an ffi call if we need casts, and it is not a special Math_ builtin or wasm-only intrinsic
bool FFI = LegalizeJavaScriptFFI && NeedCasts;
if (FFI) {
if (IsMath && (Name == "Math_ceil" || Name == "Math_floor" || Name == "Math_min" || Name == "Math_max" || Name == "Math_sqrt" || Name == "Math_abs")) {
// This special Math builtin is optimizable with all types, including floats, so can treat it as non-ffi
FFI = false;
} else if (OnlyWebAssembly && Name == "f32_copysign") {
// f32_copysign doesn't need to use a +() coercion which an ffi would need, it's a simple f32 operation
FFI = false;
}
}
unsigned FFI_OUT = FFI ? ASM_FFI_OUT : 0;
for (int i = 0; i < NumArgs; i++) {
if (!NeedCasts) {
text += getValueAsStr(CI->getOperand(i));
} else {
text += getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT);
}
if (i < NumArgs - 1) text += ',';
}
text += ')';
// handle return value
Type *InstRT = CI->getType();
Type *ActualRT = FT->getReturnType();
if (!InstRT->isVoidTy() && ActualRT->isVoidTy()) {
// the function we are calling was cast to something returning a value, but it really
// does not return a value
getAssignIfNeeded(CI); // ensure the variable is defined, but do not emit it here
// it should have 0 uses, but just to be safe
} else if (!ActualRT->isVoidTy()) {
unsigned FFI_IN = FFI ? ASM_FFI_IN : 0;
text = '(' + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN) + ')';
// in wasm-only mode, we may have full i64s, and LLVM may bitcast them at the call site, e.g.
// %5 = call zeroext i1 bitcast (i64 (i8*, i64*, i64, i32, i32, i32)* @__atomic_compare_exchange_8 to i1 (i8*, i8*, i64, i32, i32)*)(i8* nonnull %4, i8* nonnull %3, i64 undef, i32 2, i32 2)
// in such a case we must add a truncation operation
if (OnlyWebAssembly && InstRT->isIntegerTy() && InstRT->getIntegerBitWidth() < 64 &&
ActualRT->isIntegerTy() && ActualRT->getIntegerBitWidth() == 64) {
text = "i64_trunc(" + text + ")";
}
text = getAssignIfNeeded(CI) + text;
}
return text;
})
// exceptions support
DEF_CALL_HANDLER(emscripten_preinvoke, {
UsesThrew = true;
// InvokeState is normally 0 here, but might be otherwise if a block was split apart TODO: add a function attribute for this
InvokeState = 1;
return "__THREW__ = 0";
})
DEF_CALL_HANDLER(emscripten_postinvoke, {
UsesThrew = true;
// InvokeState is normally 2 here, but can be 1 if the call in between was optimized out, or 0 if a block was split apart
InvokeState = 0;
return getAssign(CI) + "__THREW__; __THREW__ = 0";
})
DEF_CALL_HANDLER(emscripten_landingpad, {
unsigned Num = getNumArgOperands(CI);
std::string target = "__cxa_find_matching_catch_" + utostr(Num);
Declares.insert(target);
std::string Ret = getAssign(CI) + '_' + target + '(';
for (unsigned i = 1; i < Num-1; i++) { // ignore personality and cleanup XXX - we probably should not be doing that!
if (i > 1) Ret += ',';
Ret += getValueAsCastStr(CI->getOperand(i));
}
Ret += ")|0";
return Ret;
})
DEF_CALL_HANDLER(emscripten_resume, {
Declares.insert("__resumeException");
return "___resumeException(" + getValueAsCastStr(CI->getOperand(0)) + ')';
})
std::string getTempRet0() {
return "(getTempRet0() | 0)";
}
std::string setTempRet0(std::string Value) {
return "setTempRet0((" + Value + ") | 0)";
}
// setjmp support
DEF_CALL_HANDLER(emscripten_prep_setjmp, {
UsesInt32Array = true;
return getAdHocAssign("_setjmpTableSize", Type::getInt32Ty(CI->getContext())) + "4;" +
getAdHocAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "_malloc(40) | 0;" +
"HEAP32[_setjmpTable>>2]=0";
})
DEF_CALL_HANDLER(emscripten_cleanup_setjmp, {
return "_free(_setjmpTable|0)";
})
DEF_CALL_HANDLER(emscripten_setjmp, {
// env, label, table
Declares.insert("saveSetjmp");
return "_setjmpTable = _saveSetjmp(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ",_setjmpTable|0,_setjmpTableSize|0)|0;_setjmpTableSize = " + getTempRet0();
})
DEF_CALL_HANDLER(emscripten_longjmp, {
Declares.insert("longjmp");
return CH___default__(CI, "_longjmp");
})
DEF_CALL_HANDLER(emscripten_check_longjmp, {
UsesThrewValue = true;
std::string Threw = getValueAsStr(CI->getOperand(0));
std::string Target = getJSName(CI);
std::string Assign = getAssign(CI);
Declares.insert("testSetjmp");
Declares.insert("longjmp");
UsesInt32Array = true;
return "if (((" + Threw + "|0) != 0) & ((threwValue|0) != 0)) { " +
Assign + "_testSetjmp(HEAP32[" + Threw + ">>2]|0, _setjmpTable|0, _setjmpTableSize|0)|0; " +
"if ((" + Target + "|0) == 0) { _longjmp(" + Threw + "|0, threwValue|0); } " + // rethrow
setTempRet0("threwValue") + "; " +
"} else { " + Assign + "-1; }";
})
DEF_CALL_HANDLER(emscripten_get_longjmp_result, {
std::string Threw = getValueAsStr(CI->getOperand(0));
return getAssign(CI) + getTempRet0();
})
// supporting async functions, see `<emscripten>/src/library_async.js` for detail.
DEF_CALL_HANDLER(emscripten_alloc_async_context, {
Declares.insert("emscripten_alloc_async_context");
// insert sp as the 2nd parameter
return getAssign(CI) + "_emscripten_alloc_async_context(" + getValueAsStr(CI->getOperand(0)) + ",sp)|0";
})
DEF_CALL_HANDLER(emscripten_check_async, {
return getAssign(CI) + "___async";
})
// prevent unwinding the stack
// preserve the return value of the return inst
DEF_CALL_HANDLER(emscripten_do_not_unwind, {
return "sp = STACKTOP";
})
// prevent unwinding the async stack
DEF_CALL_HANDLER(emscripten_do_not_unwind_async, {
return "___async_unwind = 0";
})
DEF_CALL_HANDLER(emscripten_get_async_return_value_addr, {
return getAssign(CI) + "___async_retval";
})
// emscripten instrinsics
DEF_CALL_HANDLER(emscripten_debugger, {
CantValidate = "emscripten_debugger is used";
return "debugger";
})
DEF_CALL_HANDLER(llvm_debugtrap, {
CantValidate = "llvm.debugtrap is used";
return "debugger";
})
// i64 support
DEF_CALL_HANDLER(getHigh32, {
return getAssign(CI) + getTempRet0();
})
DEF_CALL_HANDLER(setHigh32, {
return setTempRet0(getValueAsStr(CI->getOperand(0)));
})
// XXX float handling here is not optimal
#define TO_I(low, high) \
DEF_CALL_HANDLER(low, { \
std::string Input = getValueAsStr(CI->getOperand(0)); \
if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = '+' + Input; \
return getAssign(CI) + "(~~" + Input + ")>>>0"; \
}) \
DEF_CALL_HANDLER(high, { \
std::string Input = getValueAsStr(CI->getOperand(0)); \
if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = '+' + Input; \
UsesMathAbs = UsesMathMin = UsesMathFloor = UsesMathCeil = true; \
return getAssign(CI) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (~~+Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295)) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0"; \
})
TO_I(FtoILow, FtoIHigh);
TO_I(DtoILow, DtoIHigh);
DEF_CALL_HANDLER(BDtoILow, {
UsesFloat64Array = true;
UsesInt32Array = true;
return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ';' + getAssign(CI) + "HEAP32[tempDoublePtr>>2]|0";
})
DEF_CALL_HANDLER(BDtoIHigh, {
UsesInt32Array = true;
return getAssign(CI) + "HEAP32[tempDoublePtr+4>>2]|0";
})
DEF_CALL_HANDLER(SItoF, {
std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
if (PreciseF32 && CI->getType()->isFloatTy()) {
UsesMathFround = true;
Ret = "Math_fround(" + Ret + ')';
}
return getAssign(CI) + Ret;
})
DEF_CALL_HANDLER(UItoF, {
std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
if (PreciseF32 && CI->getType()->isFloatTy()) {
UsesMathFround = true;
Ret = "Math_fround(" + Ret + ')';
}
return getAssign(CI) + Ret;
})
DEF_CALL_HANDLER(SItoD, {
return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
})
DEF_CALL_HANDLER(UItoD, {
return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
})
DEF_CALL_HANDLER(BItoD, {
UsesInt32Array = true;
UsesFloat64Array = true;
return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getOperand(0)) + ';' +
"HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getOperand(1)) + ';' +
getAssign(CI) + "+HEAPF64[tempDoublePtr>>3]";
})
// misc
DEF_CALL_HANDLER(llvm_nacl_atomic_store_i32, {
UsesInt32Array = true;
return "HEAP32[" + getValueAsStr(CI->getOperand(0)) + ">>2]=" + getValueAsStr(CI->getOperand(1));
})
#define CMPXCHG_HANDLER(name, HeapName) \
DEF_CALL_HANDLER(name, { \
if (!strcmp(HeapName, "HEAP8")) UsesInt8Array = true; \
else if (!strcmp(HeapName, "HEAP16")) UsesInt16Array = true; \
else if (!strcmp(HeapName, "HEAP32")) UsesInt32Array = true; \
const Value *P = CI->getOperand(0); \
if (EnablePthreads) { \
return getAssign(CI) + "(Atomics_compareExchange(" HeapName ", " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ")|0)"; \
} else { \
return getLoad(CI, P, CI->getType(), 0) + ';' + \
"if ((" + getCast(getJSName(CI), CI->getType()) + ") == " + getValueAsCastParenStr(CI->getOperand(1)) + ") " + \
getStore(CI, P, CI->getType(), getValueAsStr(CI->getOperand(2)), 0); \
} \
})
CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i8, "HEAP8");
CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i16, "HEAP16");
CMPXCHG_HANDLER(llvm_nacl_atomic_cmpxchg_i32, "HEAP32");
#define UNROLL_LOOP_MAX 8
#define WRITE_LOOP_MAX 128
DEF_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32, {
if (CI) {
ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3));
if (AlignInt) {
ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2));
if (LenInt) {
// we can emit inline code for this
unsigned Len = LenInt->getZExtValue();
if (Len <= WRITE_LOOP_MAX) {
unsigned Align = AlignInt->getZExtValue();
if (OnlyWebAssembly) {
// wasm
if (Align > 8) Align = 8;
else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default')
unsigned Pos = 0;
std::string Ret;
std::string Dest = getValueAsStr(CI->getOperand(0));
std::string Src = getValueAsStr(CI->getOperand(1));
unsigned Size = 8; // start by writing out i64 copies
while (Len > 0) {
// handle as much as we can in the current size
unsigned CurrLen = Size*(Len/Size);
for (unsigned Offset = 0; Offset < CurrLen; Offset += Size) {
unsigned PosOffset = Pos + Offset;
std::string Add = PosOffset == 0 ? "" : ('+' + utostr(PosOffset) + " | 0");
Ret += "; store" + utostr(Size) + '(' + Dest + Add +
",load" + utostr(Size) + '(' + Src + Add + ',' + utostr(std::min(Align, Size)) + ')' +
',' + utostr(std::min(Align, Size)) + ')';
}
Pos += CurrLen;
Len -= CurrLen;
Size /= 2;
}
return Ret;
} else {
// asm.js
if (Align > 4) Align = 4;
else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default/4')
if (Align == 1 && Len > 1 && WarnOnUnaligned) {
errs() << "emcc: warning: unaligned memcpy in " << CI->getParent()->getParent()->getName() << ':' << *CI << " (compiler's fault?)\n";
}
unsigned Pos = 0;
std::string Ret;
std::string Dest = getValueAsStr(CI->getOperand(0));
std::string Src = getValueAsStr(CI->getOperand(1));
while (Len > 0) {
// handle as much as we can in the current alignment
unsigned CurrLen = Align*(Len/Align);
unsigned Factor = CurrLen/Align;
if (Factor <= UNROLL_LOOP_MAX) {
// unroll
for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) {
unsigned PosOffset = Pos + Offset;
std::string Add = PosOffset == 0 ? "" : ('+' + utostr(PosOffset));
Ret += ';' + getHeapAccess(Dest + Add, Align) + '=' + getHeapAccess(Src + Add, Align) + "|0";
}
} else {
// emit a loop
UsedVars["dest"] = UsedVars["src"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext());
std::string Add = Pos == 0 ? "" : ('+' + utostr(Pos) + "|0");
Ret += "dest=" + Dest + Add + "; src=" + Src + Add + "; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + '=' + getHeapAccess("src", Align) + "|0; dest=dest+" + utostr(Align) + "|0; src=src+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))";
}
Pos += CurrLen;
Len -= CurrLen;
Align /= 2;
}
return Ret;
}
}
}
}
}
Declares.insert("memcpy");
return CH___default__(CI, "_memcpy", 3) + "|0";
})
DEF_CALL_HANDLER(llvm_memset_p0i8_i32, {
if (CI) {
ConstantInt *AlignInt = dyn_cast<ConstantInt>(CI->getOperand(3));
if (AlignInt) {
ConstantInt *LenInt = dyn_cast<ConstantInt>(CI->getOperand(2));
if (LenInt) {
ConstantInt *ValInt = dyn_cast<ConstantInt>(CI->getOperand(1));
if (ValInt) {
// we can emit inline code for this
unsigned Len = LenInt->getZExtValue();
if (Len <= WRITE_LOOP_MAX) {
unsigned Align = AlignInt->getZExtValue();
if (OnlyWebAssembly) {
// wasm
uint64_t Val64 = ValInt->getZExtValue();
if (Align > 8) Align = 8;
else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default')
unsigned Pos = 0;
std::string Ret;
std::string Dest = getValueAsStr(CI->getOperand(0));
std::string Src = getValueAsStr(CI->getOperand(1));
unsigned Size = 8; // start by writing out i64 copies
while (Len > 0) {
// handle as much as we can in the current size
unsigned CurrLen = Size*(Len/Size);
uint64_t FullVal = 0;
for (unsigned i = 0; i < Size; i++) {
FullVal <<= 8;
FullVal |= Val64;
}
std::string ValStr = Size < 8 ? utostr(FullVal) : emitI64Const(FullVal);
for (unsigned Offset = 0; Offset < CurrLen; Offset += Size) {
unsigned PosOffset = Pos + Offset;
std::string Add = PosOffset == 0 ? "" : ('+' + utostr(PosOffset) + "|0");
Ret += "; store" + utostr(Size) + '(' + Dest + Add + ',' + ValStr + ',' + utostr(std::min(Align, Size)) + ')';
}
Pos += CurrLen;
Len -= CurrLen;
Size /= 2;
}
return Ret;
} else {
// asm.js
unsigned Val = ValInt->getZExtValue();
if (Align > 4) Align = 4;
else if (Align == 0) Align = 1; // align 0 means 1 in memcpy and memset (unlike other places where it means 'default/4')
if (Align == 1 && Len > 1 && WarnOnUnaligned) {
errs() << "emcc: warning: unaligned memcpy in " << CI->getParent()->getParent()->getName() << ':' << *CI << " (compiler's fault?)\n";
}
unsigned Pos = 0;
std::string Ret;
std::string Dest = getValueAsStr(CI->getOperand(0));
while (Len > 0) {
// handle as much as we can in the current alignment
unsigned CurrLen = Align*(Len/Align);
unsigned FullVal = 0;
for (unsigned i = 0; i < Align; i++) {
FullVal <<= 8;
FullVal |= Val;
}
unsigned Factor = CurrLen/Align;
if (Factor <= UNROLL_LOOP_MAX) {
// unroll
for (unsigned Offset = 0; Offset < CurrLen; Offset += Align) {
unsigned PosOffset = Pos + Offset;
std::string Add = PosOffset == 0 ? "" : ('+' + utostr(PosOffset));
Ret += ';' + getHeapAccess(Dest + Add, Align) + '=' + utostr(FullVal) + "|0";
}
} else {
// emit a loop
UsedVars["dest"] = UsedVars["stop"] = Type::getInt32Ty(TheModule->getContext());
std::string Add = Pos == 0 ? "" : ('+' + utostr(Pos) + "|0");
Ret += "dest=" + Dest + Add + "; stop=dest+" + utostr(CurrLen) + "|0; do { " + getHeapAccess("dest", Align) + '=' + utostr(FullVal) + "|0; dest=dest+" + utostr(Align) + "|0; } while ((dest|0) < (stop|0))";
}
Pos += CurrLen;
Len -= CurrLen;
Align /= 2;
}
return Ret;
}
}
}
}
}
}
Declares.insert("memset");
return CH___default__(CI, "_memset", 3) + "|0";
})
DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, {
Declares.insert("memmove");
return CH___default__(CI, "_memmove", 3) + "|0";
})
DEF_CALL_HANDLER(llvm_expect_i32, {
return getAssign(CI) + getValueAsStr(CI->getOperand(0));
})
DEF_CALL_HANDLER(llvm_expect_i1, {
return getAssign(CI) + getValueAsStr(CI->getOperand(0));
})
DEF_CALL_HANDLER(llvm_dbg_declare, {
if (!EnableCyberDWARF || !EnableCyberDWARFIntrinsics)
return "";
auto VariableOffset = "0";
auto AssignedValue = cast<MetadataAsValue>(CI->getOperand(0))->getMetadata();
auto const LocalVariableMD = cast<MetadataAsValue>(CI->getOperand(1))->getMetadata();
auto const LocalVariableDI = cast<DILocalVariable>(LocalVariableMD);
auto const LocalVariableType = LocalVariableDI->getRawType();
auto const DwarfOp = cast<MetadataAsValue>(CI->getOperand(2))->getMetadata();
std::string LocalVariableName = LocalVariableDI->getName().str();
auto VarMD = utostr(getIDForMetadata(LocalVariableType))
+ ',' + VariableOffset + ',' + utostr(getIDForMetadata(DwarfOp))
+ ",\"" + LocalVariableName + '"';
if (auto const *ValAsAssign = dyn_cast<LocalAsMetadata>(AssignedValue)) {
Declares.insert("metadata_llvm_dbg_value_local");
auto LocalVarName = getJSName(ValAsAssign->getValue()->stripPointerCasts());
return "_metadata_llvm_dbg_value_local(" + LocalVarName + ',' + VarMD + ')';
} else if (auto const *ValAsAssign = dyn_cast<ConstantAsMetadata>(AssignedValue)) {
Declares.insert("metadata_llvm_dbg_value_constant");
return "_metadata_llvm_dbg_value_constant(\"" + getValueAsStr(ValAsAssign->getValue())
+ ',' + VarMD + ')';
}
return "";
})
DEF_CALL_HANDLER(llvm_dbg_value, {
if (!EnableCyberDWARF || !EnableCyberDWARFIntrinsics)
return "";
auto VariableOffset = getValueAsStr(CI->getOperand(1));
auto AssignedValue = cast<MetadataAsValue>(CI->getOperand(0))->getMetadata();
auto const LocalVariableMD = cast<MetadataAsValue>(CI->getOperand(1))->getMetadata();
auto const LocalVariableDI = cast<DILocalVariable>(LocalVariableMD);
auto const LocalVariableType = LocalVariableDI->getRawType();
auto const DwarfOp = cast<MetadataAsValue>(CI->getOperand(2))->getMetadata();
std::string LocalVariableName = LocalVariableDI->getName().str();
auto VarMD = utostr(getIDForMetadata(LocalVariableType))
+ ',' + VariableOffset + ',' + utostr(getIDForMetadata(DwarfOp))
+ ",\"" + LocalVariableName + '"';
if (auto const *ValAsAssign = dyn_cast<LocalAsMetadata>(AssignedValue)) {
Declares.insert("metadata_llvm_dbg_value_local");
auto LocalVarName = getJSName(ValAsAssign->getValue()->stripPointerCasts());
return "_metadata_llvm_dbg_value_local(" + LocalVarName + ',' + VarMD + ')';
} else if (auto const *ValAsAssign = dyn_cast<ConstantAsMetadata>(AssignedValue)) {
Declares.insert("metadata_llvm_dbg_value_constant");
return "_metadata_llvm_dbg_value_constant(\"" + getValueAsStr(ValAsAssign->getValue())
+ ',' + VarMD + ')';
}
return "";
})
DEF_CALL_HANDLER(llvm_lifetime_start, {
return "";
})
DEF_CALL_HANDLER(llvm_lifetime_end, {
return "";
})
DEF_CALL_HANDLER(llvm_lifetime_start_p0i8, {
return "";
})
DEF_CALL_HANDLER(llvm_lifetime_end_p0i8, {
return "";
})
DEF_CALL_HANDLER(llvm_invariant_start, {
return "";
})
DEF_CALL_HANDLER(llvm_invariant_end, {
return "";
})
DEF_CALL_HANDLER(llvm_invariant_start_p0i8, {
return "";
})
DEF_CALL_HANDLER(llvm_invariant_end_p0i8, {
return "";
})
DEF_CALL_HANDLER(llvm_prefetch, {
return "";
})
DEF_CALL_HANDLER(llvm_objectsize_i32_p0i8, {
return getAssign(CI) + ((cast<ConstantInt>(CI->getOperand(1)))->getZExtValue() == 0 ? "-1" : "0");
})
DEF_CALL_HANDLER(llvm_flt_rounds, {
// FLT_ROUNDS helper. We don't support setting the rounding mode dynamically,
// so it's always round-to-nearest (1).
return getAssign(CI) + '1';
})
DEF_CALL_HANDLER(bitshift64Lshr, {
Declares.insert("bitshift64Lshr");
return CH___default__(CI, "_bitshift64Lshr", 3);
})
DEF_CALL_HANDLER(bitshift64Ashr, {
Declares.insert("bitshift64Ashr");
return CH___default__(CI, "_bitshift64Ashr", 3);
})
DEF_CALL_HANDLER(bitshift64Shl, {
Declares.insert("bitshift64Shl");
return CH___default__(CI, "_bitshift64Shl", 3);
})
DEF_CALL_HANDLER(llvm_ctlz_i32, {
UsesMathClz32 = true;
return CH___default__(CI, "Math_clz32", 1);
})
DEF_CALL_HANDLER(llvm_cttz_i32, {
if (OnlyWebAssembly) {
return CH___default__(CI, "i32_cttz", 1);
}
Declares.insert("llvm_cttz_i32");
return CH___default__(CI, "_llvm_cttz_i32", 1);
})
DEF_CALL_HANDLER(llvm_ctlz_i64, {
if (OnlyWebAssembly) {
return CH___default__(CI, "i64_ctlz", 1);
}
Declares.insert("llvm_ctlz_i64");
return CH___default__(CI, "_llvm_ctlz_i64");
})
DEF_CALL_HANDLER(llvm_cttz_i64, {
if (OnlyWebAssembly) {
return CH___default__(CI, "i64_cttz", 1);
}
Declares.insert("llvm_cttz_i64");
return CH___default__(CI, "_llvm_cttz_i64");
})
DEF_CALL_HANDLER(llvm_ctpop_i32, {
if (OnlyWebAssembly) {
return CH___default__(CI, "i32_ctpop", 1);
}
Declares.insert("llvm_ctpop_i32");
return CH___default__(CI, "_llvm_ctpop_i32");
})
DEF_CALL_HANDLER(llvm_ctpop_i64, {
if (OnlyWebAssembly) {
return CH___default__(CI, "i64_ctpop", 1);
}
Declares.insert("llvm_ctpop_i64");
return CH___default__(CI, "_llvm_ctpop_i64");
})
DEF_CALL_HANDLER(llvm_copysign_f32, {
if (OnlyWebAssembly) {
return CH___default__(CI, "f32_copysign", 2);
}
Declares.insert("llvm_copysign_f32");
return CH___default__(CI, "_llvm_copysign_f32", 2);
})
DEF_CALL_HANDLER(llvm_copysign_f64, {
if (OnlyWebAssembly) {
return CH___default__(CI, "(f64_copysign)", 2); // XXX add parens as this will be +f64_copysign(...), which triggers +f64 => f64.0. TODO fix regex in emscripten.py
}
Declares.insert("llvm_copysign_f64");
return CH___default__(CI, "_llvm_copysign_f64", 2);
})
DEF_CALL_HANDLER(llvm_rint_f32, {
Declares.insert("llvm_rint_f32");
return CH___default__(CI, "_llvm_rint_f32");
})
DEF_CALL_HANDLER(llvm_rint_f64, {
Declares.insert("llvm_rint_f64");
return CH___default__(CI, "_llvm_rint_f64");
})
// EM_ASM support
// callType specifies in which thread's context a given EM_ASM block will be executed in.
enum EmAsmCallType
{
EmAsmOnCallingThread,
EmAsmSyncOnMainThread,
EmAsmAsyncOnMainThread,
};
std::string handleAsmConst(const Instruction *CI, EmAsmCallType callType) {
unsigned Num = getNumArgOperands(CI);
std::string Sig;
Sig += getFunctionSignatureLetter(CI->getType());
for (unsigned i = 1; i < Num; i++) {
Sig += getFunctionSignatureLetter(CI->getOperand(i)->getType());
}
const char *callTypeFunc;
switch(callType)
{
case EmAsmOnCallingThread: callTypeFunc = ""; break;
case EmAsmSyncOnMainThread: callTypeFunc = "sync_on_main_thread_"; break;
case EmAsmAsyncOnMainThread: callTypeFunc = "async_on_main_thread_"; break;
default: llvm_unreachable("Unsupported call type");
}
std::string func = callTypeFunc + Sig;
std::string ret = "_emscripten_asm_const_" + func + '(' + utostr(getAsmConstId(CI->getOperand(0), callTypeFunc, Sig));
for (unsigned i = 1; i < Num; i++) {
ret += ',' + getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC);
}
return ret + ')';
}
DEF_CALL_HANDLER(emscripten_asm_const, {
Declares.insert("emscripten_asm_const");
return handleAsmConst(CI, EmAsmOnCallingThread);
})
DEF_CALL_HANDLER(emscripten_asm_const_int, {
Declares.insert("emscripten_asm_const_int");
return getAssign(CI) + getCast(handleAsmConst(CI, EmAsmOnCallingThread), Type::getInt32Ty(CI->getContext()));
})
DEF_CALL_HANDLER(emscripten_asm_const_double, {
Declares.insert("emscripten_asm_const_double");
return getAssign(CI) + getCast(handleAsmConst(CI, EmAsmOnCallingThread), Type::getDoubleTy(CI->getContext()));
})
DEF_CALL_HANDLER(emscripten_asm_const_sync_on_main_thread, {
Declares.insert("emscripten_asm_const_sync_on_main_thread");
return handleAsmConst(CI, EmAsmSyncOnMainThread);
})
DEF_CALL_HANDLER(emscripten_asm_const_int_sync_on_main_thread, {
Declares.insert("emscripten_asm_const_int_sync_on_main_thread");
return getAssign(CI) + getCast(handleAsmConst(CI, EmAsmSyncOnMainThread), Type::getInt32Ty(CI->getContext()));
})
DEF_CALL_HANDLER(emscripten_asm_const_double_sync_on_main_thread, {
Declares.insert("emscripten_asm_const_double_sync_on_main_thread");
return getAssign(CI) + getCast(handleAsmConst(CI, EmAsmSyncOnMainThread), Type::getDoubleTy(CI->getContext()));
})
DEF_CALL_HANDLER(emscripten_asm_const_async_on_main_thread, {
Declares.insert("emscripten_asm_const_async_on_main_thread");
return handleAsmConst(CI, EmAsmAsyncOnMainThread);
})
DEF_CALL_HANDLER(emscripten_atomic_exchange_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_exchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_exchange_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_exchange(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_exchange_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_exchange(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_exchange_8, {
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
if (EnablePthreads) {
return getAssign(CI) + '(' + (OnlyWebAssembly ? "i64_atomics_exchange" : "_emscripten_atomic_exchange_u64") + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
} else {
return getAssign(CI) + getStore(CI, CI->getOperand(0), CI->getType(), getValueAsStr(CI->getOperand(1)), 0);
}
})
DEF_CALL_HANDLER(emscripten_atomic_cas_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_compareExchange(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_cas_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_compareExchange(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_cas_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_compareExchange(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_load_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_load(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_load_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_load(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_load_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_load(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_load_f32, {
// TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then,
// we must emulate manually.
Declares.insert("_Atomics_load_f32_emulated");
UsesMathFround = true;
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
return getAssign(CI) + (PreciseF32 ? "Math_fround(" : "+") + "__Atomics_load_f32_emulated(" + getShiftedPtr(CI->getOperand(0), 4) + (PreciseF32 ? "))" : ")");
// return getAssign(CI) + "Atomics_load(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ')';
})
DEF_CALL_HANDLER(emscripten_atomic_load_f64, {
// TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then,
// we must emulate manually.
Declares.insert("emscripten_atomic_load_f64");
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
return getAssign(CI) + "+_emscripten_atomic_load_f64(" + getShiftedPtr(CI->getOperand(0), 8) + ')';
// return getAssign(CI) + "Atomics_load(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ')';
})
DEF_CALL_HANDLER(__atomic_load_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_load";
else if (OnlyWebAssembly) op = "load8";
else op = "_emscripten_atomic_load_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_store_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_store(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_store_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_store(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_store_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_store(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_store_f32, {
// TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131613 is implemented, we could use the commented out version. Until then,
// we must emulate manually.
Declares.insert("emscripten_atomic_store_f32");
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
return getAssign(CI) + "_emscripten_atomic_store_f32(" + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
// return getAssign(CI) + "Atomics_store(HEAPF32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_atomic_store_f64, {
// TODO: If https://bugzilla.mozilla.org/show_bug.cgi?id=1131624 is implemented, we could use the commented out version. Until then,
// we must emulate manually.
Declares.insert("emscripten_atomic_store_f64");
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
return getAssign(CI) + "+_emscripten_atomic_store_f64(" + getShiftedPtr(CI->getOperand(0), 8) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
// return getAssign(CI) + "Atomics_store(HEAPF64, " + getShiftedPtr(CI->getOperand(0), 8) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(__atomic_store_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_store";
else if (OnlyWebAssembly) op = "store8";
else op = "_emscripten_atomic_store_u64";
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
return std::string("(") + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_add_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_add(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_add_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_add(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_add_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_add(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_fetch_add_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_add";
else if (OnlyWebAssembly) op = "i64_add";
else op = "__emscripten_atomic_fetch_and_add_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_sub_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_sub(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_sub_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_sub(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_sub_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_sub(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_fetch_sub_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_sub";
else if (OnlyWebAssembly) op = "i64_sub";
else op = "__emscripten_atomic_fetch_and_sub_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_and_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_and(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_and_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_and(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_and_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_and(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_fetch_and_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_and";
else if (OnlyWebAssembly) op = "i64_and";
else op = "__emscripten_atomic_fetch_and_and_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_or_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_or(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_or_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_or(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_or_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_or(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_fetch_or_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_or";
else if (OnlyWebAssembly) op = "i64_or";
else op = "__emscripten_atomic_fetch_and_or_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_xor_u8, {
UsesInt8Array = true;
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
return getAssign(CI) + "(Atomics_xor(HEAP8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_xor_u16, {
UsesInt16Array = true;
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
return getAssign(CI) + "(Atomics_xor(HEAP16, " + getShiftedPtr(CI->getOperand(0), 2) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(emscripten_atomic_xor_u32, {
UsesInt32Array = true;
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
return getAssign(CI) + "(Atomics_xor(HEAP32, " + getShiftedPtr(CI->getOperand(0), 4) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
DEF_CALL_HANDLER(__atomic_fetch_xor_8, {
const char *op;
if (EnablePthreads && OnlyWebAssembly) op = "i64_atomics_xor";
else if (OnlyWebAssembly) op = "i64_xor";
else op = "__emscripten_atomic_fetch_and_xor_u64";
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
return getAssign(CI) + '(' + op + '(' + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ")|0)";
})
#define DEF_BUILTIN_HANDLER(name, to) \
DEF_CALL_HANDLER(name, { \
return CH___default__(CI, #to); \
})
#define DEF_MATH_BUILTIN_HANDLER(name, to, usesTracker) \
DEF_CALL_HANDLER(name, { \
usesTracker = true; \
return CH___default__(CI, #to); \
})
#define DEF_MAYBE_BUILTIN_HANDLER(name, to) \
DEF_CALL_HANDLER(name, { \
if (!WebAssembly) return CH___default__(CI, #to); \
Declares.insert(#name); \
return CH___default__(CI, "_" #name); \
})
#define DEF_MATH_MAYBE_BUILTIN_HANDLER(name, to, usesTracker) \
DEF_CALL_HANDLER(name, { \
usesTracker = true; \
if (!WebAssembly) return CH___default__(CI, #to); \
Declares.insert(#name); \
return CH___default__(CI, "_" #name); \
})
// Various simple redirects for our js libc, see library.js and LibraryManager.load
DEF_MATH_BUILTIN_HANDLER(abs, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(labs, Math_abs, UsesMathAbs);
DEF_MATH_MAYBE_BUILTIN_HANDLER(cos, Math_cos, UsesMathCos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(cosf, Math_cos, UsesMathCos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(cosl, Math_cos, UsesMathCos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(sin, Math_sin, UsesMathSin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(sinf, Math_sin, UsesMathSin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(sinl, Math_sin, UsesMathSin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(tan, Math_tan, UsesMathTan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(tanf, Math_tan, UsesMathTan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(tanl, Math_tan, UsesMathTan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(acos, Math_acos, UsesMathAcos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(acosf, Math_acos, UsesMathAcos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(acosl, Math_acos, UsesMathAcos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(asin, Math_asin, UsesMathAsin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(asinf, Math_asin, UsesMathAsin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(asinl, Math_asin, UsesMathAsin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atan, Math_atan, UsesMathAtan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atanf, Math_atan, UsesMathAtan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atanl, Math_atan, UsesMathAtan);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atan2, Math_atan2, UsesMathAtan2);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atan2f, Math_atan2, UsesMathAtan2);
DEF_MATH_MAYBE_BUILTIN_HANDLER(atan2l, Math_atan2, UsesMathAtan2);
DEF_MATH_MAYBE_BUILTIN_HANDLER(exp, Math_exp, UsesMathExp);
DEF_MATH_MAYBE_BUILTIN_HANDLER(expf, Math_exp, UsesMathExp);
DEF_MATH_MAYBE_BUILTIN_HANDLER(expl, Math_exp, UsesMathExp);
DEF_MATH_MAYBE_BUILTIN_HANDLER(log, Math_log, UsesMathLog);
DEF_MATH_MAYBE_BUILTIN_HANDLER(logf, Math_log, UsesMathLog);
DEF_MATH_MAYBE_BUILTIN_HANDLER(logl, Math_log, UsesMathLog);
DEF_MATH_BUILTIN_HANDLER(sqrt, Math_sqrt, UsesMathSqrt);
DEF_MATH_BUILTIN_HANDLER(sqrtf, Math_sqrt, UsesMathSqrt);
DEF_MATH_BUILTIN_HANDLER(sqrtl, Math_sqrt, UsesMathSqrt);
DEF_MATH_BUILTIN_HANDLER(fabs, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(fabsf, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(fabsl, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(llvm_fabs_f32, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(llvm_fabs_f64, Math_abs, UsesMathAbs);
DEF_MATH_BUILTIN_HANDLER(ceil, Math_ceil, UsesMathCeil);
DEF_MATH_BUILTIN_HANDLER(ceilf, Math_ceil, UsesMathCeil);
DEF_MATH_BUILTIN_HANDLER(ceill, Math_ceil, UsesMathCeil);
DEF_MATH_BUILTIN_HANDLER(llvm_ceil_f32, Math_ceil, UsesMathCeil);
DEF_MATH_BUILTIN_HANDLER(llvm_ceil_f64, Math_ceil, UsesMathCeil);
DEF_MATH_BUILTIN_HANDLER(floor, Math_floor, UsesMathFloor);
DEF_MATH_BUILTIN_HANDLER(floorf, Math_floor, UsesMathFloor);
DEF_MATH_BUILTIN_HANDLER(floorl, Math_floor, UsesMathFloor);
DEF_MATH_BUILTIN_HANDLER(llvm_floor_f32, Math_floor, UsesMathFloor);
DEF_MATH_BUILTIN_HANDLER(llvm_floor_f64, Math_floor, UsesMathFloor);
DEF_MATH_MAYBE_BUILTIN_HANDLER(pow, Math_pow, UsesMathPow);
DEF_MATH_MAYBE_BUILTIN_HANDLER(powf, Math_pow, UsesMathPow);
DEF_MATH_MAYBE_BUILTIN_HANDLER(powl, Math_pow, UsesMathPow);
DEF_MATH_BUILTIN_HANDLER(llvm_sqrt_f32, Math_sqrt, UsesMathSqrt);
DEF_MATH_BUILTIN_HANDLER(llvm_sqrt_f64, Math_sqrt, UsesMathSqrt);
DEF_MATH_BUILTIN_HANDLER(llvm_pow_f32, Math_pow, UsesMathPow); // XXX these will be slow in wasm, but need to link in libc before getting here, or stop
DEF_MATH_BUILTIN_HANDLER(llvm_pow_f64, Math_pow, UsesMathPow); // LLVM from creating these intrinsics
DEF_MATH_MAYBE_BUILTIN_HANDLER(llvm_cos_f32, Math_cos, UsesMathCos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(llvm_cos_f64, Math_cos, UsesMathCos);
DEF_MATH_MAYBE_BUILTIN_HANDLER(llvm_sin_f32, Math_sin, UsesMathSin);
DEF_MATH_MAYBE_BUILTIN_HANDLER(llvm_sin_f64, Math_sin, UsesMathSin);
// The NaN semantics of llvm_[min|max]num_* do not quite match what asm.js and wasm's float min/max do, sadly
DEF_CALL_HANDLER(llvm_powi_f32, {
UsesMathPow = true;
return getAssign(CI) + getParenCast("Math_pow(" + getValueAsCastStr(CI->getOperand(0)) + ',' + getCast(getValueAsCastStr(CI->getOperand(1)), CI->getOperand(0)->getType()) + ')', CI->getType());
})
DEF_CALL_HANDLER(llvm_powi_f64, {
UsesMathPow = true;
return getAssign(CI) + getParenCast("Math_pow(" + getValueAsCastStr(CI->getOperand(0)) + ',' + getCast(getValueAsCastStr(CI->getOperand(1)), CI->getOperand(0)->getType()) + ')', CI->getType());
})
DEF_MATH_BUILTIN_HANDLER(llvm_log_f32, Math_log, UsesMathLog);
DEF_MATH_BUILTIN_HANDLER(llvm_log_f64, Math_log, UsesMathLog);
DEF_MATH_BUILTIN_HANDLER(llvm_exp_f32, Math_exp, UsesMathExp);
DEF_MATH_BUILTIN_HANDLER(llvm_exp_f64, Math_exp, UsesMathExp);
// SIMD.js Float64x2
DEF_BUILTIN_HANDLER(emscripten_float64x2_set, SIMD_Float64x2);
DEF_BUILTIN_HANDLER(emscripten_float64x2_splat, SIMD_Float64x2_splat);
DEF_BUILTIN_HANDLER(emscripten_float64x2_add, SIMD_Float64x2_add);
DEF_BUILTIN_HANDLER(emscripten_float64x2_sub, SIMD_Float64x2_sub);
DEF_BUILTIN_HANDLER(emscripten_float64x2_mul, SIMD_Float64x2_mul);
DEF_BUILTIN_HANDLER(emscripten_float64x2_div, SIMD_Float64x2_div);
DEF_BUILTIN_HANDLER(emscripten_float64x2_max, SIMD_Float64x2_max);
DEF_BUILTIN_HANDLER(emscripten_float64x2_min, SIMD_Float64x2_min);
DEF_BUILTIN_HANDLER(emscripten_float64x2_maxNum, SIMD_Float64x2_maxNum);
DEF_BUILTIN_HANDLER(emscripten_float64x2_minNum, SIMD_Float64x2_minNum);
DEF_BUILTIN_HANDLER(emscripten_float64x2_neg, SIMD_Float64x2_neg);
DEF_BUILTIN_HANDLER(emscripten_float64x2_sqrt, SIMD_Float64x2_sqrt);
DEF_BUILTIN_HANDLER(emscripten_float64x2_reciprocalApproximation, SIMD_Float64x2_reciprocalApproximation);
DEF_BUILTIN_HANDLER(emscripten_float64x2_reciprocalSqrtApproximation, SIMD_Float64x2_reciprocalSqrtApproximation);
DEF_BUILTIN_HANDLER(emscripten_float64x2_abs, SIMD_Float64x2_abs);
// n.b. No emscripten_float64x2_and, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_xor, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_or, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_not, only defined on boolean and integer SIMD types.
static std::string castBool64x2ToInt32x4(const std::string &valueStr) {
return std::string("SIMD_Int32x4_fromBool64x2Bits(") + valueStr + ')';
}
DEF_CALL_HANDLER(emscripten_float64x2_lessThan, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_lessThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
DEF_CALL_HANDLER(emscripten_float64x2_lessThanOrEqual, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_lessThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
DEF_CALL_HANDLER(emscripten_float64x2_greaterThan, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_greaterThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
DEF_CALL_HANDLER(emscripten_float64x2_greaterThanOrEqual, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_greaterThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
DEF_CALL_HANDLER(emscripten_float64x2_equal, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_equal(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
DEF_CALL_HANDLER(emscripten_float64x2_notEqual, {
return getAssign(CI) + castBool64x2ToInt32x4("SIMD_Float64x2_notEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')');
})
// n.b. No emscripten_float64x2_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_float64x2_allTrue, only defined on boolean SIMD types.
DEF_BUILTIN_HANDLER(emscripten_float64x2_select, SIMD_Float64x2_select);
// n.b. No emscripten_float64x2_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float64x2_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float64x2_shiftLeftByScalar, only defined on integer SIMD types.
// n.b. No emscripten_float64x2_shiftRightByScalar, only defined on integer SIMD types.
DEF_BUILTIN_HANDLER(emscripten_float64x2_extractLane, SIMD_Float64x2_extractLane);
DEF_BUILTIN_HANDLER(emscripten_float64x2_replaceLane, SIMD_Float64x2_replaceLane);
DEF_CALL_HANDLER(emscripten_float64x2_store, {
UsesSIMDFloat64x2 = true;
UsesUint8Array = true;
return "SIMD_Float64x2_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float64x2_store1, {
UsesSIMDFloat64x2 = true;
UsesUint8Array = true;
return "SIMD_Float64x2_store1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float64x2_load, {
UsesSIMDFloat64x2 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float64x2_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_float64x2_load1, {
UsesSIMDFloat64x2 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float64x2_load1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromFloat32x4Bits, SIMD_Float64x2_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromInt32x4Bits, SIMD_Float64x2_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromUint32x4Bits, SIMD_Float64x2_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromInt16x8Bits, SIMD_Float64x2_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromUint16x8Bits, SIMD_Float64x2_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromInt8x16Bits, SIMD_Float64x2_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_fromUint8x16Bits, SIMD_Float64x2_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_float64x2_swizzle, SIMD_Float64x2_swizzle);
DEF_BUILTIN_HANDLER(emscripten_float64x2_shuffle, SIMD_Float64x2_shuffle);
// SIMD.js Float32x4
DEF_BUILTIN_HANDLER(emscripten_float32x4_set, SIMD_Float32x4);
DEF_BUILTIN_HANDLER(emscripten_float32x4_splat, SIMD_Float32x4_splat);
DEF_BUILTIN_HANDLER(emscripten_float32x4_add, SIMD_Float32x4_add);
DEF_BUILTIN_HANDLER(emscripten_float32x4_sub, SIMD_Float32x4_sub);
DEF_BUILTIN_HANDLER(emscripten_float32x4_mul, SIMD_Float32x4_mul);
DEF_BUILTIN_HANDLER(emscripten_float32x4_div, SIMD_Float32x4_div);
DEF_BUILTIN_HANDLER(emscripten_float32x4_max, SIMD_Float32x4_max);
DEF_BUILTIN_HANDLER(emscripten_float32x4_min, SIMD_Float32x4_min);
DEF_BUILTIN_HANDLER(emscripten_float32x4_maxNum, SIMD_Float32x4_maxNum);
DEF_BUILTIN_HANDLER(emscripten_float32x4_minNum, SIMD_Float32x4_minNum);
DEF_BUILTIN_HANDLER(emscripten_float32x4_neg, SIMD_Float32x4_neg);
DEF_BUILTIN_HANDLER(emscripten_float32x4_sqrt, SIMD_Float32x4_sqrt);
DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalApproximation, SIMD_Float32x4_reciprocalApproximation);
DEF_BUILTIN_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation, SIMD_Float32x4_reciprocalSqrtApproximation);
DEF_BUILTIN_HANDLER(emscripten_float32x4_abs, SIMD_Float32x4_abs);
// n.b. No emscripten_float32x4_and, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_xor, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_or, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_not, only defined on boolean and integer SIMD types.
std::string castBoolVecToIntVec(int numElems, const std::string &str, bool signExtend)
{
int elemWidth = 128 / numElems;
std::string simdType = "SIMD_Int" + llvm::to_string(elemWidth) + 'x' + llvm::to_string(numElems);
return simdType + "_select(" + str + ',' + simdType + "_splat(" + (signExtend ? "-1" : "1") + "), " + simdType + "_splat(0))";
}
DEF_CALL_HANDLER(emscripten_float32x4_lessThan, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_lessThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_lessThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_float32x4_greaterThan, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_greaterThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_greaterThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_float32x4_equal, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_equal(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_float32x4_notEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Float32x4_notEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
// n.b. No emscripten_float32x4_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_float32x4_allTrue, only defined on boolean SIMD types.
DEF_CALL_HANDLER(emscripten_float32x4_select, {
// FIXME: We really need a more general way of handling boolean types,
// including an optimization to allow more Int32x4 operations to be
// translated as Bool32x4 operations.
std::string Op;
if (SExtInst *SE = dyn_cast<SExtInst>(CI->getOperand(0))) {
Op = getValueAsStr(SE->getOperand(0));
} else {
Op = "SIMD_Int32x4_notEqual(" + getValueAsStr(CI->getOperand(0)) + ", SIMD_Int32x4_splat(0))";
}
return getAssign(CI) + "SIMD_Float32x4_select(" + Op + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ')';
})
// n.b. No emscripten_float32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float32x4_shiftLeftByScalar, only defined on integer SIMD types.
// n.b. No emscripten_float32x4_shiftRightByScalar, only defined on integer SIMD types.
DEF_BUILTIN_HANDLER(emscripten_float32x4_extractLane, SIMD_Float32x4_extractLane);
DEF_BUILTIN_HANDLER(emscripten_float32x4_replaceLane, SIMD_Float32x4_replaceLane);
DEF_CALL_HANDLER(emscripten_float32x4_store, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return "SIMD_Float32x4_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_store1, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return "SIMD_Float32x4_store1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_store2, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return "SIMD_Float32x4_store2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_store3, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return "SIMD_Float32x4_store3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_load, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float32x4_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_load1, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float32x4_load1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_load2, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float32x4_load2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_float32x4_load3, {
UsesSIMDFloat32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Float32x4_load3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromFloat64x2Bits, SIMD_Float32x4_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4Bits, SIMD_Float32x4_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromUint32x4Bits, SIMD_Float32x4_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt16x8Bits, SIMD_Float32x4_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromUint16x8Bits, SIMD_Float32x4_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt8x16Bits, SIMD_Float32x4_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromUint8x16Bits, SIMD_Float32x4_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromInt32x4, SIMD_Float32x4_fromInt32x4);
DEF_BUILTIN_HANDLER(emscripten_float32x4_fromUint32x4, SIMD_Float32x4_fromUint32x4);
DEF_BUILTIN_HANDLER(emscripten_float32x4_swizzle, SIMD_Float32x4_swizzle);
DEF_BUILTIN_HANDLER(emscripten_float32x4_shuffle, SIMD_Float32x4_shuffle);
// SIMD.js Int32x4
DEF_BUILTIN_HANDLER(emscripten_int32x4_set, SIMD_Int32x4);
DEF_BUILTIN_HANDLER(emscripten_int32x4_splat, SIMD_Int32x4_splat);
DEF_BUILTIN_HANDLER(emscripten_int32x4_add, SIMD_Int32x4_add);
DEF_BUILTIN_HANDLER(emscripten_int32x4_sub, SIMD_Int32x4_sub);
DEF_BUILTIN_HANDLER(emscripten_int32x4_mul, SIMD_Int32x4_mul);
// n.b. No emscripten_int32x4_div, division is only defined on floating point types.
// n.b. No emscripten_int32x4_max, only defined on floating point types.
// n.b. No emscripten_int32x4_min, only defined on floating point types.
// n.b. No emscripten_int32x4_maxNum, only defined on floating point types.
// n.b. No emscripten_int32x4_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int32x4_neg, SIMD_Int32x4_neg);
// n.b. No emscripten_int32x4_sqrt, only defined on floating point types.
// n.b. No emscripten_int32x4_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int32x4_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int32x4_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int32x4_and, SIMD_Int32x4_and);
DEF_BUILTIN_HANDLER(emscripten_int32x4_xor, SIMD_Int32x4_xor);
DEF_BUILTIN_HANDLER(emscripten_int32x4_or, SIMD_Int32x4_or);
DEF_BUILTIN_HANDLER(emscripten_int32x4_not, SIMD_Int32x4_not);
DEF_CALL_HANDLER(emscripten_int32x4_lessThan, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_lessThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_lessThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_lessThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_greaterThan, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_greaterThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_greaterThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_greaterThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_equal, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_equal(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_notEqual, {
return getAssign(CI) + castBoolVecToIntVec(4, "SIMD_Int32x4_notEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int32x4_select, {
// FIXME: We really need a more general way of handling boolean types,
// including an optimization to allow more Int32x4 operations to be
// translated as Bool32x4 operations.
std::string Op;
if (SExtInst *SE = dyn_cast<SExtInst>(CI->getOperand(0))) {
Op = getValueAsStr(SE->getOperand(0));
} else {
Op = "SIMD_Int32x4_notEqual(" + getValueAsStr(CI->getOperand(0)) + ", SIMD_Int32x4_splat(0))";
}
return getAssign(CI) + "SIMD_Int32x4_select(" + Op + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ')';
})
// n.b. No emscripten_int32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_int32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
DEF_BUILTIN_HANDLER(emscripten_int32x4_shiftLeftByScalar, SIMD_Int32x4_shiftLeftByScalar);
DEF_BUILTIN_HANDLER(emscripten_int32x4_shiftRightByScalar, SIMD_Int32x4_shiftRightByScalar);
DEF_BUILTIN_HANDLER(emscripten_int32x4_extractLane, SIMD_Int32x4_extractLane);
DEF_BUILTIN_HANDLER(emscripten_int32x4_replaceLane, SIMD_Int32x4_replaceLane);
DEF_CALL_HANDLER(emscripten_int32x4_store, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return "SIMD_Int32x4_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_store1, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return "SIMD_Int32x4_store1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_store2, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return "SIMD_Int32x4_store2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_store3, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return "SIMD_Int32x4_store3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_load, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int32x4_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_load1, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int32x4_load1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_load2, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int32x4_load2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_int32x4_load3, {
UsesSIMDInt32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int32x4_load3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat64x2Bits, SIMD_Int32x4_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4Bits, SIMD_Int32x4_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromUint32x4Bits, SIMD_Int32x4_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromInt16x8Bits, SIMD_Int32x4_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromUint16x8Bits, SIMD_Int32x4_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromInt8x16Bits, SIMD_Int32x4_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromUint8x16Bits, SIMD_Int32x4_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromFloat32x4, SIMD_Int32x4_fromFloat32x4);
DEF_BUILTIN_HANDLER(emscripten_int32x4_fromUint32x4, SIMD_Int32x4_fromUint32x4);
// TODO: emscripten_int32x4_fromFloat64x2?
DEF_BUILTIN_HANDLER(emscripten_int32x4_swizzle, SIMD_Int32x4_swizzle);
DEF_BUILTIN_HANDLER(emscripten_int32x4_shuffle, SIMD_Int32x4_shuffle);
// SIMD.js Uint32x4
DEF_BUILTIN_HANDLER(emscripten_uint32x4_set, SIMD_Uint32x4);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_splat, SIMD_Uint32x4_splat);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_add, SIMD_Uint32x4_add);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_sub, SIMD_Uint32x4_sub);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_mul, SIMD_Uint32x4_mul);
// n.b. No emscripten_uint32x4_div, division is only defined on floating point types.
// n.b. No emscripten_uint32x4_max, only defined on floating point types.
// n.b. No emscripten_uint32x4_min, only defined on floating point types.
// n.b. No emscripten_uint32x4_maxNum, only defined on floating point types.
// n.b. No emscripten_uint32x4_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint32x4_neg, SIMD_Uint32x4_neg);
// n.b. No emscripten_uint32x4_sqrt, only defined on floating point types.
// n.b. No emscripten_uint32x4_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint32x4_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint32x4_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint32x4_and, SIMD_Uint32x4_and);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_xor, SIMD_Uint32x4_xor);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_or, SIMD_Uint32x4_or);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_not, SIMD_Uint32x4_not);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_lessThan, SIMD_Uint32x4_lessThan);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_lessThanOrEqual, SIMD_Uint32x4_lessThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_greaterThan, SIMD_Uint32x4_greaterThan);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_greaterThanOrEqual, SIMD_Uint32x4_greaterThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_equal, SIMD_Uint32x4_equal);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_notEqual, SIMD_Uint32x4_notEqual);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_select, SIMD_Uint32x4_select);
// n.b. No emscripten_uint32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_uint32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
DEF_BUILTIN_HANDLER(emscripten_uint32x4_shiftLeftByScalar, SIMD_Uint32x4_shiftLeftByScalar);
DEF_CALL_HANDLER(emscripten_uint32x4_shiftRightByScalar, {
UsesSIMDUint32x4 = true;
UsesSIMDInt32x4 = true;
return getAssign(CI) + "SIMD_Int32x4_fromUint32x4Bits(SIMD_Uint32x4_shiftRightByScalar(SIMD_Uint32x4_fromInt32x4Bits(" + getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + "))";
})
DEF_BUILTIN_HANDLER(emscripten_uint32x4_extractLane, SIMD_Uint32x4_extractLane);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_replaceLane, SIMD_Uint32x4_replaceLane);
DEF_CALL_HANDLER(emscripten_uint32x4_store, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return "SIMD_Uint32x4_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_store1, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return "SIMD_Uint32x4_store1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_store2, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return "SIMD_Uint32x4_store2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_store3, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return "SIMD_Uint32x4_store3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ',' + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_load, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Uint32x4_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_load1, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Uint32x4_load1(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_load2, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Uint32x4_load2(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_CALL_HANDLER(emscripten_uint32x4_load3, {
UsesSIMDUint32x4 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Uint32x4_load3(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromFloat64x2Bits, SIMD_Uint32x4_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromFloat32x4Bits, SIMD_Uint32x4_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromInt32x4Bits, SIMD_Uint32x4_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromInt16x8Bits, SIMD_Uint32x4_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromUint16x8Bits, SIMD_Uint32x4_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromInt8x16Bits, SIMD_Uint32x4_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromUint8x16Bits, SIMD_Uint32x4_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromFloat32x4, SIMD_Uint32x4_fromFloat32x4);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_fromInt32x4, SIMD_Uint32x4_fromInt32x4);
// TODO: emscripten_uint32x4_fromFloat64x2?
DEF_BUILTIN_HANDLER(emscripten_uint32x4_swizzle, SIMD_Uint32x4_swizzle);
DEF_BUILTIN_HANDLER(emscripten_uint32x4_shuffle, SIMD_Uint32x4_shuffle);
// SIMD.js Int16x8
DEF_BUILTIN_HANDLER(emscripten_int16x8_set, SIMD_Int16x8);
DEF_BUILTIN_HANDLER(emscripten_int16x8_splat, SIMD_Int16x8_splat);
DEF_BUILTIN_HANDLER(emscripten_int16x8_add, SIMD_Int16x8_add);
DEF_BUILTIN_HANDLER(emscripten_int16x8_sub, SIMD_Int16x8_sub);
DEF_BUILTIN_HANDLER(emscripten_int16x8_mul, SIMD_Int16x8_mul);
// n.b. No emscripten_int16x8_div, division is only defined on floating point types.
// n.b. No emscripten_int16x8_max, only defined on floating point types.
// n.b. No emscripten_int16x8_min, only defined on floating point types.
// n.b. No emscripten_int16x8_maxNum, only defined on floating point types.
// n.b. No emscripten_int16x8_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int16x8_neg, SIMD_Int16x8_neg);
// n.b. No emscripten_int16x8_sqrt, only defined on floating point types.
// n.b. No emscripten_int16x8_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int16x8_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int16x8_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int16x8_and, SIMD_Int16x8_and);
DEF_BUILTIN_HANDLER(emscripten_int16x8_xor, SIMD_Int16x8_xor);
DEF_BUILTIN_HANDLER(emscripten_int16x8_or, SIMD_Int16x8_or);
DEF_BUILTIN_HANDLER(emscripten_int16x8_not, SIMD_Int16x8_not);
DEF_CALL_HANDLER(emscripten_int16x8_lessThan, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_lessThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_lessThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_lessThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_greaterThan, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_greaterThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_greaterThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_greaterThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_equal, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_equal(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_notEqual, {
return getAssign(CI) + castBoolVecToIntVec(8, "SIMD_Int16x8_notEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int16x8_select, {
// FIXME: We really need a more general way of handling boolean types,
// including an optimization to allow more Int16x8 operations to be
// translated as Bool16x8 operations.
std::string Op;
if (SExtInst *SE = dyn_cast<SExtInst>(CI->getOperand(0))) {
Op = getValueAsStr(SE->getOperand(0));
} else {
Op = "SIMD_Int16x8_notEqual(" + getValueAsStr(CI->getOperand(0)) + ", SIMD_Int16x8_splat(0))";
}
return getAssign(CI) + "SIMD_Int16x8_select(" + Op + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_int16x8_addSaturate, SIMD_Int16x8_addSaturate);
DEF_BUILTIN_HANDLER(emscripten_int16x8_subSaturate, SIMD_Int16x8_subSaturate);
DEF_BUILTIN_HANDLER(emscripten_int16x8_shiftLeftByScalar, SIMD_Int16x8_shiftLeftByScalar);
DEF_BUILTIN_HANDLER(emscripten_int16x8_shiftRightByScalar, SIMD_Int16x8_shiftRightByScalar);
DEF_BUILTIN_HANDLER(emscripten_int16x8_extractLane, SIMD_Int16x8_extractLane);
DEF_BUILTIN_HANDLER(emscripten_int16x8_replaceLane, SIMD_Int16x8_replaceLane);
DEF_CALL_HANDLER(emscripten_int16x8_store, {
UsesSIMDInt16x8 = true;
UsesUint8Array = true;
return "SIMD_Int16x8_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int16x8_load, {
UsesSIMDInt16x8 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int16x8_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromFloat64x2Bits, SIMD_Int16x8_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromFloat32x4Bits, SIMD_Int16x8_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromInt32x4Bits, SIMD_Int16x8_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromUint32x4Bits, SIMD_Int16x8_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromUint16x8Bits, SIMD_Int16x8_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromInt8x16Bits, SIMD_Int16x8_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromUint8x16Bits, SIMD_Int16x8_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_int16x8_fromUint16x8, SIMD_Int16x8_fromUint16x8);
DEF_BUILTIN_HANDLER(emscripten_int16x8_swizzle, SIMD_Int16x8_swizzle);
DEF_BUILTIN_HANDLER(emscripten_int16x8_shuffle, SIMD_Int16x8_shuffle);
// SIMD.js Uint16x8
DEF_BUILTIN_HANDLER(emscripten_uint16x8_set, SIMD_Uint16x8);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_splat, SIMD_Uint16x8_splat);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_add, SIMD_Uint16x8_add);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_sub, SIMD_Uint16x8_sub);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_mul, SIMD_Uint16x8_mul);
// n.b. No emscripten_uint16x8_div, division is only defined on floating point types.
// n.b. No emscripten_uint16x8_max, only defined on floating point types.
// n.b. No emscripten_uint16x8_min, only defined on floating point types.
// n.b. No emscripten_uint16x8_maxNum, only defined on floating point types.
// n.b. No emscripten_uint16x8_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint16x8_neg, SIMD_Uint16x8_neg);
// n.b. No emscripten_uint16x8_sqrt, only defined on floating point types.
// n.b. No emscripten_uint16x8_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint16x8_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint16x8_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint16x8_and, SIMD_Uint16x8_and);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_xor, SIMD_Uint16x8_xor);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_or, SIMD_Uint16x8_or);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_not, SIMD_Uint16x8_not);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_lessThan, SIMD_Uint16x8_lessThan);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_lessThanOrEqual, SIMD_Uint16x8_lessThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_greaterThan, SIMD_Uint16x8_greaterThan);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_greaterThanOrEqual, SIMD_Uint16x8_greaterThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_equal, SIMD_Uint16x8_equal);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_notEqual, SIMD_Uint16x8_notEqual);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_select, SIMD_Uint16x8_select);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_addSaturate, SIMD_Uint16x8_addSaturate);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_subSaturate, SIMD_Uint16x8_subSaturate);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_shiftLeftByScalar, SIMD_Uint16x8_shiftLeftByScalar);
DEF_CALL_HANDLER(emscripten_uint16x8_shiftRightByScalar, {
UsesSIMDInt16x8 = true;
UsesSIMDUint16x8 = true;
return getAssign(CI) + "SIMD_Int16x8_fromUint16x8Bits(SIMD_Uint16x8_shiftRightByScalar(SIMD_Uint16x8_fromInt16x8Bits(" + getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + "))";
})
DEF_BUILTIN_HANDLER(emscripten_uint16x8_extractLane, SIMD_Uint16x8_extractLane);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_replaceLane, SIMD_Uint16x8_replaceLane);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_store, SIMD_Uint16x8_store);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_load, SIMD_Uint16x8_load);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromFloat64x2Bits, SIMD_Uint16x8_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromFloat32x4Bits, SIMD_Uint16x8_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromInt32x4Bits, SIMD_Uint16x8_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromUint32x4Bits, SIMD_Uint16x8_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromInt16x8Bits, SIMD_Uint16x8_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromInt8x16Bits, SIMD_Uint16x8_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromUint8x16Bits, SIMD_Uint16x8_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_fromInt16x8, SIMD_Uint16x8_fromInt16x8);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_swizzle, SIMD_Uint16x8_swizzle);
DEF_BUILTIN_HANDLER(emscripten_uint16x8_shuffle, SIMD_Uint16x8_shuffle);
// SIMD.js Int8x16
DEF_BUILTIN_HANDLER(emscripten_int8x16_set, SIMD_Int8x16);
DEF_BUILTIN_HANDLER(emscripten_int8x16_splat, SIMD_Int8x16_splat);
DEF_BUILTIN_HANDLER(emscripten_int8x16_add, SIMD_Int8x16_add);
DEF_BUILTIN_HANDLER(emscripten_int8x16_sub, SIMD_Int8x16_sub);
DEF_BUILTIN_HANDLER(emscripten_int8x16_mul, SIMD_Int8x16_mul);
// n.b. No emscripten_int8x16_div, division is only defined on floating point types.
// n.b. No emscripten_int8x16_max, only defined on floating point types.
// n.b. No emscripten_int8x16_min, only defined on floating point types.
// n.b. No emscripten_int8x16_maxNum, only defined on floating point types.
// n.b. No emscripten_int8x16_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int8x16_neg, SIMD_Int8x16_neg);
// n.b. No emscripten_int8x16_sqrt, only defined on floating point types.
// n.b. No emscripten_int8x16_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int8x16_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int8x16_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_int8x16_and, SIMD_Int8x16_and);
DEF_BUILTIN_HANDLER(emscripten_int8x16_xor, SIMD_Int8x16_xor);
DEF_BUILTIN_HANDLER(emscripten_int8x16_or, SIMD_Int8x16_or);
DEF_BUILTIN_HANDLER(emscripten_int8x16_not, SIMD_Int8x16_not);
DEF_CALL_HANDLER(emscripten_int8x16_lessThan, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_lessThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_lessThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_lessThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_greaterThan, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_greaterThan(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_greaterThanOrEqual, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_greaterThanOrEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_equal, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_equal(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_notEqual, {
return getAssign(CI) + castBoolVecToIntVec(16, "SIMD_Int8x16_notEqual(" + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')', true);
})
DEF_CALL_HANDLER(emscripten_int8x16_select, {
// FIXME: We really need a more general way of handling boolean types,
// including an optimization to allow more Int8x16 operations to be
// translated as Bool8x16 operations.
std::string Op;
if (SExtInst *SE = dyn_cast<SExtInst>(CI->getOperand(0))) {
Op = getValueAsStr(SE->getOperand(0));
} else {
Op = "SIMD_Int8x16_notEqual(" + getValueAsStr(CI->getOperand(0)) + ", SIMD_Int8x16_splat(0))";
}
return getAssign(CI) + "SIMD_Int8x16_select(" + Op + ',' + getValueAsStr(CI->getOperand(1)) + ',' + getValueAsStr(CI->getOperand(2)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_int8x16_addSaturate, SIMD_Int8x16_addSaturate);
DEF_BUILTIN_HANDLER(emscripten_int8x16_subSaturate, SIMD_Int8x16_subSaturate);
DEF_BUILTIN_HANDLER(emscripten_int8x16_shiftLeftByScalar, SIMD_Int8x16_shiftLeftByScalar);
DEF_BUILTIN_HANDLER(emscripten_int8x16_shiftRightByScalar, SIMD_Int8x16_shiftRightByScalar);
DEF_BUILTIN_HANDLER(emscripten_int8x16_extractLane, SIMD_Int8x16_extractLane);
DEF_BUILTIN_HANDLER(emscripten_int8x16_replaceLane, SIMD_Int8x16_replaceLane);
DEF_CALL_HANDLER(emscripten_int8x16_store, {
UsesSIMDInt8x16 = true;
UsesUint8Array = true;
return "SIMD_Int8x16_store(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ',' + getValueAsStr(CI->getOperand(1)) + ')';
})
DEF_CALL_HANDLER(emscripten_int8x16_load, {
UsesSIMDInt8x16 = true;
UsesUint8Array = true;
return getAssign(CI) + "SIMD_Int8x16_load(HEAPU8, " + getValueAsStr(CI->getOperand(0)) + ')';
})
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromFloat64x2Bits, SIMD_Int8x16_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromFloat32x4Bits, SIMD_Int8x16_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromInt32x4Bits, SIMD_Int8x16_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromUint32x4Bits, SIMD_Int8x16_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromInt16x8Bits, SIMD_Int8x16_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromUint16x8Bits, SIMD_Int8x16_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromUint8x16Bits, SIMD_Int8x16_fromUint8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_int8x16_fromUint8x16, SIMD_Int8x16_fromUint8x16);
DEF_BUILTIN_HANDLER(emscripten_int8x16_swizzle, SIMD_Int8x16_swizzle);
DEF_BUILTIN_HANDLER(emscripten_int8x16_shuffle, SIMD_Int8x16_shuffle);
// SIMD.js Uint8x16
DEF_BUILTIN_HANDLER(emscripten_uint8x16_set, SIMD_Uint8x16);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_splat, SIMD_Uint8x16_splat);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_add, SIMD_Uint8x16_add);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_sub, SIMD_Uint8x16_sub);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_mul, SIMD_Uint8x16_mul);
// n.b. No emscripten_uint8x16_div, division is only defined on floating point types.
// n.b. No emscripten_uint8x16_max, only defined on floating point types.
// n.b. No emscripten_uint8x16_min, only defined on floating point types.
// n.b. No emscripten_uint8x16_maxNum, only defined on floating point types.
// n.b. No emscripten_uint8x16_minNum, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint8x16_neg, SIMD_Uint8x16_neg);
// n.b. No emscripten_uint8x16_sqrt, only defined on floating point types.
// n.b. No emscripten_uint8x16_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint8x16_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint8x16_abs, only defined on floating point types.
DEF_BUILTIN_HANDLER(emscripten_uint8x16_and, SIMD_Uint8x16_and);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_xor, SIMD_Uint8x16_xor);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_or, SIMD_Uint8x16_or);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_not, SIMD_Uint8x16_not);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_lessThan, SIMD_Uint8x16_lessThan);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_lessThanOrEqual, SIMD_Uint8x16_lessThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_greaterThan, SIMD_Uint8x16_greaterThan);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_greaterThanOrEqual, SIMD_Uint8x16_greaterThanOrEqual);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_equal, SIMD_Uint8x16_equal);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_notEqual, SIMD_Uint8x16_notEqual);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_select, SIMD_Uint8x16_select);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_addSaturate, SIMD_Uint8x16_addSaturate);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_subSaturate, SIMD_Uint8x16_subSaturate);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_shiftLeftByScalar, SIMD_Uint8x16_shiftLeftByScalar);
DEF_CALL_HANDLER(emscripten_uint8x16_shiftRightByScalar, {
UsesSIMDInt8x16 = true;
UsesSIMDUint8x16 = true;
return getAssign(CI) + "SIMD_Int8x16_fromUint8x16Bits(SIMD_Uint8x16_shiftRightByScalar(SIMD_Uint8x16_fromInt8x16Bits(" + getValueAsStr(CI->getOperand(0)) + "), " + getValueAsStr(CI->getOperand(1)) + "))";
})
DEF_BUILTIN_HANDLER(emscripten_uint8x16_extractLane, SIMD_Uint8x16_extractLane);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_replaceLane, SIMD_Uint8x16_replaceLane);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_store, SIMD_Uint8x16_store);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_load, SIMD_Uint8x16_load);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromFloat64x2Bits, SIMD_Uint8x16_fromFloat64x2Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromFloat32x4Bits, SIMD_Uint8x16_fromFloat32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromInt32x4Bits, SIMD_Uint8x16_fromInt32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromUint32x4Bits, SIMD_Uint8x16_fromUint32x4Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromInt16x8Bits, SIMD_Uint8x16_fromInt16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromUint16x8Bits, SIMD_Uint8x16_fromUint16x8Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromInt8x16Bits, SIMD_Uint8x16_fromInt8x16Bits);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_fromInt8x16, SIMD_Uint8x16_fromInt8x16);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_swizzle, SIMD_Uint8x16_swizzle);
DEF_BUILTIN_HANDLER(emscripten_uint8x16_shuffle, SIMD_Uint8x16_shuffle);
// SIMD.js Bool64x2
DEF_BUILTIN_HANDLER(emscripten_bool64x2_anyTrue, SIMD_Bool64x2_anyTrue);
DEF_BUILTIN_HANDLER(emscripten_bool64x2_allTrue, SIMD_Bool64x2_allTrue);
// SIMD.js Bool32x4
DEF_BUILTIN_HANDLER(emscripten_bool32x4_anyTrue, SIMD_Bool32x4_anyTrue);
DEF_BUILTIN_HANDLER(emscripten_bool32x4_allTrue, SIMD_Bool32x4_allTrue);
// SIMD.js Bool16x8
DEF_BUILTIN_HANDLER(emscripten_bool16x8_anyTrue, SIMD_Bool16x8_anyTrue);
DEF_BUILTIN_HANDLER(emscripten_bool16x8_allTrue, SIMD_Bool16x8_allTrue);
// SIMD.js Bool8x16
DEF_BUILTIN_HANDLER(emscripten_bool8x16_anyTrue, SIMD_Bool8x16_anyTrue);
DEF_BUILTIN_HANDLER(emscripten_bool8x16_allTrue, SIMD_Bool8x16_allTrue);
DEF_CALL_HANDLER(emscripten_atomic_fence, {
if (EnablePthreads) {
UsesInt32Array = true;
return "(Atomics_add(HEAP32, 0, 0)|0) /* fence */";
}
else return "/* fence */";
})
// Setups
void setupCallHandlers() {
assert(CallHandlers.empty());
#define SETUP_CALL_HANDLER(Ident) \
CallHandlers["_" #Ident] = &JSWriter::CH_##Ident;
SETUP_CALL_HANDLER(__default__);
SETUP_CALL_HANDLER(emscripten_preinvoke);
SETUP_CALL_HANDLER(emscripten_postinvoke);
SETUP_CALL_HANDLER(emscripten_landingpad);
SETUP_CALL_HANDLER(emscripten_resume);
SETUP_CALL_HANDLER(emscripten_prep_setjmp);
SETUP_CALL_HANDLER(emscripten_cleanup_setjmp);
SETUP_CALL_HANDLER(emscripten_setjmp);
SETUP_CALL_HANDLER(emscripten_longjmp);
SETUP_CALL_HANDLER(emscripten_check_longjmp);
SETUP_CALL_HANDLER(emscripten_get_longjmp_result);
SETUP_CALL_HANDLER(emscripten_alloc_async_context);
SETUP_CALL_HANDLER(emscripten_check_async);
SETUP_CALL_HANDLER(emscripten_do_not_unwind);
SETUP_CALL_HANDLER(emscripten_do_not_unwind_async);
SETUP_CALL_HANDLER(emscripten_get_async_return_value_addr);
SETUP_CALL_HANDLER(emscripten_debugger);
SETUP_CALL_HANDLER(llvm_debugtrap);
SETUP_CALL_HANDLER(getHigh32);
SETUP_CALL_HANDLER(setHigh32);
SETUP_CALL_HANDLER(FtoILow);
SETUP_CALL_HANDLER(FtoIHigh);
SETUP_CALL_HANDLER(DtoILow);
SETUP_CALL_HANDLER(DtoIHigh);
SETUP_CALL_HANDLER(BDtoILow);
SETUP_CALL_HANDLER(BDtoIHigh);
SETUP_CALL_HANDLER(SItoF);
SETUP_CALL_HANDLER(UItoF);
SETUP_CALL_HANDLER(SItoD);
SETUP_CALL_HANDLER(UItoD);
SETUP_CALL_HANDLER(BItoD);
SETUP_CALL_HANDLER(llvm_nacl_atomic_store_i32);
SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i8);
SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i16);
SETUP_CALL_HANDLER(llvm_nacl_atomic_cmpxchg_i32);
SETUP_CALL_HANDLER(llvm_memcpy_p0i8_p0i8_i32);
SETUP_CALL_HANDLER(llvm_memset_p0i8_i32);
SETUP_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32);
SETUP_CALL_HANDLER(llvm_expect_i32);
SETUP_CALL_HANDLER(llvm_expect_i1);
SETUP_CALL_HANDLER(llvm_dbg_declare);
SETUP_CALL_HANDLER(llvm_dbg_value);
SETUP_CALL_HANDLER(llvm_lifetime_start);
SETUP_CALL_HANDLER(llvm_lifetime_end);
SETUP_CALL_HANDLER(llvm_lifetime_start_p0i8);
SETUP_CALL_HANDLER(llvm_lifetime_end_p0i8);
SETUP_CALL_HANDLER(llvm_invariant_start);
SETUP_CALL_HANDLER(llvm_invariant_end);
SETUP_CALL_HANDLER(llvm_invariant_start_p0i8);
SETUP_CALL_HANDLER(llvm_invariant_end_p0i8);
SETUP_CALL_HANDLER(llvm_prefetch);
SETUP_CALL_HANDLER(llvm_objectsize_i32_p0i8);
SETUP_CALL_HANDLER(llvm_flt_rounds);
SETUP_CALL_HANDLER(bitshift64Lshr);
SETUP_CALL_HANDLER(bitshift64Ashr);
SETUP_CALL_HANDLER(bitshift64Shl);
SETUP_CALL_HANDLER(llvm_ctlz_i32);
SETUP_CALL_HANDLER(llvm_cttz_i32);
SETUP_CALL_HANDLER(llvm_ctlz_i64);
SETUP_CALL_HANDLER(llvm_cttz_i64);
SETUP_CALL_HANDLER(llvm_ctpop_i32);
SETUP_CALL_HANDLER(llvm_ctpop_i64);
SETUP_CALL_HANDLER(llvm_copysign_f32);
SETUP_CALL_HANDLER(llvm_copysign_f64);
SETUP_CALL_HANDLER(llvm_rint_f32);
SETUP_CALL_HANDLER(llvm_rint_f64);
// SIMD.js Float64x2
SETUP_CALL_HANDLER(emscripten_float64x2_set);
SETUP_CALL_HANDLER(emscripten_float64x2_splat);
SETUP_CALL_HANDLER(emscripten_float64x2_add);
SETUP_CALL_HANDLER(emscripten_float64x2_sub);
SETUP_CALL_HANDLER(emscripten_float64x2_mul);
SETUP_CALL_HANDLER(emscripten_float64x2_div);
SETUP_CALL_HANDLER(emscripten_float64x2_max);
SETUP_CALL_HANDLER(emscripten_float64x2_min);
SETUP_CALL_HANDLER(emscripten_float64x2_maxNum);
SETUP_CALL_HANDLER(emscripten_float64x2_minNum);
SETUP_CALL_HANDLER(emscripten_float64x2_neg);
SETUP_CALL_HANDLER(emscripten_float64x2_sqrt);
SETUP_CALL_HANDLER(emscripten_float64x2_reciprocalApproximation);
SETUP_CALL_HANDLER(emscripten_float64x2_reciprocalSqrtApproximation);
SETUP_CALL_HANDLER(emscripten_float64x2_abs);
// n.b. No emscripten_float64x2_and, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_xor, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_or, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float64x2_not, only defined on boolean and integer SIMD types.
SETUP_CALL_HANDLER(emscripten_float64x2_lessThan);
SETUP_CALL_HANDLER(emscripten_float64x2_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_float64x2_greaterThan);
SETUP_CALL_HANDLER(emscripten_float64x2_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_float64x2_equal);
SETUP_CALL_HANDLER(emscripten_float64x2_notEqual);
// n.b. No emscripten_float64x2_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_float64x2_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_float64x2_select);
// n.b. No emscripten_float64x2_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float64x2_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float64x2_shiftLeftByScalar, only defined on integer SIMD types.
// n.b. No emscripten_float64x2_shiftRightByScalar, only defined on integer SIMD types.
SETUP_CALL_HANDLER(emscripten_float64x2_extractLane);
SETUP_CALL_HANDLER(emscripten_float64x2_replaceLane);
SETUP_CALL_HANDLER(emscripten_float64x2_store);
SETUP_CALL_HANDLER(emscripten_float64x2_store1);
SETUP_CALL_HANDLER(emscripten_float64x2_load);
SETUP_CALL_HANDLER(emscripten_float64x2_load1);
SETUP_CALL_HANDLER(emscripten_float64x2_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_float64x2_swizzle);
SETUP_CALL_HANDLER(emscripten_float64x2_shuffle);
// SIMD.js Float32x4
SETUP_CALL_HANDLER(emscripten_float32x4_set);
SETUP_CALL_HANDLER(emscripten_float32x4_splat);
SETUP_CALL_HANDLER(emscripten_float32x4_add);
SETUP_CALL_HANDLER(emscripten_float32x4_sub);
SETUP_CALL_HANDLER(emscripten_float32x4_mul);
SETUP_CALL_HANDLER(emscripten_float32x4_div);
SETUP_CALL_HANDLER(emscripten_float32x4_max);
SETUP_CALL_HANDLER(emscripten_float32x4_min);
SETUP_CALL_HANDLER(emscripten_float32x4_maxNum);
SETUP_CALL_HANDLER(emscripten_float32x4_minNum);
SETUP_CALL_HANDLER(emscripten_float32x4_neg);
SETUP_CALL_HANDLER(emscripten_float32x4_sqrt);
SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalApproximation);
SETUP_CALL_HANDLER(emscripten_float32x4_reciprocalSqrtApproximation);
SETUP_CALL_HANDLER(emscripten_float32x4_abs);
// n.b. No emscripten_float32x4_and, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_xor, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_or, only defined on boolean and integer SIMD types.
// n.b. No emscripten_float32x4_not, only defined on boolean and integer SIMD types.
SETUP_CALL_HANDLER(emscripten_float32x4_lessThan);
SETUP_CALL_HANDLER(emscripten_float32x4_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_float32x4_greaterThan);
SETUP_CALL_HANDLER(emscripten_float32x4_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_float32x4_equal);
SETUP_CALL_HANDLER(emscripten_float32x4_notEqual);
// n.b. No emscripten_float32x4_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_float32x4_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_float32x4_select);
// n.b. No emscripten_float32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_float32x4_shiftLeftByScalar, only defined on integer SIMD types.
// n.b. No emscripten_float32x4_shiftRightByScalar, only defined on integer SIMD types.
SETUP_CALL_HANDLER(emscripten_float32x4_extractLane);
SETUP_CALL_HANDLER(emscripten_float32x4_replaceLane);
SETUP_CALL_HANDLER(emscripten_float32x4_store);
SETUP_CALL_HANDLER(emscripten_float32x4_store1);
SETUP_CALL_HANDLER(emscripten_float32x4_store2);
SETUP_CALL_HANDLER(emscripten_float32x4_store3);
SETUP_CALL_HANDLER(emscripten_float32x4_load);
SETUP_CALL_HANDLER(emscripten_float32x4_load1);
SETUP_CALL_HANDLER(emscripten_float32x4_load2);
SETUP_CALL_HANDLER(emscripten_float32x4_load3);
SETUP_CALL_HANDLER(emscripten_float32x4_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_float32x4_fromInt32x4);
SETUP_CALL_HANDLER(emscripten_float32x4_fromUint32x4);
SETUP_CALL_HANDLER(emscripten_float32x4_swizzle);
SETUP_CALL_HANDLER(emscripten_float32x4_shuffle);
// SIMD.js Int32x4
SETUP_CALL_HANDLER(emscripten_int32x4_set);
SETUP_CALL_HANDLER(emscripten_int32x4_splat);
SETUP_CALL_HANDLER(emscripten_int32x4_add);
SETUP_CALL_HANDLER(emscripten_int32x4_sub);
SETUP_CALL_HANDLER(emscripten_int32x4_mul);
// n.b. No emscripten_int32x4_div, division is only defined on floating point types.
// n.b. No emscripten_int32x4_max, only defined on floating point types.
// n.b. No emscripten_int32x4_min, only defined on floating point types.
// n.b. No emscripten_int32x4_maxNum, only defined on floating point types.
// n.b. No emscripten_int32x4_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int32x4_neg);
// n.b. No emscripten_int32x4_sqrt, only defined on floating point types.
// n.b. No emscripten_int32x4_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int32x4_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int32x4_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int32x4_and);
SETUP_CALL_HANDLER(emscripten_int32x4_xor);
SETUP_CALL_HANDLER(emscripten_int32x4_or);
SETUP_CALL_HANDLER(emscripten_int32x4_not);
SETUP_CALL_HANDLER(emscripten_int32x4_lessThan);
SETUP_CALL_HANDLER(emscripten_int32x4_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int32x4_greaterThan);
SETUP_CALL_HANDLER(emscripten_int32x4_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int32x4_equal);
SETUP_CALL_HANDLER(emscripten_int32x4_notEqual);
// n.b. No emscripten_int32x4_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_int32x4_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_int32x4_select);
// n.b. No emscripten_int32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_int32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
SETUP_CALL_HANDLER(emscripten_int32x4_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_int32x4_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_int32x4_extractLane);
SETUP_CALL_HANDLER(emscripten_int32x4_replaceLane);
SETUP_CALL_HANDLER(emscripten_int32x4_store);
SETUP_CALL_HANDLER(emscripten_int32x4_store1);
SETUP_CALL_HANDLER(emscripten_int32x4_store2);
SETUP_CALL_HANDLER(emscripten_int32x4_store3);
SETUP_CALL_HANDLER(emscripten_int32x4_load);
SETUP_CALL_HANDLER(emscripten_int32x4_load1);
SETUP_CALL_HANDLER(emscripten_int32x4_load2);
SETUP_CALL_HANDLER(emscripten_int32x4_load3);
SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat32x4);
SETUP_CALL_HANDLER(emscripten_int32x4_fromUint32x4);
// SETUP_CALL_HANDLER(emscripten_int32x4_fromFloat64x2); // TODO: Unofficial extension
SETUP_CALL_HANDLER(emscripten_int32x4_swizzle);
SETUP_CALL_HANDLER(emscripten_int32x4_shuffle);
// SIMD.js Uint32x4
SETUP_CALL_HANDLER(emscripten_uint32x4_set);
SETUP_CALL_HANDLER(emscripten_uint32x4_splat);
SETUP_CALL_HANDLER(emscripten_uint32x4_add);
SETUP_CALL_HANDLER(emscripten_uint32x4_sub);
SETUP_CALL_HANDLER(emscripten_uint32x4_mul);
// n.b. No emscripten_uint32x4_div, division is only defined on floating point types.
// n.b. No emscripten_uint32x4_max, only defined on floating point types.
// n.b. No emscripten_uint32x4_min, only defined on floating point types.
// n.b. No emscripten_uint32x4_maxNum, only defined on floating point types.
// n.b. No emscripten_uint32x4_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint32x4_neg);
// n.b. No emscripten_uint32x4_sqrt, only defined on floating point types.
// n.b. No emscripten_uint32x4_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint32x4_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint32x4_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint32x4_and);
SETUP_CALL_HANDLER(emscripten_uint32x4_xor);
SETUP_CALL_HANDLER(emscripten_uint32x4_or);
SETUP_CALL_HANDLER(emscripten_uint32x4_not);
SETUP_CALL_HANDLER(emscripten_uint32x4_lessThan);
SETUP_CALL_HANDLER(emscripten_uint32x4_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint32x4_greaterThan);
SETUP_CALL_HANDLER(emscripten_uint32x4_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint32x4_equal);
SETUP_CALL_HANDLER(emscripten_uint32x4_notEqual);
// n.b. No emscripten_uint32x4_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_uint32x4_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_uint32x4_select);
// n.b. No emscripten_uint32x4_addSaturate, only defined on 8-bit and 16-bit integer SIMD types.
// n.b. No emscripten_uint32x4_subSaturate, only defined on 8-bit and 16-bit integer SIMD types.
SETUP_CALL_HANDLER(emscripten_uint32x4_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_uint32x4_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_uint32x4_extractLane);
SETUP_CALL_HANDLER(emscripten_uint32x4_replaceLane);
SETUP_CALL_HANDLER(emscripten_uint32x4_store);
SETUP_CALL_HANDLER(emscripten_uint32x4_store1);
SETUP_CALL_HANDLER(emscripten_uint32x4_store2);
SETUP_CALL_HANDLER(emscripten_uint32x4_store3);
SETUP_CALL_HANDLER(emscripten_uint32x4_load);
SETUP_CALL_HANDLER(emscripten_uint32x4_load1);
SETUP_CALL_HANDLER(emscripten_uint32x4_load2);
SETUP_CALL_HANDLER(emscripten_uint32x4_load3);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromFloat32x4);
SETUP_CALL_HANDLER(emscripten_uint32x4_fromInt32x4);
// SETUP_CALL_HANDLER(emscripten_uint32x4_fromFloat64x2); // TODO: Unofficial extension
SETUP_CALL_HANDLER(emscripten_uint32x4_swizzle);
SETUP_CALL_HANDLER(emscripten_uint32x4_shuffle);
// SIMD.js Int16x8
SETUP_CALL_HANDLER(emscripten_int16x8_set);
SETUP_CALL_HANDLER(emscripten_int16x8_splat);
SETUP_CALL_HANDLER(emscripten_int16x8_add);
SETUP_CALL_HANDLER(emscripten_int16x8_sub);
SETUP_CALL_HANDLER(emscripten_int16x8_mul);
// n.b. No emscripten_int16x8_div, division is only defined on floating point types.
// n.b. No emscripten_int16x8_max, only defined on floating point types.
// n.b. No emscripten_int16x8_min, only defined on floating point types.
// n.b. No emscripten_int16x8_maxNum, only defined on floating point types.
// n.b. No emscripten_int16x8_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int16x8_neg);
// n.b. No emscripten_int16x8_sqrt, only defined on floating point types.
// n.b. No emscripten_int16x8_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int16x8_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int16x8_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int16x8_and);
SETUP_CALL_HANDLER(emscripten_int16x8_xor);
SETUP_CALL_HANDLER(emscripten_int16x8_or);
SETUP_CALL_HANDLER(emscripten_int16x8_not);
SETUP_CALL_HANDLER(emscripten_int16x8_lessThan);
SETUP_CALL_HANDLER(emscripten_int16x8_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int16x8_greaterThan);
SETUP_CALL_HANDLER(emscripten_int16x8_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int16x8_equal);
SETUP_CALL_HANDLER(emscripten_int16x8_notEqual);
// n.b. No emscripten_int16x8_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_int16x8_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_int16x8_select);
SETUP_CALL_HANDLER(emscripten_int16x8_addSaturate);
SETUP_CALL_HANDLER(emscripten_int16x8_subSaturate);
SETUP_CALL_HANDLER(emscripten_int16x8_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_int16x8_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_int16x8_extractLane);
SETUP_CALL_HANDLER(emscripten_int16x8_replaceLane);
SETUP_CALL_HANDLER(emscripten_int16x8_store);
SETUP_CALL_HANDLER(emscripten_int16x8_load);
SETUP_CALL_HANDLER(emscripten_int16x8_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_int16x8_fromUint16x8);
SETUP_CALL_HANDLER(emscripten_int16x8_swizzle);
SETUP_CALL_HANDLER(emscripten_int16x8_shuffle);
// SIMD.js Uint16x8
SETUP_CALL_HANDLER(emscripten_uint16x8_set);
SETUP_CALL_HANDLER(emscripten_uint16x8_splat);
SETUP_CALL_HANDLER(emscripten_uint16x8_add);
SETUP_CALL_HANDLER(emscripten_uint16x8_sub);
SETUP_CALL_HANDLER(emscripten_uint16x8_mul);
// n.b. No emscripten_uint16x8_div, division is only defined on floating point types.
// n.b. No emscripten_uint16x8_max, only defined on floating point types.
// n.b. No emscripten_uint16x8_min, only defined on floating point types.
// n.b. No emscripten_uint16x8_maxNum, only defined on floating point types.
// n.b. No emscripten_uint16x8_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint16x8_neg);
// n.b. No emscripten_uint16x8_sqrt, only defined on floating point types.
// n.b. No emscripten_uint16x8_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint16x8_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint16x8_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint16x8_and);
SETUP_CALL_HANDLER(emscripten_uint16x8_xor);
SETUP_CALL_HANDLER(emscripten_uint16x8_or);
SETUP_CALL_HANDLER(emscripten_uint16x8_not);
SETUP_CALL_HANDLER(emscripten_uint16x8_lessThan);
SETUP_CALL_HANDLER(emscripten_uint16x8_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint16x8_greaterThan);
SETUP_CALL_HANDLER(emscripten_uint16x8_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint16x8_equal);
SETUP_CALL_HANDLER(emscripten_uint16x8_notEqual);
// n.b. No emscripten_uint16x8_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_uint16x8_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_uint16x8_select);
SETUP_CALL_HANDLER(emscripten_uint16x8_addSaturate);
SETUP_CALL_HANDLER(emscripten_uint16x8_subSaturate);
SETUP_CALL_HANDLER(emscripten_uint16x8_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_uint16x8_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_uint16x8_extractLane);
SETUP_CALL_HANDLER(emscripten_uint16x8_replaceLane);
SETUP_CALL_HANDLER(emscripten_uint16x8_store);
SETUP_CALL_HANDLER(emscripten_uint16x8_load);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_uint16x8_fromInt16x8);
SETUP_CALL_HANDLER(emscripten_uint16x8_swizzle);
SETUP_CALL_HANDLER(emscripten_uint16x8_shuffle);
// SIMD.js Int8x16
SETUP_CALL_HANDLER(emscripten_int8x16_set);
SETUP_CALL_HANDLER(emscripten_int8x16_splat);
SETUP_CALL_HANDLER(emscripten_int8x16_add);
SETUP_CALL_HANDLER(emscripten_int8x16_sub);
SETUP_CALL_HANDLER(emscripten_int8x16_mul);
// n.b. No emscripten_int8x16_div, division is only defined on floating point types.
// n.b. No emscripten_int8x16_max, only defined on floating point types.
// n.b. No emscripten_int8x16_min, only defined on floating point types.
// n.b. No emscripten_int8x16_maxNum, only defined on floating point types.
// n.b. No emscripten_int8x16_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int8x16_neg);
// n.b. No emscripten_int8x16_sqrt, only defined on floating point types.
// n.b. No emscripten_int8x16_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_int8x16_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_int8x16_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_int8x16_and);
SETUP_CALL_HANDLER(emscripten_int8x16_xor);
SETUP_CALL_HANDLER(emscripten_int8x16_or);
SETUP_CALL_HANDLER(emscripten_int8x16_not);
SETUP_CALL_HANDLER(emscripten_int8x16_lessThan);
SETUP_CALL_HANDLER(emscripten_int8x16_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int8x16_greaterThan);
SETUP_CALL_HANDLER(emscripten_int8x16_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_int8x16_equal);
SETUP_CALL_HANDLER(emscripten_int8x16_notEqual);
// n.b. No emscripten_int8x16_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_int8x16_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_int8x16_select);
SETUP_CALL_HANDLER(emscripten_int8x16_addSaturate);
SETUP_CALL_HANDLER(emscripten_int8x16_subSaturate);
SETUP_CALL_HANDLER(emscripten_int8x16_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_int8x16_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_int8x16_extractLane);
SETUP_CALL_HANDLER(emscripten_int8x16_replaceLane);
SETUP_CALL_HANDLER(emscripten_int8x16_store);
SETUP_CALL_HANDLER(emscripten_int8x16_load);
SETUP_CALL_HANDLER(emscripten_int8x16_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromUint8x16Bits);
SETUP_CALL_HANDLER(emscripten_int8x16_fromUint8x16);
SETUP_CALL_HANDLER(emscripten_int8x16_swizzle);
SETUP_CALL_HANDLER(emscripten_int8x16_shuffle);
// SIMD.js Uint8x16
SETUP_CALL_HANDLER(emscripten_uint8x16_set);
SETUP_CALL_HANDLER(emscripten_uint8x16_splat);
SETUP_CALL_HANDLER(emscripten_uint8x16_add);
SETUP_CALL_HANDLER(emscripten_uint8x16_sub);
SETUP_CALL_HANDLER(emscripten_uint8x16_mul);
// n.b. No emscripten_uint8x16_div, division is only defined on floating point types.
// n.b. No emscripten_uint8x16_max, only defined on floating point types.
// n.b. No emscripten_uint8x16_min, only defined on floating point types.
// n.b. No emscripten_uint8x16_maxNum, only defined on floating point types.
// n.b. No emscripten_uint8x16_minNum, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint8x16_neg);
// n.b. No emscripten_uint8x16_sqrt, only defined on floating point types.
// n.b. No emscripten_uint8x16_reciprocalApproximation, only defined on floating point types.
// n.b. No emscripten_uint8x16_reciprocalSqrtApproximation, only defined on floating point types.
// n.b. No emscripten_uint8x16_abs, only defined on floating point types.
SETUP_CALL_HANDLER(emscripten_uint8x16_and);
SETUP_CALL_HANDLER(emscripten_uint8x16_xor);
SETUP_CALL_HANDLER(emscripten_uint8x16_or);
SETUP_CALL_HANDLER(emscripten_uint8x16_not);
SETUP_CALL_HANDLER(emscripten_uint8x16_lessThan);
SETUP_CALL_HANDLER(emscripten_uint8x16_lessThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint8x16_greaterThan);
SETUP_CALL_HANDLER(emscripten_uint8x16_greaterThanOrEqual);
SETUP_CALL_HANDLER(emscripten_uint8x16_equal);
SETUP_CALL_HANDLER(emscripten_uint8x16_notEqual);
// n.b. No emscripten_uint8x16_anyTrue, only defined on boolean SIMD types.
// n.b. No emscripten_uint8x16_allTrue, only defined on boolean SIMD types.
SETUP_CALL_HANDLER(emscripten_uint8x16_select);
SETUP_CALL_HANDLER(emscripten_uint8x16_addSaturate);
SETUP_CALL_HANDLER(emscripten_uint8x16_subSaturate);
SETUP_CALL_HANDLER(emscripten_uint8x16_shiftLeftByScalar);
SETUP_CALL_HANDLER(emscripten_uint8x16_shiftRightByScalar);
SETUP_CALL_HANDLER(emscripten_uint8x16_extractLane);
SETUP_CALL_HANDLER(emscripten_uint8x16_replaceLane);
SETUP_CALL_HANDLER(emscripten_uint8x16_store);
SETUP_CALL_HANDLER(emscripten_uint8x16_load);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromFloat64x2Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromFloat32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromInt32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromUint32x4Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromInt16x8Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromUint16x8Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromInt8x16Bits);
SETUP_CALL_HANDLER(emscripten_uint8x16_fromInt8x16);
SETUP_CALL_HANDLER(emscripten_uint8x16_swizzle);
SETUP_CALL_HANDLER(emscripten_uint8x16_shuffle);
// SIMD.js Bool64x2
SETUP_CALL_HANDLER(emscripten_bool64x2_anyTrue);
SETUP_CALL_HANDLER(emscripten_bool64x2_allTrue);
// SIMD.js Bool32x4
SETUP_CALL_HANDLER(emscripten_bool32x4_anyTrue);
SETUP_CALL_HANDLER(emscripten_bool32x4_allTrue);
// SIMD.js Bool16x8
SETUP_CALL_HANDLER(emscripten_bool16x8_anyTrue);
SETUP_CALL_HANDLER(emscripten_bool16x8_allTrue);
// SIMD.js Bool8x16
SETUP_CALL_HANDLER(emscripten_bool8x16_anyTrue);
SETUP_CALL_HANDLER(emscripten_bool8x16_allTrue);
SETUP_CALL_HANDLER(emscripten_asm_const);
SETUP_CALL_HANDLER(emscripten_asm_const_int);
SETUP_CALL_HANDLER(emscripten_asm_const_double);
SETUP_CALL_HANDLER(emscripten_asm_const_sync_on_main_thread);
SETUP_CALL_HANDLER(emscripten_asm_const_int_sync_on_main_thread);
SETUP_CALL_HANDLER(emscripten_asm_const_double_sync_on_main_thread);
SETUP_CALL_HANDLER(emscripten_asm_const_async_on_main_thread);
SETUP_CALL_HANDLER(emscripten_atomic_exchange_u8);
SETUP_CALL_HANDLER(emscripten_atomic_exchange_u16);
SETUP_CALL_HANDLER(emscripten_atomic_exchange_u32);
SETUP_CALL_HANDLER(emscripten_atomic_cas_u8);
SETUP_CALL_HANDLER(emscripten_atomic_cas_u16);
SETUP_CALL_HANDLER(emscripten_atomic_cas_u32);
SETUP_CALL_HANDLER(emscripten_atomic_load_u8);
SETUP_CALL_HANDLER(emscripten_atomic_load_u16);
SETUP_CALL_HANDLER(emscripten_atomic_load_u32);
SETUP_CALL_HANDLER(emscripten_atomic_load_f32);
SETUP_CALL_HANDLER(emscripten_atomic_load_f64);
SETUP_CALL_HANDLER(emscripten_atomic_store_u8);
SETUP_CALL_HANDLER(emscripten_atomic_store_u16);
SETUP_CALL_HANDLER(emscripten_atomic_store_u32);
SETUP_CALL_HANDLER(emscripten_atomic_store_f32);
SETUP_CALL_HANDLER(emscripten_atomic_store_f64);
SETUP_CALL_HANDLER(emscripten_atomic_add_u8);
SETUP_CALL_HANDLER(emscripten_atomic_add_u16);
SETUP_CALL_HANDLER(emscripten_atomic_add_u32);
SETUP_CALL_HANDLER(emscripten_atomic_sub_u8);
SETUP_CALL_HANDLER(emscripten_atomic_sub_u16);
SETUP_CALL_HANDLER(emscripten_atomic_sub_u32);
SETUP_CALL_HANDLER(emscripten_atomic_and_u8);
SETUP_CALL_HANDLER(emscripten_atomic_and_u16);
SETUP_CALL_HANDLER(emscripten_atomic_and_u32);
SETUP_CALL_HANDLER(emscripten_atomic_or_u8);
SETUP_CALL_HANDLER(emscripten_atomic_or_u16);
SETUP_CALL_HANDLER(emscripten_atomic_or_u32);
SETUP_CALL_HANDLER(emscripten_atomic_xor_u8);
SETUP_CALL_HANDLER(emscripten_atomic_xor_u16);
SETUP_CALL_HANDLER(emscripten_atomic_xor_u32);
SETUP_CALL_HANDLER(emscripten_atomic_fence);
if (OnlyWebAssembly) {
SETUP_CALL_HANDLER(__atomic_load_8);
SETUP_CALL_HANDLER(__atomic_store_8);
if (EnablePthreads) {
// If targeting Wasm multithreading, route 64-bit atomic ops directly to wasm opcodes.
// Otherwise these will be passed through to JS/C library functions that do the
// equivalent operations, e.g. for asm.js that doesn't have 64-bit atomics.
SETUP_CALL_HANDLER(__atomic_exchange_8);
SETUP_CALL_HANDLER(__atomic_fetch_add_8);
SETUP_CALL_HANDLER(__atomic_fetch_sub_8);
SETUP_CALL_HANDLER(__atomic_fetch_and_8);
SETUP_CALL_HANDLER(__atomic_fetch_or_8);
SETUP_CALL_HANDLER(__atomic_fetch_xor_8);
}
}
SETUP_CALL_HANDLER(abs);
SETUP_CALL_HANDLER(labs);
SETUP_CALL_HANDLER(cos);
SETUP_CALL_HANDLER(cosf);
SETUP_CALL_HANDLER(cosl);
SETUP_CALL_HANDLER(sin);
SETUP_CALL_HANDLER(sinf);
SETUP_CALL_HANDLER(sinl);
SETUP_CALL_HANDLER(tan);
SETUP_CALL_HANDLER(tanf);
SETUP_CALL_HANDLER(tanl);
SETUP_CALL_HANDLER(acos);
SETUP_CALL_HANDLER(acosf);
SETUP_CALL_HANDLER(acosl);
SETUP_CALL_HANDLER(asin);
SETUP_CALL_HANDLER(asinf);
SETUP_CALL_HANDLER(asinl);
SETUP_CALL_HANDLER(atan);
SETUP_CALL_HANDLER(atanf);
SETUP_CALL_HANDLER(atanl);
SETUP_CALL_HANDLER(atan2);
SETUP_CALL_HANDLER(atan2f);
SETUP_CALL_HANDLER(atan2l);
SETUP_CALL_HANDLER(exp);
SETUP_CALL_HANDLER(expf);
SETUP_CALL_HANDLER(expl);
SETUP_CALL_HANDLER(log);
SETUP_CALL_HANDLER(logf);
SETUP_CALL_HANDLER(logl);
SETUP_CALL_HANDLER(sqrt);
SETUP_CALL_HANDLER(sqrtf);
SETUP_CALL_HANDLER(sqrtl);
SETUP_CALL_HANDLER(fabs);
SETUP_CALL_HANDLER(fabsf);
SETUP_CALL_HANDLER(fabsl);
SETUP_CALL_HANDLER(llvm_fabs_f32);
SETUP_CALL_HANDLER(llvm_fabs_f64);
SETUP_CALL_HANDLER(ceil);
SETUP_CALL_HANDLER(ceilf);
SETUP_CALL_HANDLER(ceill);
SETUP_CALL_HANDLER(llvm_ceil_f32);
SETUP_CALL_HANDLER(llvm_ceil_f64);
SETUP_CALL_HANDLER(floor);
SETUP_CALL_HANDLER(floorf);
SETUP_CALL_HANDLER(floorl);
SETUP_CALL_HANDLER(llvm_floor_f32);
SETUP_CALL_HANDLER(llvm_floor_f64);
SETUP_CALL_HANDLER(pow);
SETUP_CALL_HANDLER(powf);
SETUP_CALL_HANDLER(powl);
SETUP_CALL_HANDLER(llvm_sqrt_f32);
SETUP_CALL_HANDLER(llvm_sqrt_f64);
SETUP_CALL_HANDLER(llvm_pow_f32);
SETUP_CALL_HANDLER(llvm_pow_f64);
SETUP_CALL_HANDLER(llvm_powi_f32);
SETUP_CALL_HANDLER(llvm_powi_f64);
SETUP_CALL_HANDLER(llvm_log_f32);
SETUP_CALL_HANDLER(llvm_log_f64);
SETUP_CALL_HANDLER(llvm_exp_f32);
SETUP_CALL_HANDLER(llvm_exp_f64);
SETUP_CALL_HANDLER(llvm_cos_f32);
SETUP_CALL_HANDLER(llvm_cos_f64);
SETUP_CALL_HANDLER(llvm_sin_f32);
SETUP_CALL_HANDLER(llvm_sin_f64);
}
std::string handleCall(const Instruction *CI) {
const Value *CV = getActuallyCalledValue(CI);
if (const InlineAsm* IA = dyn_cast<const InlineAsm>(CV)) {
if (IA->hasSideEffects() && IA->getAsmString() == "") {
return "/* asm() memory 'barrier' */";
} else {
errs() << "In function " << CI->getParent()->getParent()->getName() << "()\n";
errs() << *IA << "\n";
report_fatal_error("asm() with non-empty content not supported, use EM_ASM() (see emscripten.h)");
}
}
// Get the name to call this function by. If it's a direct call, meaning
// which know which Function we're calling, avoid calling getValueAsStr, as
// we don't need to use a function index.
const std::string &Name = isa<Function>(CV) ? getJSName(CV) : getValueAsStr(CV);
CallHandlerMap::iterator CH = CallHandlers.find("___default__");
if (isa<Function>(CV)) {
CallHandlerMap::iterator Custom = CallHandlers.find(Name);
if (Custom != CallHandlers.end()) CH = Custom;
}
return (this->*(CH->second))(CI, Name, -1);
}