From da3dfe8e6b03d16634063b6315d903a0fa2cd654 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 10 Jun 2013 16:32:48 +0200 Subject: [PATCH] Add type conversion nodes to the IR. Change-Id: I5a5a69ccd2e2f2f3c9f8592c4b04455d6a567e83 Reviewed-by: Simon Hausmann --- src/qml/qml/v4/moth/qv4isel_moth.cpp | 6 ++ src/qml/qml/v4/moth/qv4isel_moth_p.h | 1 + src/qml/qml/v4/qv4isel_masm.cpp | 6 ++ src/qml/qml/v4/qv4isel_masm_p.h | 3 +- src/qml/qml/v4/qv4isel_p.cpp | 4 + src/qml/qml/v4/qv4isel_p.h | 1 + src/qml/qml/v4/qv4jsir.cpp | 25 +++++++ src/qml/qml/v4/qv4jsir_p.h | 20 +++++ src/qml/qml/v4/qv4ssa.cpp | 141 ++++++++++++++++++++++++++++++----- 9 files changed, 186 insertions(+), 21 deletions(-) diff --git a/src/qml/qml/v4/moth/qv4isel_moth.cpp b/src/qml/qml/v4/moth/qv4isel_moth.cpp index 9371806..e4a3738 100644 --- a/src/qml/qml/v4/moth/qv4isel_moth.cpp +++ b/src/qml/qml/v4/moth/qv4isel_moth.cpp @@ -187,6 +187,12 @@ void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4 addInstruction(call); } +void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target) +{ + // FIXME: do something more useful with this info + copyValue(source, target); +} + void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) diff --git a/src/qml/qml/v4/moth/qv4isel_moth_p.h b/src/qml/qml/v4/moth/qv4isel_moth_p.h index 09d9de7..e969e33 100644 --- a/src/qml/qml/v4/moth/qv4isel_moth_p.h +++ b/src/qml/qml/v4/moth/qv4isel_moth_p.h @@ -58,6 +58,7 @@ protected: virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result); + virtual void convertType(V4IR::Temp *source, V4IR::Temp *target); virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result); virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); diff --git a/src/qml/qml/v4/qv4isel_masm.cpp b/src/qml/qml/v4/qv4isel_masm.cpp index 7a5467f..867100d 100644 --- a/src/qml/qml/v4/qv4isel_masm.cpp +++ b/src/qml/qml/v4/qv4isel_masm.cpp @@ -1137,6 +1137,12 @@ void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4 Assembler::TrustedImm32(argc)); } +void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target) +{ + // FIXME: do something more useful with this info + copyValue(source, target); +} + String *InstructionSelection::identifier(const QString &s) { String *str = engine()->newIdentifier(s); diff --git a/src/qml/qml/v4/qv4isel_masm_p.h b/src/qml/qml/v4/qv4isel_masm_p.h index 8f47323..dc0299a 100644 --- a/src/qml/qml/v4/qv4isel_masm_p.h +++ b/src/qml/qml/v4/qv4isel_masm_p.h @@ -792,9 +792,10 @@ protected: virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value); virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args); virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args); + virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result); - virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); + virtual void convertType(V4IR::Temp *source, V4IR::Temp *target); virtual void loadThisObject(V4IR::Temp *temp); virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp); virtual void loadString(const QString &str, V4IR::Temp *targetTemp); diff --git a/src/qml/qml/v4/qv4isel_p.cpp b/src/qml/qml/v4/qv4isel_p.cpp index 48678d8..3f9d599 100644 --- a/src/qml/qml/v4/qv4isel_p.cpp +++ b/src/qml/qml/v4/qv4isel_p.cpp @@ -149,6 +149,10 @@ void InstructionSelection::visitMove(V4IR::Move *s) callValue(value, c->args, t); return; } + } else if (V4IR::Convert *c = s->source->asConvert()) { + Q_ASSERT(c->expr->asTemp()); + convertType(c->expr->asTemp(), t); + return; } } else if (V4IR::Member *m = s->target->asMember()) { if (V4IR::Temp *base = m->base->asTemp()) { diff --git a/src/qml/qml/v4/qv4isel_p.h b/src/qml/qml/v4/qv4isel_p.h index be30e06..e0c202d 100644 --- a/src/qml/qml/v4/qv4isel_p.h +++ b/src/qml/qml/v4/qv4isel_p.h @@ -131,6 +131,7 @@ public: // to implement by subclasses: virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0; + virtual void convertType(V4IR::Temp *source, V4IR::Temp *target) = 0; virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0; diff --git a/src/qml/qml/v4/qv4jsir.cpp b/src/qml/qml/v4/qv4jsir.cpp index 6957067..fd0b866 100644 --- a/src/qml/qml/v4/qv4jsir.cpp +++ b/src/qml/qml/v4/qv4jsir.cpp @@ -238,6 +238,11 @@ struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor virtual void visitTemp(Temp *) {} virtual void visitClosure(Closure *) {} + virtual void visitConvert(Convert *e) + { + e->expr = cleanup(e->expr); + } + virtual void visitUnop(Unop *e) { e->expr = cleanup(e->expr); @@ -452,6 +457,14 @@ void Closure::dump(QTextStream &out) out << "closure(" << name << ')'; } +void Convert::dump(QTextStream &out) +{ + out << dumpStart(this); + out << "convert("; + expr->dump(out); + out << ')' << dumpEnd(this); +} + void Unop::dump(QTextStream &out) { out << dumpStart(this) << opname(op); @@ -733,6 +746,13 @@ Closure *BasicBlock::CLOSURE(Function *function) return clos; } +Expr *BasicBlock::CONVERT(Expr *expr, Type type) +{ + Convert *e = function->New(); + e->init(expr, type); + return e; +} + Expr *BasicBlock::UNOP(AluOp op, Expr *expr) { Unop *e = function->New(); @@ -981,6 +1001,11 @@ void CloneExpr::visitClosure(Closure *e) cloned = block->CLOSURE(e->value); } +void CloneExpr::visitConvert(Convert *e) +{ + cloned = block->CONVERT(clone(e->expr), e->type); +} + void CloneExpr::visitUnop(Unop *e) { cloned = block->UNOP(e->op, clone(e->expr)); diff --git a/src/qml/qml/v4/qv4jsir_p.h b/src/qml/qml/v4/qv4jsir_p.h index b78654a..c873344 100644 --- a/src/qml/qml/v4/qv4jsir_p.h +++ b/src/qml/qml/v4/qv4jsir_p.h @@ -103,6 +103,7 @@ struct RegExp; struct Name; struct Temp; struct Closure; +struct Convert; struct Unop; struct Binop; struct Call; @@ -192,6 +193,7 @@ struct ExprVisitor { virtual void visitName(Name *) = 0; virtual void visitTemp(Temp *) = 0; virtual void visitClosure(Closure *) = 0; + virtual void visitConvert(Convert *) = 0; virtual void visitUnop(Unop *) = 0; virtual void visitBinop(Binop *) = 0; virtual void visitCall(Call *) = 0; @@ -226,6 +228,7 @@ struct Expr { virtual Name *asName() { return 0; } virtual Temp *asTemp() { return 0; } virtual Closure *asClosure() { return 0; } + virtual Convert *asConvert() { return 0; } virtual Unop *asUnop() { return 0; } virtual Binop *asBinop() { return 0; } virtual Call *asCall() { return 0; } @@ -367,6 +370,21 @@ struct Closure: Expr { virtual void dump(QTextStream &out); }; +struct Convert: Expr { + Expr *expr; + + void init(Expr *expr, Type type) + { + this->expr = expr; + this->type = type; + } + + virtual void accept(ExprVisitor *v) { v->visitConvert(this); } + virtual Convert *asConvert() { return this; } + + virtual void dump(QTextStream &out); +}; + struct Unop: Expr { AluOp op; Expr *expr; @@ -786,6 +804,7 @@ struct BasicBlock { Closure *CLOSURE(Function *function); + Expr *CONVERT(Expr *expr, Type type); Expr *UNOP(AluOp op, Expr *expr); Expr *BINOP(AluOp op, Expr *left, Expr *right); Expr *CALL(Expr *base, ExprList *args = 0); @@ -854,6 +873,7 @@ protected: virtual void visitName(Name *); virtual void visitTemp(Temp *); virtual void visitClosure(Closure *); + virtual void visitConvert(Convert *); virtual void visitUnop(Unop *); virtual void visitBinop(Binop *); virtual void visitCall(Call *); diff --git a/src/qml/qml/v4/qv4ssa.cpp b/src/qml/qml/v4/qv4ssa.cpp index 82a6506..f7daf26 100644 --- a/src/qml/qml/v4/qv4ssa.cpp +++ b/src/qml/qml/v4/qv4ssa.cpp @@ -447,6 +447,7 @@ public: protected: virtual void visitPhi(Phi *) {}; + virtual void visitConvert(Convert *e) { e->expr->accept(this); }; virtual void visitConst(Const *) {} virtual void visitString(String *) {} @@ -683,6 +684,7 @@ protected: tempMapping[newIdx] = origIdx; } + virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitPhi(Phi *s) { renameTemp(s->targetTemp); } virtual void visitExp(Exp *s) { s->expr->accept(this); } @@ -894,6 +896,7 @@ protected: virtual void visitRegExp(RegExp *) {} virtual void visitName(Name *) {} virtual void visitClosure(Closure *) {} + virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitUnop(Unop *e) { e->expr->accept(this); } virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); } virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); } @@ -1034,6 +1037,11 @@ protected: virtual void visitTemp(Temp *e) { } virtual void visitClosure(Closure *) {} + virtual void visitConvert(Convert *e) { + // we do not have type information yet, so: + _sideEffect = true; + } + virtual void visitUnop(Unop *e) { switch (e->op) { case V4IR::OpIncrement: @@ -1181,6 +1189,10 @@ protected: setType(e, _ty.type); } virtual void visitClosure(Closure *) { _ty = TypingResult(ObjectType); } // TODO: VERIFY THIS! + virtual void visitConvert(Convert *e) { + _ty = run(e->expr); + } + virtual void visitUnop(Unop *e) { _ty = run(e->expr); switch (e->op) { @@ -1318,19 +1330,69 @@ protected: class TypePropagation: public StmtVisitor, public ExprVisitor { Type _ty; - void run(Expr *e, Type requestedType = UnknownType) { + void run(Expr *&e, Type requestedType = UnknownType) { qSwap(_ty, requestedType); e->accept(this); qSwap(_ty, requestedType); + + if (requestedType != UnknownType) + if (e->type != requestedType) + if (requestedType & NumberType) { + qDebug()<<"adding conversion from"<type)<<"to"< _conversions; + + void addConversion(Expr *&expr, Type targetType) { + _conversions.append(Conversion(&expr, targetType, _currStmt)); } public: TypePropagation() : _ty(UnknownType) {} void run(Function *f) { - foreach (BasicBlock *bb, f->basicBlocks) - foreach (Stmt *s, bb->statements) + foreach (BasicBlock *bb, f->basicBlocks) { + _conversions.clear(); + + foreach (Stmt *s, bb->statements) { + _currStmt = s; s->accept(this); + } + + foreach (const Conversion &conversion, _conversions) { + if (conversion.stmt->asMove() && conversion.stmt->asMove()->source->asTemp()) { + *conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType); + } else { + Temp *target = bb->TEMP(bb->newTemp()); + target->type = conversion.targetType; + Expr *convert = bb->CONVERT(*conversion.expr, conversion.targetType); + Move *convCall = f->New(); + convCall->init(target, convert, OpInvalid); + + Temp *source = bb->TEMP(target->index); + source->type = conversion.targetType; + *conversion.expr = source; + + int idx = bb->statements.indexOf(conversion.stmt); + bb->statements.insert(idx, convCall); + } + } + } } protected: @@ -1345,8 +1407,57 @@ protected: virtual void visitName(Name *) {} virtual void visitTemp(Temp *) {} virtual void visitClosure(Closure *) {} + virtual void visitConvert(Convert *e) { run(e->expr, e->type); } virtual void visitUnop(Unop *e) { run(e->expr, e->type); } - virtual void visitBinop(Binop *e) { run(e->left, e->type); run(e->right, e->type); } + virtual void visitBinop(Binop *e) { + // FIXME: This routine needs more tuning! + switch (e->op) { + case OpAdd: + case OpSub: + case OpMul: + case OpDiv: + case OpMod: + case OpBitAnd: + case OpBitOr: + case OpBitXor: + case OpLShift: + case OpRShift: + case OpURShift: + run(e->left, e->type); + run(e->right, e->type); + break; + + case OpGt: + case OpLt: + case OpGe: + case OpLe: + if (e->left->type == DoubleType) + run(e->right, DoubleType); + else if (e->right->type == DoubleType) + run(e->left, DoubleType); + else { + run(e->left, e->type); + run(e->right, e->type); + } + break; + + case OpEqual: + case OpNotEqual: + case OpStrictEqual: + case OpStrictNotEqual: + break; + + case OpInstanceof: + case OpIn: + run(e->left, e->type); + run(e->right, e->type); + break; + + default: + Q_UNIMPLEMENTED(); + Q_UNREACHABLE(); + } + } virtual void visitCall(Call *e) { run(e->base); for (ExprList *it = e->args; it; it = it->next) @@ -1375,11 +1486,15 @@ protected: virtual void visitPhi(Phi *s) { Type ty = s->targetTemp->type; foreach (Expr *e, s->incoming) - run(e, ty); + if (e->asConst()) + run(e, ty); } }; void insertMove(Function *function, BasicBlock *basicBlock, Temp *target, Expr *source) { + if (target->type != source->type) + source = basicBlock->CONVERT(source, target->type); + Move *s = function->New(); s->init(target, source, OpInvalid); basicBlock->statements.insert(basicBlock->statements.size() - 1, s); @@ -1672,22 +1787,8 @@ void QQmlJS::linearize(V4IR::Function *function) function->basicBlocks[i]->index = i; } #endif - function->removeSharedExpressions(); -// if (qgetenv("NO_OPT").isEmpty()) -// ConstantPropagation().run(function); - -//#ifndef QV4_NO_LIVENESS -// liveness(function); -//#endif -// if (qgetenv("NO_OPT").isEmpty()) { -// removeDeadAssignments(function); -// removeUnreachableBlocks(function); -// } - -// showMeTheCode(function); -// splitEdges(function); -// showMeTheCode(function); + function->removeSharedExpressions(); // showMeTheCode(function); -- 2.7.4