{
if (IR::Const *c1 = left->asConst()) {
if (IR::Const *c2 = right->asConst()) {
- const IR::Type ty = IR::Binop::typeForOp(op, left, right);
-
- switch (op) {
- case IR::OpAdd: return _block->CONST(ty, c1->value + c2->value);
- case IR::OpAnd: return _block->CONST(ty, c1->value ? c2->value : 0);
- case IR::OpBitAnd: return _block->CONST(ty, int(c1->value) & int(c2->value));
- case IR::OpBitOr: return _block->CONST(ty, int(c1->value) | int(c2->value));
- case IR::OpBitXor: return _block->CONST(ty, int(c1->value) ^ int(c2->value));
- case IR::OpDiv: return _block->CONST(ty, c1->value / c2->value);
- case IR::OpEqual: return _block->CONST(ty, c1->value == c2->value);
- case IR::OpGe: return _block->CONST(ty, c1->value >= c2->value);
- case IR::OpGt: return _block->CONST(ty, c1->value > c2->value);
- case IR::OpLe: return _block->CONST(ty, c1->value <= c2->value);
- case IR::OpLShift: return _block->CONST(ty, int(c1->value) << int(c2->value));
- case IR::OpLt: return _block->CONST(ty, c1->value < c2->value);
- case IR::OpMod: return _block->CONST(ty, ::fmod(c1->value, c2->value));
- case IR::OpMul: return _block->CONST(ty, c1->value * c2->value);
- case IR::OpNotEqual: return _block->CONST(ty, c1->value != c2->value);
- case IR::OpOr: return _block->CONST(ty, c1->value ? c1->value : c2->value);
- case IR::OpRShift: return _block->CONST(ty, int(c1->value) >> int(c2->value));
- case IR::OpStrictEqual: return _block->CONST(ty, c1->value == c2->value);
- case IR::OpStrictNotEqual: return _block->CONST(ty, c1->value != c2->value);
- case IR::OpSub: return _block->CONST(ty, c1->value - c2->value);
- case IR::OpURShift: return _block->CONST(ty, unsigned(c1->value) >> int(c2->value));
-
- case IR::OpInstanceof:
- case IR::OpIn:
- assert(!"unreachabe");
- break;
-
- case IR::OpIfTrue: // unary ops
- case IR::OpNot:
- case IR::OpUMinus:
- case IR::OpUPlus:
- case IR::OpCompl:
- case IR::OpInvalid:
- break;
+ if (c1->type == IR::NumberType && c2->type == IR::NumberType) {
+ const IR::Type ty = IR::NumberType;
+
+ switch (op) {
+ case IR::OpAdd: return _block->CONST(ty, c1->value + c2->value);
+ case IR::OpAnd: return _block->CONST(ty, c1->value ? c2->value : 0);
+ case IR::OpBitAnd: return _block->CONST(ty, int(c1->value) & int(c2->value));
+ case IR::OpBitOr: return _block->CONST(ty, int(c1->value) | int(c2->value));
+ case IR::OpBitXor: return _block->CONST(ty, int(c1->value) ^ int(c2->value));
+ case IR::OpDiv: return _block->CONST(ty, c1->value / c2->value);
+ case IR::OpEqual: return _block->CONST(ty, c1->value == c2->value);
+ case IR::OpGe: return _block->CONST(ty, c1->value >= c2->value);
+ case IR::OpGt: return _block->CONST(ty, c1->value > c2->value);
+ case IR::OpLe: return _block->CONST(ty, c1->value <= c2->value);
+ case IR::OpLShift: return _block->CONST(ty, int(c1->value) << int(c2->value));
+ case IR::OpLt: return _block->CONST(ty, c1->value < c2->value);
+ case IR::OpMod: return _block->CONST(ty, ::fmod(c1->value, c2->value));
+ case IR::OpMul: return _block->CONST(ty, c1->value * c2->value);
+ case IR::OpNotEqual: return _block->CONST(ty, c1->value != c2->value);
+ case IR::OpOr: return _block->CONST(ty, c1->value ? c1->value : c2->value);
+ case IR::OpRShift: return _block->CONST(ty, int(c1->value) >> int(c2->value));
+ case IR::OpStrictEqual: return _block->CONST(ty, c1->value == c2->value);
+ case IR::OpStrictNotEqual: return _block->CONST(ty, c1->value != c2->value);
+ case IR::OpSub: return _block->CONST(ty, c1->value - c2->value);
+ case IR::OpURShift: return _block->CONST(ty, unsigned(c1->value) >> int(c2->value));
+
+ case IR::OpInstanceof:
+ case IR::OpIn:
+ assert(!"unreachabe");
+ break;
+
+ case IR::OpIfTrue: // unary ops
+ case IR::OpNot:
+ case IR::OpUMinus:
+ case IR::OpUPlus:
+ case IR::OpCompl:
+ case IR::OpInvalid:
+ break;
+ }
}
}
} else if (op == IR::OpAdd) {
unsigned returnAddress = entryBlock->newTemp();
entryBlock->MOVE(entryBlock->TEMP(returnAddress), entryBlock->CONST(IR::UndefinedType, 0));
- exitBlock->RET(exitBlock->TEMP(returnAddress), IR::InvalidType);
+ exitBlock->RET(exitBlock->TEMP(returnAddress));
IR::ExprList *throwArgs = function->New<IR::ExprList>();
throwArgs->expr = throwBlock->TEMP(returnAddress);
throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
const char *typeName(Type t)
{
switch (t) {
- case InvalidType: return "invalid";
case UndefinedType: return "undefined";
case NullType: return "null";
- case VoidType: return "void";
- case StringType: return "string";
- case UrlType: return "QUrl";
- case ColorType: return "QColor";
- case SGAnchorLineType: return "SGAnchorLine";
- case AttachType: return "AttachType";
- case ObjectType: return "object";
- case VariantType: return "variant";
- case VarType: return "var";
case BoolType: return "bool";
- case IntType: return "int";
- case FloatType: return "float";
case NumberType: return "number";
default: return "invalid";
}
}
-inline bool isNumberType(IR::Type ty)
-{
- return ty >= IR::FirstNumberType;
-}
-
-inline bool isStringType(IR::Type ty)
-{
- return ty == IR::StringType || ty == IR::UrlType || ty == IR::ColorType;
-}
-
-IR::Type maxType(IR::Type left, IR::Type right)
-{
- if (isStringType(left) && isStringType(right)) {
- // String promotions (url to string) are more specific than
- // identity conversions (AKA left == right). That's because
- // we want to ensure we convert urls to strings in binary
- // expressions.
- return IR::StringType;
- } else if (left == right)
- return left;
- else if (isNumberType(left) && isNumberType(right)) {
- IR::Type ty = qMax(left, right);
- return ty == FloatType ? NumberType : ty; // promote floats
- } else if ((isNumberType(left) && isStringType(right)) ||
- (isNumberType(right) && isStringType(left)))
- return IR::StringType;
- else
- return IR::InvalidType;
-}
-
-bool isRealType(IR::Type type)
-{
- return type == IR::NumberType || type == IR::FloatType;
-}
-
const char *opname(AluOp op)
{
switch (op) {
case QQmlJS::IR::NullType:
out << "null";
break;
- case QQmlJS::IR::VoidType:
- out << "void";
- break;
case QQmlJS::IR::BoolType:
out << (value ? "true" : "false");
break;
return r;
}
-void Name::init(Type type, const QString *id, quint32 line, quint32 column)
+void Name::init(const QString *id, quint32 line, quint32 column)
{
- this->type = type;
this->id = id;
this->builtin = builtin_invalid;
this->line = line;
this->column = column;
}
-void Name::init(Type type, Builtin builtin, quint32 line, quint32 column)
+void Name::init(Builtin builtin, quint32 line, quint32 column)
{
- this->type = type;
this->id = 0;
this->builtin = builtin;
this->line = line;
expr->dump(out);
}
-Type Unop::typeForOp(AluOp op, Expr *expr)
-{
- switch (op) {
- case OpIfTrue: return BoolType;
- case OpNot: return BoolType;
-
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- return maxType(expr->type, NumberType);
-
- default:
- break;
- }
-
- return InvalidType;
-}
-
void Binop::dump(QTextStream &out)
{
left->dump(out);
right->dump(out);
}
-Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
-{
- if (! (left && right))
- return InvalidType;
-
- switch (op) {
- case OpInvalid:
- return InvalidType;
-
- // unary operators
- case OpIfTrue:
- case OpNot:
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- return InvalidType;
-
- // bit fields
- case OpBitAnd:
- case OpBitOr:
- case OpBitXor:
- return IntType;
-
- case OpAdd:
- if (left->type == StringType)
- return StringType;
- return NumberType;
-
- case OpSub:
- case OpMul:
- case OpDiv:
- case OpMod:
- return NumberType;
-
- case OpLShift:
- case OpRShift:
- case OpURShift:
- return IntType;
-
- case OpAnd:
- case OpOr:
- return BoolType;
-
- case OpGt:
- case OpLt:
- case OpGe:
- case OpLe:
- case OpEqual:
- case OpNotEqual:
- case OpStrictEqual:
- case OpStrictNotEqual:
- case OpInstanceof:
- case OpIn:
- return BoolType;
- } // switch
-
- return InvalidType;
-}
-
void Call::dump(QTextStream &out)
{
base->dump(out);
out << ')';
}
-Type Call::typeForFunction(Expr *)
-{
- return InvalidType;
-}
-
void New::dump(QTextStream &out)
{
out << "new ";
out << ')';
}
-Type New::typeForFunction(Expr *)
-{
- return InvalidType;
-}
-
void Subscript::dump(QTextStream &out)
{
base->dump(out);
Temp *BasicBlock::TEMP(int index)
{
Temp *e = function->New<Temp>();
- e->init(IR::InvalidType, index);
+ e->init(index);
return e;
}
-Expr *BasicBlock::CONST(Type type, double value)
+Expr *BasicBlock::CONST(Type type, double value)
{
Const *e = function->New<Const>();
e->init(type, value);
Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
{
Name *e = function->New<Name>();
- e->init(InvalidType, function->newString(id), line, column);
+ e->init(function->newString(id), line, column);
return e;
}
Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
{
Name *e = function->New<Name>();
- e->init(InvalidType, builtin, line, column);
+ e->init(builtin, line, column);
return e;
}
Closure *BasicBlock::CLOSURE(Function *function)
{
Closure *clos = function->New<Closure>();
- clos->init(IR::InvalidType, function);
+ clos->init(function);
return clos;
}
return s;
}
-Stmt *BasicBlock::RET(Temp *expr, Type type)
+Stmt *BasicBlock::RET(Temp *expr)
{
if (isTerminated())
return 0;
Ret *s = function->New<Ret>();
- s->init(expr, type);
+ s->init(expr);
statements.append(s);
return s;
}
const char *opname(IR::AluOp op);
enum Type {
- InvalidType,
UndefinedType,
NullType,
- VoidType,
- StringType,
- UrlType,
- ColorType,
- SGAnchorLineType,
- AttachType,
- ObjectType,
- VariantType,
- VarType,
-
- FirstNumberType,
- BoolType = FirstNumberType,
- IntType,
- FloatType,
+ BoolType,
NumberType
};
-Type maxType(IR::Type left, IR::Type right);
-bool isRealType(IR::Type type);
-const char *typeName(IR::Type t);
struct ExprVisitor {
virtual ~ExprVisitor() {}
};
struct Expr {
- Type type;
-
- Expr(): type(InvalidType) {}
virtual ~Expr() {}
virtual void accept(ExprVisitor *) = 0;
virtual Const *asConst() { return 0; }
};
struct Const: Expr {
+ Type type;
double value;
void init(Type type, double value)
void init(const QString *value)
{
- this->type = StringType;
this->value = value;
}
quint32 line;
quint32 column;
- void init(Type type, const QString *id, quint32 line, quint32 column);
- void init(Type type, Builtin builtin, quint32 line, quint32 column);
+ void init(const QString *id, quint32 line, quint32 column);
+ void init(Builtin builtin, quint32 line, quint32 column);
virtual void accept(ExprVisitor *v) { v->visitName(this); }
virtual Name *asName() { return this; }
struct Temp: Expr {
int index;
- void init(Type type, int index)
+ void init(int index)
{
- this->type = type;
this->index = index;
}
struct Closure: Expr {
Function *value;
- void init(Type type, Function *value)
+ void init(Function *value)
{
- this->type = type;
this->value = value;
}
void init(AluOp op, Temp *expr)
{
- this->type = this->typeForOp(op, expr);
this->op = op;
this->expr = expr;
}
virtual Unop *asUnop() { return this; }
virtual void dump(QTextStream &out);
-
-private:
- static Type typeForOp(AluOp op, Expr *expr);
};
struct Binop: Expr {
void init(AluOp op, Temp *left, Temp *right)
{
- this->type = typeForOp(op, left, right);
this->op = op;
this->left = left;
this->right = right;
virtual Binop *asBinop() { return this; }
virtual void dump(QTextStream &out);
-
- static Type typeForOp(AluOp op, Expr *left, Expr *right);
};
struct Call: Expr {
void init(Expr *base, ExprList *args)
{
- this->type = typeForFunction(base);
this->base = base;
this->args = args;
}
virtual Call *asCall() { return this; }
virtual void dump(QTextStream &out);
-
-private:
- static Type typeForFunction(Expr *base);
};
struct New: Expr {
void init(Expr *base, ExprList *args)
{
- this->type = typeForFunction(base);
this->base = base;
this->args = args;
}
virtual New *asNew() { return this; }
virtual void dump(QTextStream &out);
-
-private:
- static Type typeForFunction(Expr *base);
};
struct Subscript: Expr {
void init(Temp *base, Temp *index)
{
- this->type = typeForFunction(base);
this->base = base;
this->index = index;
}
virtual Subscript *asSubscript() { return this; }
virtual void dump(QTextStream &out);
-
-private:
- static Type typeForFunction(Expr *) { return IR::InvalidType; }
};
struct Member: Expr {
void init(Temp *base, const QString *name)
{
- this->type = typeForFunction(base);
this->base = base;
this->name = name;
}
virtual Member *asMember() { return this; }
virtual void dump(QTextStream &out);
-
-private:
- static Type typeForFunction(Expr *) { return IR::InvalidType; }
};
struct Stmt {
struct Ret: Stmt {
Temp *expr;
- Type type;
- void init(Temp *expr, Type type)
+ void init(Temp *expr)
{
this->expr = expr;
- this->type = type;
}
virtual Stmt *asTerminator() { return this; }
Stmt *JUMP(BasicBlock *target);
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
- Stmt *RET(Temp *expr, Type type);
+ Stmt *RET(Temp *expr);
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
};