aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/JSBackend/CallHandlers.h72
-rw-r--r--lib/Target/JSBackend/JSBackend.cpp516
-rw-r--r--lib/Transforms/NaCl/ExpandI64.cpp55
-rw-r--r--lib/Transforms/NaCl/ExpandVarArgs.cpp11
-rw-r--r--lib/Transforms/NaCl/LowerEmExceptionsPass.cpp16
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp4
-rw-r--r--lib/Transforms/NaCl/PromoteIntegers.cpp10
7 files changed, 393 insertions, 291 deletions
diff --git a/lib/Target/JSBackend/CallHandlers.h b/lib/Target/JSBackend/CallHandlers.h
index c70a37bc47..dae61b2054 100644
--- a/lib/Target/JSBackend/CallHandlers.h
+++ b/lib/Target/JSBackend/CallHandlers.h
@@ -78,7 +78,7 @@ DEF_CALL_HANDLER(__default__, {
if (!NeedCasts) {
text += getValueAsStr(CI->getOperand(i));
} else {
- text += getValueAsCastStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT);
+ text += getValueAsCastParenStr(CI->getOperand(i), ASM_NONSPECIFIC | FFI_OUT);
}
if (i < NumArgs - 1) text += ",";
}
@@ -89,11 +89,11 @@ DEF_CALL_HANDLER(__default__, {
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
- getAssign(getJSName(CI), InstRT); // ensure the variable is defined, but do not emit it here
- // it should have 0 uses, but just to be safe
+ 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 = getAssign(getJSName(CI), ActualRT) + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN);
+ text = getAssignIfNeeded(CI) + "(" + getCast(text, ActualRT, ASM_NONSPECIFIC | FFI_IN) + ")";
}
return text;
})
@@ -107,10 +107,10 @@ DEF_CALL_HANDLER(emscripten_preinvoke, {
DEF_CALL_HANDLER(emscripten_postinvoke, {
assert(InvokeState == 1 || InvokeState == 2); // normally 2, but can be 1 if the call in between was optimized out
InvokeState = 0;
- return getAssign(getJSName(CI), CI->getType()) + "__THREW__; __THREW__ = 0";
+ return getAssign(CI) + "__THREW__; __THREW__ = 0";
})
DEF_CALL_HANDLER(emscripten_landingpad, {
- std::string Ret = getAssign(getJSName(CI), CI->getType()) + "___cxa_find_matching_catch(-1,-1";
+ std::string Ret = getAssign(CI) + "___cxa_find_matching_catch(-1,-1";
unsigned Num = getNumArgOperands(CI);
for (unsigned i = 1; i < Num-1; i++) { // ignore personality and cleanup XXX - we probably should not be doing that!
Ret += ",";
@@ -126,7 +126,7 @@ DEF_CALL_HANDLER(emscripten_resume, {
// setjmp support
DEF_CALL_HANDLER(emscripten_prep_setjmp, {
- return getAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "STACKTOP; STACKTOP=(STACKTOP+168)|0;" + // XXX FIXME
+ return getAdHocAssign("_setjmpTable", Type::getInt32Ty(CI->getContext())) + "STACKTOP; STACKTOP=(STACKTOP+168)|0;" + // XXX FIXME
"HEAP32[_setjmpTable>>2]=0";
})
DEF_CALL_HANDLER(emscripten_setjmp, {
@@ -141,7 +141,7 @@ DEF_CALL_HANDLER(emscripten_longjmp, {
DEF_CALL_HANDLER(emscripten_check_longjmp, {
std::string Threw = getValueAsStr(CI->getOperand(0));
std::string Target = getJSName(CI);
- std::string Assign = getAssign(Target, CI->getType());
+ std::string Assign = getAssign(CI);
return "if (((" + Threw + "|0) != 0) & ((threwValue|0) != 0)) { " +
Assign + "_testSetjmp(HEAP32[" + Threw + ">>2]|0, _setjmpTable)|0; " +
"if ((" + Target + "|0) == 0) { _longjmp(" + Threw + "|0, threwValue|0); } " + // rethrow
@@ -150,13 +150,13 @@ DEF_CALL_HANDLER(emscripten_check_longjmp, {
})
DEF_CALL_HANDLER(emscripten_get_longjmp_result, {
std::string Threw = getValueAsStr(CI->getOperand(0));
- return getAssign(getJSName(CI), CI->getType()) + "tempRet0";
+ return getAssign(CI) + "tempRet0";
})
// i64 support
DEF_CALL_HANDLER(getHigh32, {
- return getAssign(getJSName(CI), CI->getType()) + "tempRet0";
+ return getAssign(CI) + "tempRet0";
})
DEF_CALL_HANDLER(setHigh32, {
return "tempRet0 = " + getValueAsStr(CI->getOperand(0));
@@ -166,20 +166,20 @@ DEF_CALL_HANDLER(setHigh32, {
DEF_CALL_HANDLER(low, { \
std::string Input = getValueAsStr(CI->getOperand(0)); \
if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Input; \
- return getAssign(getJSName(CI), CI->getType()) + "(~~" + Input + ")>>>0"; \
+ return getAssign(CI) + "(~~" + Input + ")>>>0"; \
}) \
DEF_CALL_HANDLER(high, { \
std::string Input = getValueAsStr(CI->getOperand(0)); \
if (PreciseF32 && CI->getOperand(0)->getType()->isFloatTy()) Input = "+" + Input; \
- return getAssign(getJSName(CI), CI->getType()) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295) | 0) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0"; \
+ return getAssign(CI) + "+Math_abs(" + Input + ") >= +1 ? " + Input + " > +0 ? (Math_min(+Math_floor(" + Input + " / +4294967296), +4294967295) | 0) >>> 0 : ~~+Math_ceil((" + Input + " - +(~~" + Input + " >>> 0)) / +4294967296) >>> 0 : 0"; \
})
TO_I(FtoILow, FtoIHigh);
TO_I(DtoILow, DtoIHigh);
DEF_CALL_HANDLER(BDtoILow, {
- return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";" + getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr>>2]|0";
+ return "HEAPF64[tempDoublePtr>>3] = " + getValueAsStr(CI->getOperand(0)) + ";" + getAssign(CI) + "HEAP32[tempDoublePtr>>2]|0";
})
DEF_CALL_HANDLER(BDtoIHigh, {
- return getAssign(getJSName(CI), CI->getType()) + "HEAP32[tempDoublePtr+4>>2]|0";
+ return getAssign(CI) + "HEAP32[tempDoublePtr+4>>2]|0";
})
DEF_CALL_HANDLER(SItoF, {
std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
@@ -187,7 +187,7 @@ DEF_CALL_HANDLER(SItoF, {
if (PreciseF32 && CI->getType()->isFloatTy()) {
Ret = "Math_fround(" + Ret + ")";
}
- return getAssign(getJSName(CI), CI->getType()) + Ret;
+ return getAssign(CI) + Ret;
})
DEF_CALL_HANDLER(UItoF, {
std::string Ret = "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
@@ -195,20 +195,20 @@ DEF_CALL_HANDLER(UItoF, {
if (PreciseF32 && CI->getType()->isFloatTy()) {
Ret = "Math_fround(" + Ret + ")";
}
- return getAssign(getJSName(CI), CI->getType()) + Ret;
+ return getAssign(CI) + Ret;
})
DEF_CALL_HANDLER(SItoD, {
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_SIGNED) + "))";
})
DEF_CALL_HANDLER(UItoD, {
- return getAssign(getJSName(CI), CI->getType()) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
+ return getAssign(CI) + "(+" + getValueAsCastParenStr(CI->getOperand(0), ASM_UNSIGNED) + ") + " +
"(+4294967296*(+" + getValueAsCastParenStr(CI->getOperand(1), ASM_UNSIGNED) + "))";
})
DEF_CALL_HANDLER(BItoD, {
return "HEAP32[tempDoublePtr>>2] = " + getValueAsStr(CI->getOperand(0)) + ";" +
"HEAP32[tempDoublePtr+4>>2] = " + getValueAsStr(CI->getOperand(1)) + ";" +
- getAssign(getJSName(CI), CI->getType()) + "+HEAPF64[tempDoublePtr>>3]";
+ getAssign(CI) + "+HEAPF64[tempDoublePtr>>3]";
})
// misc
@@ -323,7 +323,7 @@ DEF_CALL_HANDLER(llvm_memmove_p0i8_p0i8_i32, {
})
DEF_CALL_HANDLER(llvm_expect_i32, {
- return getAssign(getJSName(CI), CI->getType()) + getValueAsStr(CI->getOperand(0));
+ return getAssign(CI) + getValueAsStr(CI->getOperand(0));
})
DEF_CALL_HANDLER(llvm_dbg_declare, {
@@ -342,6 +342,18 @@ DEF_CALL_HANDLER(llvm_lifetime_end, {
return "";
})
+DEF_CALL_HANDLER(llvm_invariant_start, {
+ return "";
+})
+
+DEF_CALL_HANDLER(llvm_invariant_end, {
+ return "";
+})
+
+DEF_CALL_HANDLER(llvm_prefetch, {
+ return "";
+})
+
DEF_CALL_HANDLER(bitshift64Lshr, {
return CH___default__(CI, "_bitshift64Lshr", 3);
})
@@ -364,7 +376,7 @@ DEF_CALL_HANDLER(llvm_cttz_i32, {
// vector ops
DEF_CALL_HANDLER(emscripten_float32x4_signmask, {
- return getAssign(getJSName(CI), CI->getType()) + "SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + ").signMask";
+ return getAssign(CI) + "SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(0)) + ").signMask";
})
DEF_CALL_HANDLER(emscripten_float32x4_min, {
return CH___default__(CI, "SIMD.float32x4.min");
@@ -391,19 +403,19 @@ DEF_CALL_HANDLER(emscripten_float32x4_greaterThan, {
return CH___default__(CI, "SIMD.float32x4.greaterThan");
})
DEF_CALL_HANDLER(emscripten_float32x4_and, {
- return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(" +
+ return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.float32x4.bitsToInt32x4(" +
getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))";
})
DEF_CALL_HANDLER(emscripten_float32x4_andNot, {
- return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(" +
+ return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(SIMD.int32x4.not(SIMD.float32x4.bitsToInt32x4(" +
getValueAsStr(CI->getOperand(0)) + ")),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))";
})
DEF_CALL_HANDLER(emscripten_float32x4_or, {
- return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(" +
+ return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(SIMD.float32x4.bitsToInt32x4(" +
getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))";
})
DEF_CALL_HANDLER(emscripten_float32x4_xor, {
- return getAssign(getJSName(CI), CI->getType()) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(" +
+ return getAssign(CI) + "SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(SIMD.float32x4.bitsToInt32x4(" +
getValueAsStr(CI->getOperand(0)) + "),SIMD.float32x4.bitsToInt32x4(" + getValueAsStr(CI->getOperand(1)) + ")))";
})
DEF_CALL_HANDLER(emscripten_int32x4_bitsToFloat32x4, {
@@ -712,6 +724,9 @@ void setupCallHandlers() {
SETUP_CALL_HANDLER(llvm_dbg_value);
SETUP_CALL_HANDLER(llvm_lifetime_start);
SETUP_CALL_HANDLER(llvm_lifetime_end);
+ SETUP_CALL_HANDLER(llvm_invariant_start);
+ SETUP_CALL_HANDLER(llvm_invariant_end);
+ SETUP_CALL_HANDLER(llvm_prefetch);
SETUP_CALL_HANDLER(bitshift64Lshr);
SETUP_CALL_HANDLER(bitshift64Ashr);
SETUP_CALL_HANDLER(bitshift64Shl);
@@ -977,7 +992,12 @@ void setupCallHandlers() {
std::string handleCall(const Instruction *CI) {
const Value *CV = getActuallyCalledValue(CI);
assert(!isa<InlineAsm>(CV) && "asm() not supported, use EM_ASM() (see emscripten.h)");
- const std::string &Name = getJSName(CV);
+
+ // 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);
+
unsigned NumArgs = getNumArgOperands(CI);
CallHandlerMap::iterator CH = CallHandlers->find("___default__");
if (isa<Function>(CV)) {
diff --git a/lib/Target/JSBackend/JSBackend.cpp b/lib/Target/JSBackend/JSBackend.cpp
index a9d1aac129..a0c199e7db 100644
--- a/lib/Target/JSBackend/JSBackend.cpp
+++ b/lib/Target/JSBackend/JSBackend.cpp
@@ -15,8 +15,11 @@
//===----------------------------------------------------------------------===//
#include "JSTargetMachine.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
@@ -24,7 +27,9 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
@@ -34,6 +39,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/GetElementPtrTypeIterator.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/DebugInfo.h"
#include <algorithm>
@@ -341,28 +347,6 @@ namespace {
return false;
}
- std::string getPtrAsStr(const Value* Ptr) {
- Ptr = Ptr->stripPointerCasts();
- if (isa<const ConstantPointerNull>(Ptr) || isa<UndefValue>(Ptr)) return "0";
- if (const Function *F = dyn_cast<Function>(Ptr)) {
- return utostr(getFunctionIndex(F));
- } else if (const Constant *CV = dyn_cast<Constant>(Ptr)) {
- if (const BlockAddress *BA = dyn_cast<const BlockAddress>(Ptr)) {
- return utostr(getBlockAddress(BA));
- }
- if (const GlobalValue *GV = dyn_cast<GlobalValue>(Ptr)) {
- if (GV->isDeclaration()) {
- std::string Name = getOpName(Ptr);
- Externals.insert(Name);
- return Name;
- }
- }
- return utostr(getGlobalAddress(CV->getName().str()));
- } else {
- return getOpName(Ptr);
- }
- }
-
void checkVectorType(Type *T) {
VectorType *VT = cast<VectorType>(T);
assert(VT->getElementType()->getPrimitiveSizeInBits() == 32);
@@ -387,7 +371,9 @@ namespace {
void printType(Type* Ty);
void printTypes(const Module* M);
- std::string getAssign(const StringRef &, Type *);
+ std::string getAdHocAssign(const StringRef &, Type *);
+ std::string getAssign(const Instruction *I);
+ std::string getAssignIfNeeded(const Value *V);
std::string getCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED);
std::string getParenCast(const StringRef &, Type *, AsmCast sign=ASM_SIGNED);
std::string getDoubleToInt(const StringRef &);
@@ -397,8 +383,9 @@ namespace {
void addBlock(const BasicBlock *BB, Relooper& R, LLVMToRelooperMap& LLVMToRelooper);
void printFunctionBody(const Function *F);
- bool generateSIMDInstruction(const std::string &iName, const Instruction *I, raw_string_ostream& Code);
- void generateInstruction(const Instruction *I, raw_string_ostream& Code);
+ bool generateSIMDExpression(const User *I, raw_string_ostream& Code);
+ void generateExpression(const User *I, raw_string_ostream& Code);
+
std::string getOpName(const Value*);
void processConstants();
@@ -522,7 +509,7 @@ std::string JSWriter::getPhiCode(const BasicBlock *From, const BasicBlock *To) {
if (index < 0) continue;
// we found it
const std::string &name = getJSName(P);
- assigns[name] = getAssign(name, P->getType());
+ assigns[name] = getAssign(P);
const Value *V = P->getIncomingValue(index);
values[name] = V;
std::string vname = getValueAsStr(V);
@@ -550,7 +537,7 @@ std::string JSWriter::getPhiCode(const BasicBlock *From, const BasicBlock *To) {
// break a cycle
std::string depString = dep->second;
std::string temp = curr + "$phi";
- pre += getAssign(temp, V->getType()) + CV + ';';
+ pre += getAdHocAssign(temp, V->getType()) + CV + ';';
CV = temp;
deps.erase(curr);
undeps.erase(depString);
@@ -584,16 +571,26 @@ const std::string &JSWriter::getJSName(const Value* val) {
return ValueNames[val] = name;
}
-std::string JSWriter::getAssign(const StringRef &s, Type *t) {
+std::string JSWriter::getAdHocAssign(const StringRef &s, Type *t) {
UsedVars[s] = t->getTypeID();
return (s + " = ").str();
}
+std::string JSWriter::getAssign(const Instruction *I) {
+ return getAdHocAssign(getJSName(I), I->getType());
+}
+
+std::string JSWriter::getAssignIfNeeded(const Value *V) {
+ if (const Instruction *I = dyn_cast<Instruction>(V))
+ return getAssign(I);
+ return std::string();
+}
+
std::string JSWriter::getCast(const StringRef &s, Type *t, AsmCast sign) {
switch (t->getTypeID()) {
default: {
// some types we cannot cast, like vectors - ignore
- if (!t->isVectorTy()) assert(false && "Unsupported type");
+ if (!t->isVectorTy()) { errs() << *t << "\n"; assert(false && "Unsupported type");}
}
case Type::FloatTyID: {
if (PreciseF32 && !(sign & ASM_FFI_OUT)) {
@@ -656,8 +653,8 @@ std::string JSWriter::getIMul(const Value *V1, const Value *V2) {
}
std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, unsigned Alignment, char sep) {
- std::string Assign = getAssign(getJSName(I), I->getType());
- unsigned Bytes = T->getPrimitiveSizeInBits()/8;
+ std::string Assign = getAssign(I);
+ unsigned Bytes = DL->getTypeAllocSize(T);
std::string text;
if (Bytes <= Alignment || Alignment == 0) {
text = Assign + getPtrLoad(P);
@@ -672,7 +669,7 @@ std::string JSWriter::getLoad(const Instruction *I, const Value *P, Type *T, uns
emitDebugInfo(errs(), I);
errs() << "\n";
}
- std::string PS = getOpName(P);
+ std::string PS = getValueAsStr(P);
switch (Bytes) {
case 8: {
switch (Alignment) {
@@ -767,7 +764,7 @@ std::string JSWriter::getStore(const Instruction *I, const Value *P, Type *T, co
emitDebugInfo(errs(), I);
errs() << "\n";
}
- std::string PS = getOpName(P);
+ std::string PS = getValueAsStr(P);
switch (Bytes) {
case 8: {
text = "HEAPF64[tempDoublePtr>>3]=" + VS + ';';
@@ -894,121 +891,108 @@ std::string JSWriter::getPtrUse(const Value* Ptr) {
case 1: return "HEAP8[" + utostr(Addr) + "]";
}
} else {
- return getHeapAccess(getPtrAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy());
+ return getHeapAccess(getValueAsStr(Ptr), Bytes, t->isIntegerTy() || t->isPointerTy());
}
}
-static int hexToInt(char x) {
- if (x <= '9') {
- assert(x >= '0');
- return x - '0';
- } else {
- assert('A' <= x && x <= 'F');
- return x - 'A' + 10;
- }
-}
-
-/* static inline std::string ftostr(const APFloat& V) {
- std::string Buf;
- if (&V.getSemantics() == &APFloat::IEEEdouble) {
- raw_string_ostream(Buf) << V.convertToDouble();
- return Buf;
- } else if (&V.getSemantics() == &APFloat::IEEEsingle) {
- raw_string_ostream(Buf) << (double)V.convertToFloat();
- return Buf;
- }
- return "<unknown format in ftostr>"; // error
-} */
-
-static inline std::string ftostr_exact(const ConstantFP *CFP) {
+static inline std::string ftostr(const ConstantFP *CFP) {
const APFloat &flt = CFP->getValueAPF();
+
+ // Emscripten has its own spellings for infinity and NaN.
if (flt.getCategory() == APFloat::fcInfinity) return flt.isNegative() ? "-inf" : "inf";
else if (flt.getCategory() == APFloat::fcNaN) return "nan";
- std::string temp;
- raw_string_ostream stream(temp);
- stream << *CFP; // bitcast on APF produces odd results, so do it this horrible way
- const char *raw = temp.c_str();
- if (CFP->getType()->isFloatTy()) {
- raw += 6; // skip "float "
- } else {
- raw += 7; // skip "double "
- }
- if (raw[1] != 'x') return raw; // number has already been printed out
- raw += 2; // skip "0x"
- unsigned len = strlen(raw);
- if (len&1) {
- // uneven, need to add a 0 to make it be entire bytes
- temp = std::string("0") + raw;
- raw = temp.c_str();
- len++;
- }
- unsigned missing = 8 - len/2;
- union dbl { double d; unsigned char b[sizeof(double)]; } dbl;
- dbl.d = 0;
- for (unsigned i = 0; i < 8 - missing; i++) {
- dbl.b[7-i] = (hexToInt(raw[2*i]) << 4) |
- hexToInt(raw[2*i+1]);
- }
- char buffer[101];
- snprintf(buffer, 100, "%.30g", dbl.d);
- return buffer;
+ // Request 21 digits, aka DECIMAL_DIG, to avoid rounding errors.
+ SmallString<29> Str;
+ flt.toString(Str, 21);
+
+ // asm.js considers literals to be floating-point literals when they contain a
+ // dot, however our output may be processed by UglifyJS, which doesn't
+ // currently preserve dots in all cases. Mark floating-point literals with
+ // unary plus to force them to floating-point.
+ if (APFloat(flt).roundToIntegral(APFloat::rmNearestTiesToEven) == APFloat::opOK) {
+ return '+' + Str.str().str();
+ }
+
+ return Str.str().str();
}
std::string JSWriter::getConstant(const Constant* CV, AsmCast sign) {
- if (isa<PointerType>(CV->getType())) {
- return getPtrAsStr(CV);
- } else {
- if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
- std::string S = ftostr_exact(CFP);
- if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) {
- S = "Math_fround(+" + S + ")"; // FIXME: can avoid "+" for small enough constants
- } else if (S[0] != '+') {
- S = '+' + S;
- }
- return S;
- } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
- if (sign != ASM_UNSIGNED && CI->getValue().getBitWidth() == 1) {
- sign = ASM_UNSIGNED; // bools must always be unsigned: either 0 or 1
- }
- return CI->getValue().toString(10, sign != ASM_UNSIGNED);
- } else if (isa<UndefValue>(CV)) {
- return CV->getType()->isIntegerTy() || CV->getType()->isPointerTy() ? "0" : getCast("0", CV->getType());
- } else if (isa<ConstantAggregateZero>(CV)) {
- if (VectorType *VT = dyn_cast<VectorType>(CV->getType())) {
- if (VT->getElementType()->isIntegerTy()) {
- return "int32x4.splat(0)";
- } else {
- return "float32x4.splat(0)";
- }
+ if (isa<ConstantPointerNull>(CV)) return "0";
+
+ if (const Function *F = dyn_cast<Function>(CV)) {
+ return utostr(getFunctionIndex(F));
+ }
+
+ if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
+ if (GV->isDeclaration()) {
+ std::string Name = getOpName(GV);
+ Externals.insert(Name);
+ return Name;
+ }
+ return utostr(getGlobalAddress(GV->getName().str()));
+ }
+
+ if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
+ std::string S = ftostr(CFP);
+ if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) {
+ S = "Math_fround(" + S + ")";
+ }
+ return S;
+ } else if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
+ if (sign != ASM_UNSIGNED && CI->getValue().getBitWidth() == 1) {
+ sign = ASM_UNSIGNED; // bools must always be unsigned: either 0 or 1
+ }
+ return CI->getValue().toString(10, sign != ASM_UNSIGNED);
+ } else if (isa<UndefValue>(CV)) {
+ std::string S = CV->getType()->isFloatingPointTy() ? "+0" : "0"; // XXX refactor this
+ if (PreciseF32 && CV->getType()->isFloatTy() && !(sign & ASM_FFI_OUT)) {
+ S = "Math_fround(" + S + ")";
+ }
+ return S;
+ } else if (isa<ConstantAggregateZero>(CV)) {
+ if (VectorType *VT = dyn_cast<VectorType>(CV->getType())) {
+ if (VT->getElementType()->isIntegerTy()) {
+ return "int32x4.splat(0)";
} else {
- // something like [0 x i8*] zeroinitializer, which clang can emit for landingpads
- return "0";
+ return "float32x4.splat(0)";
}
- } else if (const ConstantDataVector *DV = dyn_cast<ConstantDataVector>(CV)) {
- const VectorType *VT = cast<VectorType>(CV->getType());
- if (VT->getElementType()->isIntegerTy()) {
- return "int32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' +
+ } else {
+ // something like [0 x i8*] zeroinitializer, which clang can emit for landingpads
+ return "0";
+ }
+ } else if (const ConstantDataVector *DV = dyn_cast<ConstantDataVector>(CV)) {
+ const VectorType *VT = cast<VectorType>(CV->getType());
+ if (VT->getElementType()->isIntegerTy()) {
+ return "int32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' +
+ getConstant(DV->getElementAsConstant(1)) + ',' +
+ getConstant(DV->getElementAsConstant(2)) + ',' +
+ getConstant(DV->getElementAsConstant(3)) + ')';
+ } else {
+ return "float32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' +
getConstant(DV->getElementAsConstant(1)) + ',' +
getConstant(DV->getElementAsConstant(2)) + ',' +
getConstant(DV->getElementAsConstant(3)) + ')';
- } else {
- return "float32x4(" + getConstant(DV->getElementAsConstant(0)) + ',' +
- getConstant(DV->getElementAsConstant(1)) + ',' +
- getConstant(DV->getElementAsConstant(2)) + ',' +
- getConstant(DV->getElementAsConstant(3)) + ')';
- }
- } else if (const ConstantArray *CA = dyn_cast<const ConstantArray>(CV)) {
- // handle things like [i8* bitcast (<{ i32, i32, i32 }>* @_ZTISt9bad_alloc to i8*)] which clang can emit for landingpads
- assert(CA->getNumOperands() == 1);
- CV = CA->getOperand(0);
- const ConstantExpr *CE = cast<ConstantExpr>(CV);
- CV = CE->getOperand(0); // ignore bitcast
- return getPtrAsStr(CV);
- } else {
- CV->dump();
- llvm_unreachable("Unsupported constant kind");
}
+ } else if (const ConstantArray *CA = dyn_cast<const ConstantArray>(CV)) {
+ // handle things like [i8* bitcast (<{ i32, i32, i32 }>* @_ZTISt9bad_alloc to i8*)] which clang can emit for landingpads
+ assert(CA->getNumOperands() == 1);
+ CV = CA->getOperand(0);
+ const ConstantExpr *CE = cast<ConstantExpr>(CV);
+ CV = CE->getOperand(0); // ignore bitcast
+ return getConstant(CV);
+ } else if (const BlockAddress *BA = dyn_cast<const BlockAddress>(CV)) {
+ return utostr(getBlockAddress(BA));
+ } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
+ std::string Code;
+ raw_string_ostream CodeStream(Code);
+ CodeStream << '(';
+ generateExpression(CE, CodeStream);
+ CodeStream << ')';
+ return CodeStream.str();
+ } else {
+ CV->dump();
+ llvm_unreachable("Unsupported constant kind");
}
}
@@ -1021,10 +1005,10 @@ std::string JSWriter::getValueAsStr(const Value* V, AsmCast sign) {
}
std::string JSWriter::getValueAsCastStr(const Value* V, AsmCast sign) {
- if (const Constant *CV = dyn_cast<Constant>(V)) {
- return getConstant(CV, sign);
+ if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) {
+ return getConstant(cast<Constant>(V), sign);
} else {
- return getCast(getJSName(V), V->getType(), sign);
+ return getCast(getValueAsStr(V), V->getType(), sign);
}
}
@@ -1032,39 +1016,38 @@ std::string JSWriter::getValueAsParenStr(const Value* V) {
if (const Constant *CV = dyn_cast<Constant>(V)) {
return getConstant(CV);
} else {
- return "(" + getJSName(V) + ")";
+ return "(" + getValueAsStr(V) + ")";
}
}
std::string JSWriter::getValueAsCastParenStr(const Value* V, AsmCast sign) {
- if (const Constant *CV = dyn_cast<Constant>(V)) {
- return getConstant(CV, sign);
+ if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) {
+ return getConstant(cast<Constant>(V), sign);
} else {
- return "(" + getCast(getJSName(V), V->getType(), sign) + ")";
+ return "(" + getCast(getValueAsStr(V), V->getType(), sign) + ")";
}
}
-bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instruction *I, raw_string_ostream& Code) {
+bool JSWriter::generateSIMDExpression(const User *I, raw_string_ostream& Code) {
VectorType *VT;
if ((VT = dyn_cast<VectorType>(I->getType()))) {
// vector-producing instructions
checkVectorType(VT);
- Code << getAssign(iName, I->getType());
-
- switch (I->getOpcode()) {
+ switch (Operator::getOpcode(I)) {
default: I->dump(); error("invalid vector instr"); break;
- case Instruction::FAdd: Code << "SIMD.float32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::FMul: Code << "SIMD.float32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::FDiv: Code << "SIMD.float32x4.div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::Add: Code << "SIMD.int32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::Sub: Code << "SIMD.int32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::Mul: Code << "SIMD.int32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::And: Code << "SIMD.int32x4.and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::Or: Code << "SIMD.int32x4.or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
- case Instruction::Xor: Code << "SIMD.int32x4.xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::FAdd: Code << getAssignIfNeeded(I) << "SIMD.float32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::FMul: Code << getAssignIfNeeded(I) << "SIMD.float32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::FDiv: Code << getAssignIfNeeded(I) << "SIMD.float32x4.div(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::Add: Code << getAssignIfNeeded(I) << "SIMD.int32x4.add(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::Sub: Code << getAssignIfNeeded(I) << "SIMD.int32x4.sub(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::Mul: Code << getAssignIfNeeded(I) << "SIMD.int32x4.mul(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::And: Code << getAssignIfNeeded(I) << "SIMD.int32x4.and(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::Or: Code << getAssignIfNeeded(I) << "SIMD.int32x4.or(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
+ case Instruction::Xor: Code << getAssignIfNeeded(I) << "SIMD.int32x4.xor(" << getValueAsStr(I->getOperand(0)) << "," << getValueAsStr(I->getOperand(1)) << ")"; break;
case Instruction::FSub:
// LLVM represents an fneg(x) as -0.0 - x.
+ Code << getAssignIfNeeded(I);
if (BinaryOperator::isFNeg(I)) {
Code << "SIMD.float32x4.neg(" << getValueAsStr(BinaryOperator::getFNegArgument(I)) << ")";
} else {
@@ -1072,6 +1055,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi
}
break;
case Instruction::BitCast: {
+ Code << getAssignIfNeeded(I);
if (cast<VectorType>(I->getType())->getElementType()->isIntegerTy()) {
Code << "SIMD.float32x4.bitsToInt32x4(" << getValueAsStr(I->getOperand(0)) << ')';
} else {
@@ -1080,7 +1064,10 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi
break;
}
case Instruction::Load: {
- std::string PS = getOpName(I->getOperand(0));
+ const LoadInst *LI = cast<LoadInst>(I);
+ const Value *P = LI->getPointerOperand();
+ std::string PS = getValueAsStr(P);
+ Code << getAssignIfNeeded(I);
if (VT->getElementType()->isIntegerTy()) {
Code << "int32x4(HEAPU32[" << PS << ">>2],HEAPU32[" << PS << "+4>>2],HEAPU32[" << PS << "+8>>2],HEAPU32[" << PS << "+12>>2])";
} else {
@@ -1093,6 +1080,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi
const ConstantInt *IndexInt = cast<const ConstantInt>(III->getOperand(2));
unsigned Index = IndexInt->getZExtValue();
assert(Index <= 3);
+ Code << getAssignIfNeeded(I);
if (VT->getElementType()->isIntegerTy()) {
Code << "SIMD.int32x4.with";
} else {
@@ -1103,6 +1091,7 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi
break;
}
case Instruction::ShuffleVector: {
+ Code << getAssignIfNeeded(I);
if (VT->getElementType()->isIntegerTy()) {
Code << "int32x4(";
} else {
@@ -1130,24 +1119,27 @@ bool JSWriter::generateSIMDInstruction(const std::string &iName, const Instructi
return true;
} else {
// vector-consuming instructions
- if (I->getOpcode() == Instruction::Store && (VT = dyn_cast<VectorType>(I->getOperand(0)->getType())) && VT->isVectorTy()) {
+ if (Operator::getOpcode(I) == Instruction::Store && (VT = dyn_cast<VectorType>(I->getOperand(0)->getType())) && VT->isVectorTy()) {
checkVectorType(VT);
- std::string PS = getOpName(I->getOperand(1));
- std::string VS = getValueAsStr(I->getOperand(0));
+ const StoreInst *SI = cast<StoreInst>(I);
+ const Value *P = SI->getPointerOperand();
+ std::string PS = getOpName(P);
+ std::string VS = getValueAsStr(SI->getValueOperand());
+ Code << getAdHocAssign(PS, P->getType()) << getValueAsStr(P) << ';';
if (VT->getElementType()->isIntegerTy()) {
Code << "HEAPU32[" << PS << ">>2]=" << VS << ".x;HEAPU32[" << PS << "+4>>2]=" << VS << ".y;HEAPU32[" << PS << "+8>>2]=" << VS << ".z;HEAPU32[" << PS << "+12>>2]=" << VS << ".w";
} else {
Code << "HEAPF32[" << PS << ">>2]=" << VS << ".x;HEAPF32[" << PS << "+4>>2]=" << VS << ".y;HEAPF32[" << PS << "+8>>2]=" << VS << ".z;HEAPF32[" << PS << "+12>>2]=" << VS << ".w";
}
return true;
- } else if (I->getOpcode() == Instruction::ExtractElement) {
+ } else if (Operator::getOpcode(I) == Instruction::ExtractElement) {
const ExtractElementInst *EEI = cast<ExtractElementInst>(I);
VT = cast<VectorType>(EEI->getVectorOperand()->getType());
checkVectorType(VT);
const ConstantInt *IndexInt = cast<const ConstantInt>(EEI->getIndexOperand());
unsigned Index = IndexInt->getZExtValue();
assert(Index <= 3);
- Code << getAssign(iName, I->getType());
+ Code << getAssignIfNeeded(I);
Code << getValueAsStr(EEI->getVectorOperand()) << '.' << simdLane[Index];
return true;
}
@@ -1159,17 +1151,15 @@ static uint64_t LSBMask(unsigned numBits) {
return numBits >= 64 ? 0xFFFFFFFFFFFFFFFFULL : (1ULL << numBits) - 1;
}
-// generateInstruction - This member is called for each Instruction in a function.
-void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Code) {
- const std::string &iName(getJSName(I));
-
+// Generate code for and operator, either an Instruction or a ConstantExpr.
+void JSWriter::generateExpression(const User *I, raw_string_ostream& Code) {
Type *T = I->getType();
if (T->isIntegerTy() && T->getIntegerBitWidth() > 32) {
errs() << *I << "\n";
report_fatal_error("legalization problem");
}
- if (!generateSIMDInstruction(iName, I, Code)) switch (I->getOpcode()) {
+ if (!generateSIMDExpression(I, Code)) switch (Operator::getOpcode(I)) {
default: {
I->dump();
error("Invalid instruction");
@@ -1180,16 +1170,14 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
const Value *RV = ret->getReturnValue();
Code << "STACKTOP = sp;";
Code << "return";
- if (RV == NULL) {
- Code << ";";
- } else {
- Code << " " << getValueAsCastStr(RV, ASM_NONSPECIFIC) << ";";
+ if (RV != NULL) {
+ Code << " " << getValueAsCastParenStr(RV, ASM_NONSPECIFIC);
}
break;
}
case Instruction::Br:
case Instruction::IndirectBr:
- case Instruction::Switch: break; // handled while relooping
+ case Instruction::Switch: return; // handled while relooping
case Instruction::Unreachable: {
// Typically there should be an abort right before these, so we don't emit any code // TODO: when ASSERTIONS are on, emit abort(0)
Code << "// unreachable";
@@ -1213,8 +1201,8 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:{
- Code << getAssign(iName, I->getType());
- unsigned opcode = I->getOpcode();
+ Code << getAssignIfNeeded(I);
+ unsigned opcode = Operator::getOpcode(I);
switch (opcode) {
case Instruction::Add: Code << getParenCast(
getValueAsParenStr(I->getOperand(0)) +
@@ -1270,13 +1258,12 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
Code << ensureFloat(getValueAsStr(I->getOperand(0)) + " - " + getValueAsStr(I->getOperand(1)), I->getType());
}