aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/JSBackend/JSBackend.cpp
diff options
context:
space:
mode:
authorDan Gohman <sunfish@google.com>2014-02-24 08:49:19 -0800
committerDan Gohman <sunfish@google.com>2014-02-25 11:58:56 -0800
commit338da97ed47659b9ef04f60067f84cafc93e3dd3 (patch)
tree2a80c78435712eafe02ea4afdc96c8d7713016cb /lib/Target/JSBackend/JSBackend.cpp
parent5653eb58d0b0068f0ef341c8928aa06d1d0ea3f7 (diff)
Support GEP and ConstantExprs directly in the JSBackend.
This patch also lays the groundwork for the single-use instruction trick to reduce the number of temporary variables.
Diffstat (limited to 'lib/Target/JSBackend/JSBackend.cpp')
-rw-r--r--lib/Target/JSBackend/JSBackend.cpp516
1 files changed, 279 insertions, 237 deletions
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());
}
break;
- default: error("bad icmp"); break;
+ default: error("bad binary opcode"); break;
}
- Code << ';';
break;
}
case Instruction::FCmp: {
- Code << getAssign(iName, I->getType());
+ Code << getAssignIfNeeded(I);
switch (cast<FCmpInst>(I)->getPredicate()) {
// Comparisons which are simple JS operators.
case FCmpInst::FCMP_OEQ: Code << getValueAsStr(I->getOperand(0)) << " == " << getValueAsStr(I->getOperand(1)); break;
@@ -1324,13 +1311,14 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
default: error("bad fcmp"); break;
}
- Code << ";";
break;
}
case Instruction::ICmp: {
- unsigned predicate = cast<ICmpInst>(I)->getPredicate();
+ unsigned predicate = isa<ConstantExpr>(I) ?
+ cast<ConstantExpr>(I)->getPredicate() :
+ cast<ICmpInst>(I)->getPredicate();
AsmCast sign = CmpInst::isUnsigned(predicate) ? ASM_UNSIGNED : ASM_SIGNED;
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << "(" <<
+ Code << getAssignIfNeeded(I) << "(" <<
getValueAsCastStr(I->getOperand(0), sign) <<
")";
switch (predicate) {
@@ -1348,23 +1336,23 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
}
Code << "(" <<
getValueAsCastStr(I->getOperand(1), sign) <<
- ");";
+ ")";
break;
}
case Instruction::Alloca: {
if (NativizedVars.count(I)) {
// nativized stack variable, we just need a 'var' definition
- UsedVars[iName] = cast<PointerType>(I->getType())->getElementType()->getTypeID();
- break;
+ UsedVars[getJSName(I)] = cast<PointerType>(I->getType())->getElementType()->getTypeID();
+ return;
}
const AllocaInst* AI = cast<AllocaInst>(I);
AllocaIntMap::iterator AIMI = StackAllocs.find(AI);
if (AIMI != StackAllocs.end()) {
// fixed-size allocation that is already taken into account in the big initial allocation
if (AIMI->second) {
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << "sp + " << utostr(AIMI->second) << "|0;";
+ Code << getAssign(AI) << "sp + " << utostr(AIMI->second) << "|0";
} else {
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << "sp;";
+ Code << getAssign(AI) << "sp";
}
break;
}
@@ -1377,7 +1365,7 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
} else {
Size = memAlignStr("((" + utostr(BaseSize) + '*' + getValueAsStr(AS) + ")|0)");
}
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << "STACKTOP; STACKTOP = STACKTOP + " << Size << "|0;";
+ Code << getAssign(AI) << "STACKTOP; STACKTOP = STACKTOP + " << Size << "|0";
break;
}
case Instruction::Load: {
@@ -1385,9 +1373,9 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
const Value *P = LI->getPointerOperand();
unsigned Alignment = LI->getAlignment();
if (NativizedVars.count(P)) {
- Code << getAssign(iName, LI->getType()) << getValueAsStr(P) << ';';
+ Code << getAssign(LI) << getValueAsStr(P);
} else {
- Code << getLoad(I, P, LI->getType(), Alignment) << ';';
+ Code << getLoad(LI, P, LI->getType(), Alignment);
}
break;
}
@@ -1398,9 +1386,9 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
unsigned Alignment = SI->getAlignment();
std::string VS = getValueAsStr(V);
if (NativizedVars.count(P)) {
- Code << getValueAsStr(P) << " = " << VS << ';';
+ Code << getValueAsStr(P) << " = " << VS;
} else {
- Code << getStore(I, P, V->getType(), VS, Alignment) << ';';
+ Code << getStore(SI, P, V->getType(), VS, Alignment);
}
Type *T = V->getType();
@@ -1411,18 +1399,43 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
break;
}
case Instruction::GetElementPtr: {
- report_fatal_error("Unlowered getelementptr");
+ Code << getAssignIfNeeded(I);
+ const GEPOperator *GEP = cast<GEPOperator>(I);
+ gep_type_iterator GTI = gep_type_begin(GEP);
+ int32_t ConstantOffset = 0;
+ std::string text = getValueAsParenStr(GEP->getPointerOperand());
+ for (GetElementPtrInst::const_op_iterator I = llvm::next(GEP->op_begin()),
+ E = GEP->op_end();
+ I != E; ++I) {
+ const Value *Index = *I;
+ if (StructType *STy = dyn_cast<StructType>(*GTI++)) {
+ // For a struct, add the member offset.
+ unsigned FieldNo = cast<ConstantInt>(Index)->getZExtValue();
+ uint32_t Offset = DL->getStructLayout(STy)->getElementOffset(FieldNo);
+ ConstantOffset = (uint32_t)ConstantOffset + Offset;
+ } else {
+ // For an array, add the element offset, explicitly scaled.
+ uint32_t ElementSize = DL->getTypeAllocSize(*GTI);
+ if (const ConstantInt *CI = dyn_cast<ConstantInt>(Index)) {
+ ConstantOffset = (uint32_t)ConstantOffset + (uint32_t)CI->getSExtValue() * ElementSize;
+ } else {
+ text = "(" + text + " + (" + getIMul(Index, ConstantInt::get(Type::getInt32Ty(GEP->getContext()), ElementSize)) + ")|0)";
+ }
+ }
+ }
+ if (ConstantOffset != 0) {
+ text = "(" + text + " + " + itostr(ConstantOffset) + "|0)";
+ }
+ Code << text;
break;
}
case Instruction::PHI: {
// handled separately - we push them back into the relooper branchings
- break;
+ return;
}
case Instruction::PtrToInt:
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << getPtrAsStr(I->getOperand(0)) << ';';
- break;
case Instruction::IntToPtr:
- Code << getAssign(iName, Type::getInt32Ty(I->getContext())) << getValueAsStr(I->getOperand(0)) << ";";
+ Code << getAssignIfNeeded(I) << getValueAsStr(I->getOperand(0));
break;
case Instruction::Trunc:
case Instruction::ZExt:
@@ -1433,8 +1446,8 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
case Instruction::FPToSI:
case Instruction::UIToFP:
case Instruction::SIToFP: {
- Code << getAssign(iName, I->getType());
- switch (I->getOpcode()) {
+ Code << getAssignIfNeeded(I);
+ switch (Operator::getOpcode(I)) {
case Instruction::Trunc: {
//unsigned inBits = V->getType()->getIntegerBitWidth();
unsigned outBits = I->getType()->getIntegerBitWidth();
@@ -1459,52 +1472,53 @@ void JSWriter::generateInstruction(const Instruction *I, raw_string_ostream& Cod
Code << ensureFloat(getValueAsStr(I->getOperand(0)), I->getType());
break;
}
- case Instruction::SIToFP: Code << getCast(getValueAsCastParenStr(I->getOperand(0), ASM_SIGNED), I->getType()); break;
- case Instruction::UIToFP: Code << getCast(getValueAsCastParenStr(I->getOperand(0), ASM_UNSIGNED), I->getType()); break;
- case Instruction::FPToSI: Code << getDoubleToInt(getValueAsParenStr(I->getOperand(0))); break;
- case Instruction::FPToUI: Code << getCast(getDoubleToInt(getValueAsParenStr(I->getOperand(0))), I->getType(), ASM_UNSIGNED); break;
- case Instruction::PtrToInt: Code << getValueAsStr(I->getOperand(0)); break;
- case Instruction::IntToPtr: Code << getValueAsStr(I->getOperand(0)); break;
+ case Instruction::SIToFP: Code << '(' << getCast(getValueAsCastParenStr(I->getOperand(0), ASM_SIGNED), I->getType()) << ')'; break;
+ case Instruction::UIToFP: Code << '('<< getCast(getValueAsCastParenStr(I->getOperand(0), ASM_UNSIGNED), I->getType()) << ')'; break;
+ case Instruction::FPToSI: Code << '('<< getDoubleToInt(getValueAsParenStr(I->getOperand(0))) << ')'; break;
+ case Instruction::FPToUI: Code << '('<< getCast(getDoubleToInt(getValueAsParenStr(I->getOperand(0))), I->getType(), ASM_UNSIGNED) << ')'; break;
+ case Instruction::PtrToInt: Code << '(' << getValueAsStr(I->getOperand(0)) << ')'; break;
+ case Instruction::IntToPtr: Code << '(' << getValueAsStr(I->getOperand(0)) << ')'; break;
default: llvm_unreachable("Unreachable");
}
- Code << ";";
break;
}
case Instruction::BitCast: {
- Code << getAssign(iName, I->getType());
+ Code << getAssignIfNeeded(I);
// Most bitcasts are no-ops for us. However, the exception is int to float and float to int
Type *InType = I->getOperand(0)->getType();
Type *OutType = I->getType();
std::string V = getValueAsStr(I->getOperand(0));
if (InType->isIntegerTy() && OutType->isFloatingPointTy()) {
assert(InType->getIntegerBitWidth() == 32);
- Code << "(HEAP32[tempDoublePtr>>2]=" << V << "," << getCast("HEAPF32[tempDoublePtr>>2]", Type::getFloatTy(TheModule->getContext())) + ");";
+ Code << "(HEAP32[tempDoublePtr>>2]=" << V << "," << getCast("HEAPF32[tempDoublePtr>>2]", Type::getFloatTy(TheModule->getContext())) + ")";
} else if (OutType->isIntegerTy() && InType->isFloatingPointTy()) {
assert(OutType->getIntegerBitWidth() == 32);
- Code << "(HEAPF32[tempDoublePtr>>2]=" << V << "," << "HEAP32[tempDoublePtr>>2]|0);";
+ Code << "(HEAPF32[tempDoublePtr>>2]=" << V << "," << "HEAP32[tempDoublePtr>>2]|0)";
} else {
- Code << V << ";";
+ Code << V;
}
break;
}
case Instruction::Call: {
const CallInst *CI = cast<CallInst>(I);
std::string Call = handleCall(CI);
- if (Call.size() > 0) Code << Call << ';';
+ if (Call.empty()) return;
+ Code << Call;
break;
}
case Instruction::Select: {
const SelectInst* SI = cast<SelectInst>(I);
- Code << getAssign(iName, I->getType()) << getValueAsStr(SI->getCondition()) << " ? " <<
- getValueAsStr(SI->getTrueValue()) << " : " <<
- getValueAsStr(SI->getFalseValue()) << ';';
+ Code << getAssignIfNeeded(I) << getValueAsStr(SI->getCondition()) << " ? " <<
+ getValueAsStr(SI->getTrueValue()) << " : " <<
+ getValueAsStr(SI->getFalseValue());
break;
}
case Instruction::AtomicCmpXchg: {
+ const AtomicCmpXchgInst *cxi = cast<AtomicCmpXchgInst>(I);
const Value *P = I->getOperand(0);
- Code << getLoad(I, P, I->getType(), 0) << ';' <<
- "if ((" << getCast(iName, I->getType()) << ") == " << getValueAsCastParenStr(I->getOperand(1)) << ") " <<
- getStore(I, P, I->getType(), getValueAsStr(I->getOperand(2)), 0) << ";";
+ Code << getLoad(cxi, P, I->getType(), 0) << ';' <<
+ "if ((" << getCast(getJSName(I), I->getType()) << ") == " << getValueAsCastParenStr(I->getOperand(1)) << ") " <<
+ getStore(cxi, P, I->getType(), getValueAsStr(I->getOpe