Commit ae6d1c53 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Implement AugAssign (ie '+=' and friends)

parent 8130abc9
...@@ -208,9 +208,9 @@ OPTIONAL_SRCS := codegen/profiling/oprofile.cpp codegen/profiling/pprof.cpp ...@@ -208,9 +208,9 @@ OPTIONAL_SRCS := codegen/profiling/oprofile.cpp codegen/profiling/pprof.cpp
TOOL_SRCS := $(wildcard $(TOOLS_DIR)/*.cpp) TOOL_SRCS := $(wildcard $(TOOLS_DIR)/*.cpp)
NONSTDLIB_SRCS := $(MAIN_SRCS) $(OPTIONAL_SRCS) $(TOOL_SRCS) NONSTDLIB_SRCS := $(MAIN_SRCS) $(OPTIONAL_SRCS) $(TOOL_SRCS)
# .DEFAULT_GOAL := pyston_dbg .DEFAULT_GOAL := pyston_dbg
_ : # _ :
$(MAKE) pyston_dbg || (clear; $(MAKE) pyston_dbg -j1 ERROR_LIMIT=1) # $(MAKE) pyston_dbg || (clear; $(MAKE) pyston_dbg -j1 ERROR_LIMIT=1)
.PHONY: all _all .PHONY: all _all
all: llvm all: llvm
......
...@@ -204,6 +204,11 @@ class DefinednessVisitor : public ASTVisitor { ...@@ -204,6 +204,11 @@ class DefinednessVisitor : public ASTVisitor {
return true; return true;
} }
virtual bool visit_augassign(AST_AugAssign *node) {
_doSet(node->target);
return true;
}
virtual bool visit_arguments(AST_arguments *node) { virtual bool visit_arguments(AST_arguments *node) {
if (node->kwarg) _doSet(node->kwarg); if (node->kwarg) _doSet(node->kwarg);
if (node->vararg.size()) _doSet(node->vararg); if (node->vararg.size()) _doSet(node->vararg);
......
...@@ -163,6 +163,7 @@ class NameCollectorVisitor : public ASTVisitor { ...@@ -163,6 +163,7 @@ class NameCollectorVisitor : public ASTVisitor {
virtual bool visit_arguments(AST_arguments *node) { return false; } virtual bool visit_arguments(AST_arguments *node) { return false; }
virtual bool visit_assign(AST_Assign *node) { return false; } virtual bool visit_assign(AST_Assign *node) { return false; }
virtual bool visit_augassign(AST_AugAssign *node) { return false; }
virtual bool visit_attribute(AST_Attribute *node) { return false; } virtual bool visit_attribute(AST_Attribute *node) { return false; }
virtual bool visit_binop(AST_BinOp *node) { return false; } virtual bool visit_binop(AST_BinOp *node) { return false; }
virtual bool visit_boolop(AST_BoolOp *node) { return false; } virtual bool visit_boolop(AST_BoolOp *node) { return false; }
......
...@@ -346,6 +346,22 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor { ...@@ -346,6 +346,22 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
} }
} }
virtual void visit_augassign(AST_AugAssign* node) {
CompilerType *t = getType(node->target);
CompilerType *v = getType(node->value);
// TODO this isn't the right behavior
std::string name = getOpName(node->op_type);
name = "__i" + name.substr(2);
CompilerType *attr_type = t->getattrType(name);
std::vector<CompilerType*> arg_types;
arg_types.push_back(v);
CompilerType *rtn = attr_type->callType(arg_types);
_doSet(node->target, rtn);
}
virtual void visit_branch(AST_Branch* node) { virtual void visit_branch(AST_Branch* node) {
if (EXPAND_UNNEEDED) { if (EXPAND_UNNEEDED) {
getType(node->test); getType(node->test);
......
...@@ -519,6 +519,7 @@ class IRGenerator { ...@@ -519,6 +519,7 @@ class IRGenerator {
} }
enum BinExpType { enum BinExpType {
AugAssign,
BinOp, BinOp,
Compare, Compare,
}; };
...@@ -536,7 +537,7 @@ class IRGenerator { ...@@ -536,7 +537,7 @@ class IRGenerator {
v = emitter.getBuilder()->CreateCall2(g.funcs.div_i64_i64, converted_left->getValue(), converted_right->getValue()); v = emitter.getBuilder()->CreateCall2(g.funcs.div_i64_i64, converted_left->getValue(), converted_right->getValue());
} else if (type == AST_TYPE::Pow) { } else if (type == AST_TYPE::Pow) {
v = emitter.getBuilder()->CreateCall2(g.funcs.pow_i64_i64, converted_left->getValue(), converted_right->getValue()); v = emitter.getBuilder()->CreateCall2(g.funcs.pow_i64_i64, converted_left->getValue(), converted_right->getValue());
} else if (exp_type == BinOp) { } else if (exp_type == BinOp || exp_type == AugAssign) {
llvm::Instruction::BinaryOps binopcode; llvm::Instruction::BinaryOps binopcode;
switch (type) { switch (type) {
case AST_TYPE::Add: case AST_TYPE::Add:
...@@ -626,7 +627,7 @@ class IRGenerator { ...@@ -626,7 +627,7 @@ class IRGenerator {
v = emitter.getBuilder()->CreateCall2(g.funcs.div_float_float, converted_left->getValue(), converted_right->getValue()); v = emitter.getBuilder()->CreateCall2(g.funcs.div_float_float, converted_left->getValue(), converted_right->getValue());
} else if (type == AST_TYPE::Pow) { } else if (type == AST_TYPE::Pow) {
v = emitter.getBuilder()->CreateCall2(g.funcs.pow_float_float, converted_left->getValue(), converted_right->getValue()); v = emitter.getBuilder()->CreateCall2(g.funcs.pow_float_float, converted_left->getValue(), converted_right->getValue());
} else if (exp_type == BinOp) { } else if (exp_type == BinOp || exp_type == AugAssign) {
llvm::Instruction::BinaryOps binopcode; llvm::Instruction::BinaryOps binopcode;
switch (type) { switch (type) {
case AST_TYPE::Add: case AST_TYPE::Add:
...@@ -707,6 +708,9 @@ class IRGenerator { ...@@ -707,6 +708,9 @@ class IRGenerator {
if (exp_type == BinOp) { if (exp_type == BinOp) {
rt_func = g.funcs.binop; rt_func = g.funcs.binop;
rt_func_addr = (void*)binop; rt_func_addr = (void*)binop;
} else if (exp_type == AugAssign) {
rt_func = g.funcs.augassign;
rt_func_addr = (void*)augassign;
} else { } else {
rt_func = g.funcs.compare; rt_func = g.funcs.compare;
rt_func_addr = (void*)compare; rt_func_addr = (void*)compare;
...@@ -1485,6 +1489,29 @@ class IRGenerator { ...@@ -1485,6 +1489,29 @@ class IRGenerator {
val->decvref(emitter); val->decvref(emitter);
} }
void doAugAssign(AST_AugAssign *node) {
CompilerVariable *target = evalExpr(node->target);
_setFake(_nodeFakeName(0, node), target); // 'fakes' are for handling deopt entries
CompilerVariable *val = evalExpr(node->value);
_setFake(_nodeFakeName(1, node), val);
if (state == PARTIAL) {
_clearFake(_nodeFakeName(0, node));
_clearFake(_nodeFakeName(1, node));
return;
}
target = _getFake(_nodeFakeName(0, node));
val = _getFake(_nodeFakeName(1, node));
CompilerVariable *rtn = this->_evalBinExp(target, val, node->op_type, AugAssign);
target->decvref(emitter);
val->decvref(emitter);
_doSet(node->target, rtn);
rtn->decvref(emitter);
}
void doClassDef(AST_ClassDef *node) { void doClassDef(AST_ClassDef *node) {
if (state == PARTIAL) if (state == PARTIAL)
return; return;
...@@ -1621,7 +1648,7 @@ class IRGenerator { ...@@ -1621,7 +1648,7 @@ class IRGenerator {
endBlock(DEAD); endBlock(DEAD);
assert(rtn->getVrefs() == 1); ASSERT(rtn->getVrefs() == 1, "%d", rtn->getVrefs());
emitter.getBuilder()->CreateRet(rtn->getValue()); emitter.getBuilder()->CreateRet(rtn->getValue());
} }
...@@ -1820,6 +1847,9 @@ class IRGenerator { ...@@ -1820,6 +1847,9 @@ class IRGenerator {
case AST_TYPE::Assign: case AST_TYPE::Assign:
doAssign(static_cast<AST_Assign*>(node)); doAssign(static_cast<AST_Assign*>(node));
break; break;
case AST_TYPE::AugAssign:
doAugAssign(static_cast<AST_AugAssign*>(node));
break;
case AST_TYPE::ClassDef: case AST_TYPE::ClassDef:
doClassDef(static_cast<AST_ClassDef*>(node)); doClassDef(static_cast<AST_ClassDef*>(node));
break; break;
......
...@@ -179,6 +179,17 @@ AST_Assign* read_assign(BufferedReader *reader) { ...@@ -179,6 +179,17 @@ AST_Assign* read_assign(BufferedReader *reader) {
return rtn; return rtn;
} }
AST_AugAssign* read_augassign(BufferedReader *reader) {
AST_AugAssign *rtn = new AST_AugAssign();
rtn->col_offset = readColOffset(reader);
rtn->lineno = reader->readULL();
rtn->op_type = (AST_TYPE::AST_TYPE)reader->readByte();
rtn->target = readASTExpr(reader);
rtn->value = readASTExpr(reader);
return rtn;
}
AST_Attribute* read_attribute(BufferedReader *reader) { AST_Attribute* read_attribute(BufferedReader *reader) {
AST_Attribute *rtn = new AST_Attribute(); AST_Attribute *rtn = new AST_Attribute();
...@@ -622,6 +633,8 @@ AST_stmt* readASTStmt(BufferedReader *reader) { ...@@ -622,6 +633,8 @@ AST_stmt* readASTStmt(BufferedReader *reader) {
switch (type) { switch (type) {
case AST_TYPE::Assign: case AST_TYPE::Assign:
return read_assign(reader); return read_assign(reader);
case AST_TYPE::AugAssign:
return read_augassign(reader);
case AST_TYPE::Break: case AST_TYPE::Break:
return read_break(reader); return read_break(reader);
case AST_TYPE::ClassDef: case AST_TYPE::ClassDef:
......
...@@ -151,6 +151,7 @@ void initGlobalFuncs(GlobalState &g) { ...@@ -151,6 +151,7 @@ void initGlobalFuncs(GlobalState &g) {
GET(getGlobal); GET(getGlobal);
GET(binop); GET(binop);
GET(compare); GET(compare);
GET(augassign);
GET(nonzero); GET(nonzero);
GET(print); GET(print);
GET(unboxedLen); GET(unboxedLen);
......
...@@ -21,7 +21,7 @@ struct GlobalFuncs { ...@@ -21,7 +21,7 @@ struct GlobalFuncs {
llvm::Value *printf, *my_assert, *malloc, *free; llvm::Value *printf, *my_assert, *malloc, *free;
llvm::Value *boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction, *boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createClass; llvm::Value *boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction, *boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createClass;
llvm::Value *getattr, *setattr, *print, *nonzero, *binop, *compare, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import; llvm::Value *getattr, *setattr, *print, *nonzero, *binop, *compare, *augassign, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import;
llvm::Value *checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, *assertNameDefined; llvm::Value *checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, *assertNameDefined;
llvm::Value *printFloat, *listAppendInternal; llvm::Value *printFloat, *listAppendInternal;
llvm::Value *dump; llvm::Value *dump;
......
...@@ -81,6 +81,10 @@ std::string getOpSymbol(int op_type) { ...@@ -81,6 +81,10 @@ std::string getOpSymbol(int op_type) {
} }
} }
std::string getInplaceOpSymbol(int op_type) {
return getOpSymbol(op_type) + '=';
}
std::string getOpName(int op_type) { std::string getOpName(int op_type) {
assert(op_type != AST_TYPE::Is); assert(op_type != AST_TYPE::Is);
assert(op_type != AST_TYPE::IsNot); assert(op_type != AST_TYPE::IsNot);
...@@ -139,6 +143,11 @@ std::string getOpName(int op_type) { ...@@ -139,6 +143,11 @@ std::string getOpName(int op_type) {
} }
} }
std::string getInplaceOpName(int op_type) {
std::string normal_name = getOpName(op_type);
return "__i" + normal_name.substr(2);
}
std::string getReverseOpName(int op_type) { std::string getReverseOpName(int op_type) {
if (op_type == AST_TYPE::Lt) if (op_type == AST_TYPE::Lt)
return getOpName(AST_TYPE::GtE); return getOpName(AST_TYPE::GtE);
...@@ -196,6 +205,18 @@ void AST_Assign::accept_stmt(StmtVisitor *v) { ...@@ -196,6 +205,18 @@ void AST_Assign::accept_stmt(StmtVisitor *v) {
v->visit_assign(this); v->visit_assign(this);
} }
void AST_AugAssign::accept(ASTVisitor *v) {
bool skip = v->visit_augassign(this);
if (skip) return;
value->accept(v);
target->accept(v);
}
void AST_AugAssign::accept_stmt(StmtVisitor *v) {
v->visit_augassign(this);
}
void AST_Attribute::accept(ASTVisitor *v) { void AST_Attribute::accept(ASTVisitor *v) {
bool skip = v->visit_attribute(this); bool skip = v->visit_attribute(this);
if (skip) return; if (skip) return;
...@@ -616,16 +637,8 @@ bool PrintVisitor::visit_assign(AST_Assign *node) { ...@@ -616,16 +637,8 @@ bool PrintVisitor::visit_assign(AST_Assign *node) {
return true; return true;
} }
bool PrintVisitor::visit_attribute(AST_Attribute *node) { static void printOp(AST_TYPE::AST_TYPE op_type) {
node->value->accept(this); switch (op_type) {
putchar('.');
printf("%s", node->attr.c_str());
return true;
}
bool PrintVisitor::visit_binop(AST_BinOp *node) {
node->left->accept(this);
switch (node->op_type) {
case AST_TYPE::Add: case AST_TYPE::Add:
putchar('+'); putchar('+');
break; break;
...@@ -660,9 +673,29 @@ bool PrintVisitor::visit_binop(AST_BinOp *node) { ...@@ -660,9 +673,29 @@ bool PrintVisitor::visit_binop(AST_BinOp *node) {
putchar('-'); putchar('-');
break; break;
default: default:
printf("<%d>", node->op_type); printf("<%d>", op_type);
break; break;
} }
}
bool PrintVisitor::visit_augassign(AST_AugAssign *node) {
node->target->accept(this);
printOp(node->op_type);
putchar('=');
node->value->accept(this);
return true;
}
bool PrintVisitor::visit_attribute(AST_Attribute *node) {
node->value->accept(this);
putchar('.');
printf("%s", node->attr.c_str());
return true;
}
bool PrintVisitor::visit_binop(AST_BinOp *node) {
node->left->accept(this);
printOp(node->op_type);
node->right->accept(this); node->right->accept(this);
return true; return true;
} }
...@@ -1071,6 +1104,7 @@ class FlattenVisitor : public ASTVisitor { ...@@ -1071,6 +1104,7 @@ class FlattenVisitor : public ASTVisitor {
virtual bool visit_alias(AST_alias *node) { output->push_back(node); return false; } virtual bool visit_alias(AST_alias *node) { output->push_back(node); return false; }
virtual bool visit_arguments(AST_arguments *node) { output->push_back(node); return false; } virtual bool visit_arguments(AST_arguments *node) { output->push_back(node); return false; }
virtual bool visit_assign(AST_Assign *node) { output->push_back(node); return false; } virtual bool visit_assign(AST_Assign *node) { output->push_back(node); return false; }
virtual bool visit_augassign(AST_AugAssign *node) { output->push_back(node); return false; }
virtual bool visit_attribute(AST_Attribute *node) { output->push_back(node); return false; } virtual bool visit_attribute(AST_Attribute *node) { output->push_back(node); return false; }
virtual bool visit_binop(AST_BinOp *node) { output->push_back(node); return false; } virtual bool visit_binop(AST_BinOp *node) { output->push_back(node); return false; }
virtual bool visit_boolop(AST_BoolOp *node) { output->push_back(node); return false; } virtual bool visit_boolop(AST_BoolOp *node) { output->push_back(node); return false; }
......
...@@ -185,6 +185,18 @@ class AST_Assign : public AST_stmt { ...@@ -185,6 +185,18 @@ class AST_Assign : public AST_stmt {
AST_Assign() : AST_stmt(AST_TYPE::Assign) {} AST_Assign() : AST_stmt(AST_TYPE::Assign) {}
}; };
class AST_AugAssign : public AST_stmt {
public:
AST_expr* value;
AST_expr* target;
AST_TYPE::AST_TYPE op_type;
virtual void accept(ASTVisitor *v);
virtual void accept_stmt(StmtVisitor *v);
AST_AugAssign() : AST_stmt(AST_TYPE::AugAssign) {}
};
class AST_Attribute : public AST_expr { class AST_Attribute : public AST_expr {
public: public:
AST_expr* value; AST_expr* value;
...@@ -577,6 +589,7 @@ class ASTVisitor { ...@@ -577,6 +589,7 @@ class ASTVisitor {
virtual bool visit_alias(AST_alias *node) { assert(0); abort(); } virtual bool visit_alias(AST_alias *node) { assert(0); abort(); }
virtual bool visit_arguments(AST_arguments *node) { assert(0); abort(); } virtual bool visit_arguments(AST_arguments *node) { assert(0); abort(); }
virtual bool visit_assign(AST_Assign *node) { assert(0); abort(); } virtual bool visit_assign(AST_Assign *node) { assert(0); abort(); }
virtual bool visit_augassign(AST_AugAssign *node) { assert(0); abort(); }
virtual bool visit_attribute(AST_Attribute *node) { assert(0); abort(); } virtual bool visit_attribute(AST_Attribute *node) { assert(0); abort(); }
virtual bool visit_binop(AST_BinOp *node) { assert(0); abort(); } virtual bool visit_binop(AST_BinOp *node) { assert(0); abort(); }
virtual bool visit_boolop(AST_BoolOp *node) { assert(0); abort(); } virtual bool visit_boolop(AST_BoolOp *node) { assert(0); abort(); }
...@@ -622,6 +635,7 @@ class NoopASTVisitor : public ASTVisitor { ...@@ -622,6 +635,7 @@ class NoopASTVisitor : public ASTVisitor {
virtual bool visit_alias(AST_alias *node) { return false; } virtual bool visit_alias(AST_alias *node) { return false; }
virtual bool visit_arguments(AST_arguments *node) { return false; } virtual bool visit_arguments(AST_arguments *node) { return false; }
virtual bool visit_assign(AST_Assign *node) { return false; } virtual bool visit_assign(AST_Assign *node) { return false; }
virtual bool visit_augassign(AST_AugAssign *node) { return false; }
virtual bool visit_attribute(AST_Attribute *node) { return false; } virtual bool visit_attribute(AST_Attribute *node) { return false; }
virtual bool visit_binop(AST_BinOp *node) { return false; } virtual bool visit_binop(AST_BinOp *node) { return false; }
virtual bool visit_boolop(AST_BoolOp *node) { return false; } virtual bool visit_boolop(AST_BoolOp *node) { return false; }
...@@ -688,6 +702,7 @@ class StmtVisitor { ...@@ -688,6 +702,7 @@ class StmtVisitor {
virtual ~StmtVisitor() {} virtual ~StmtVisitor() {}
virtual void visit_assign(AST_Assign *node) { assert(0); abort(); } virtual void visit_assign(AST_Assign *node) { assert(0); abort(); }
virtual void visit_augassign(AST_AugAssign *node) { assert(0); abort(); }
virtual void visit_break(AST_Break *node) { assert(0); abort(); } virtual void visit_break(AST_Break *node) { assert(0); abort(); }
virtual void visit_classdef(AST_ClassDef *node) { assert(0); abort(); } virtual void visit_classdef(AST_ClassDef *node) { assert(0); abort(); }
virtual void visit_continue(AST_Continue *node) { assert(0); abort(); } virtual void visit_continue(AST_Continue *node) { assert(0); abort(); }
...@@ -719,6 +734,7 @@ class PrintVisitor : public ASTVisitor { ...@@ -719,6 +734,7 @@ class PrintVisitor : public ASTVisitor {
virtual bool visit_alias(AST_alias *node); virtual bool visit_alias(AST_alias *node);
virtual bool visit_arguments(AST_arguments *node); virtual bool visit_arguments(AST_arguments *node);
virtual bool visit_assign(AST_Assign *node); virtual bool visit_assign(AST_Assign *node);
virtual bool visit_augassign(AST_AugAssign *node);
virtual bool visit_attribute(AST_Attribute *node); virtual bool visit_attribute(AST_Attribute *node);
virtual bool visit_binop(AST_BinOp *node); virtual bool visit_binop(AST_BinOp *node);
virtual bool visit_boolop(AST_BoolOp *node); virtual bool visit_boolop(AST_BoolOp *node);
......
...@@ -202,6 +202,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -202,6 +202,7 @@ class CFGVisitor : public ASTVisitor {
} }
virtual bool visit_assign(AST_Assign* node) { push_back(node); return true; } virtual bool visit_assign(AST_Assign* node) { push_back(node); return true; }
virtual bool visit_augassign(AST_AugAssign* node) { push_back(node); return true; }
virtual bool visit_classdef(AST_ClassDef* node) { push_back(node); return true; } virtual bool visit_classdef(AST_ClassDef* node) { push_back(node); return true; }
virtual bool visit_expr(AST_Expr* node) { push_back(node); return true; } virtual bool visit_expr(AST_Expr* node) { push_back(node); return true; }
virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; } virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; }
......
...@@ -224,8 +224,10 @@ extern "C" CompiledFunction* resolveCLFunc(CLFunction *f, int64_t nargs, Box* ar ...@@ -224,8 +224,10 @@ extern "C" CompiledFunction* resolveCLFunc(CLFunction *f, int64_t nargs, Box* ar
extern "C" Box* callCompiledFunc(CompiledFunction *cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); extern "C" Box* callCompiledFunc(CompiledFunction *cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args);
std::string getOpName(int op_type); std::string getOpName(int op_type);
std::string getOpSymbol(int op_type);
std::string getReverseOpName(int op_type); std::string getReverseOpName(int op_type);
std::string getInplaceOpName(int op_type);
std::string getOpSymbol(int op_type);
std::string getInplaceOpSymbol(int op_type);
typedef bool i1; typedef bool i1;
typedef int64_t i64; typedef int64_t i64;
......
...@@ -62,6 +62,7 @@ void force() { ...@@ -62,6 +62,7 @@ void force() {
FORCE(nonzero); FORCE(nonzero);
FORCE(binop); FORCE(binop);
FORCE(compare); FORCE(compare);
FORCE(augassign);
FORCE(unboxedLen); FORCE(unboxedLen);
FORCE(getitem); FORCE(getitem);
FORCE(getclsattr); FORCE(getclsattr);
......
...@@ -230,6 +230,43 @@ Box* listMul(BoxedList* self, Box* rhs) { ...@@ -230,6 +230,43 @@ Box* listMul(BoxedList* self, Box* rhs) {
return rtn; return rtn;
} }
Box* listIAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
int s1 = self->size;
int s2 = rhs->size;
self->ensure(s1 + s2);
memcpy(self->elts->elts + s1, rhs->elts->elts, sizeof(rhs->elts->elts[0]) * s2);
self->size = s1 + s2;
return self;
}
Box* listAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
BoxedList* rtn = new BoxedList();
int s1 = self->size;
int s2 = rhs->size;
rtn->ensure(s1 + s2);
memcpy(rtn->elts->elts, self->elts->elts, sizeof(self->elts->elts[0]) * s1);
memcpy(rtn->elts->elts + s1, rhs->elts->elts, sizeof(rhs->elts->elts[0]) * s2);
rtn->size = s1 + s2;
return rtn;
}
BoxedClass *list_iterator_cls = NULL; BoxedClass *list_iterator_cls = NULL;
extern "C" void listIteratorGCHandler(GCVisitor *v, void* p) { extern "C" void listIteratorGCHandler(GCVisitor *v, void* p) {
boxGCHandler(v, p); boxGCHandler(v, p);
...@@ -289,6 +326,9 @@ void setupList() { ...@@ -289,6 +326,9 @@ void setupList() {
list_cls->giveAttr("insert", new BoxedFunction(boxRTFunction((void*)listInsert, NULL, 3, false))); list_cls->giveAttr("insert", new BoxedFunction(boxRTFunction((void*)listInsert, NULL, 3, false)));
list_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)listMul, NULL, 2, false))); list_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)listMul, NULL, 2, false)));
list_cls->giveAttr("__iadd__", new BoxedFunction(boxRTFunction((void*)listIAdd, NULL, 2, false)));
list_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)listAdd, NULL, 2, false)));
CLFunction *new_ = boxRTFunction((void*)listNew1, NULL, 1, false); CLFunction *new_ = boxRTFunction((void*)listNew1, NULL, 1, false);
addRTFunction(new_, (void*)listNew2, NULL, 2, false); addRTFunction(new_, (void*)listNew2, NULL, 2, false);
list_cls->giveAttr("__new__", new BoxedFunction(new_)); list_cls->giveAttr("__new__", new BoxedFunction(new_));
......
...@@ -128,6 +128,17 @@ struct CallRewriteArgs { ...@@ -128,6 +128,17 @@ struct CallRewriteArgs {
} }
}; };
struct BinopRewriteArgs {
Rewriter *rewriter;
RewriterVar lhs, rhs;
bool out_success;
RewriterVar out_rtn;
BinopRewriteArgs(Rewriter *rewriter, const RewriterVar &lhs,
const RewriterVar &rhs) : rewriter(rewriter), lhs(lhs), rhs(rhs), out_success(false) {
}
};
struct CompareRewriteArgs { struct CompareRewriteArgs {
Rewriter *rewriter; Rewriter *rewriter;
RewriterVar lhs, rhs; RewriterVar lhs, rhs;
...@@ -1506,32 +1517,16 @@ extern "C" Box* runtimeCall(Box *obj, int64_t nargs, Box* arg1, Box* arg2, Box* ...@@ -1506,32 +1517,16 @@ extern "C" Box* runtimeCall(Box *obj, int64_t nargs, Box* arg1, Box* arg2, Box*
return rtn; return rtn;
} }
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs *rewrite_args) {
static StatCounter slowpath_binop("slowpath_binop");
slowpath_binop.log();
static StatCounter nopatch_binop("nopatch_binop");
std::string op_name = getOpName(op_type);
//int id = Stats::getStatId("slowpath_binop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs));
//Stats::log(id);
// TODO handle the case of the rhs being a subclass of the lhs // TODO handle the case of the rhs being a subclass of the lhs
// this could get really annoying because you can dynamically make one type a subclass // this could get really annoying because you can dynamically make one type a subclass
// of the other! // of the other!
{ // anonymous scope to make sure all variables get cleaned up before we error if (rewrite_args) {
std::unique_ptr<Rewriter> rewriter((Rewriter*)NULL);
bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls);
if (can_patchpoint)
rewriter.reset(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "binop"));
if (rewriter.get()) {
//rewriter->trap(); //rewriter->trap();
RewriterVar r_lhs = rewriter->getArg(0); RewriterVar r_lhs = rewrite_args->rewriter->getArg(0);
RewriterVar r_rhs = rewriter->getArg(1); RewriterVar r_rhs = rewrite_args->rewriter->getArg(1);
// TODO probably don't need to guard on the lhs_cls since it // TODO probably don't need to guard on the lhs_cls since it
// will get checked no matter what, but the check that should be // will get checked no matter what, but the check that should be
// removed is probably the later one. // removed is probably the later one.
...@@ -1541,16 +1536,45 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { ...@@ -1541,16 +1536,45 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
r_rhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls); r_rhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls);
} }
std::string iop_name = getInplaceOpName(op_type);
Box* irtn = NULL;
if (inplace) {
if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs);
srewrite_args.arg1 = rewrite_args->rhs;
irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, &srewrite_args, 1, rhs);
if (!srewrite_args.out_success)
rewrite_args = NULL;
else if (irtn)
rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1);
} else {
irtn = callattrInternal1(lhs, &iop_name, CLASS_ONLY, NULL, 1, rhs);
}
if (irtn) {
if (irtn != NotImplemented) {
if (rewrite_args) {
rewrite_args->out_success = true;
}
return irtn;
}
}
}
std::string op_name = getOpName(op_type);
Box* lrtn; Box* lrtn;
if (rewriter.get()) { if (rewrite_args) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs);
rewrite_args.arg1 = rewriter->getArg(1); srewrite_args.arg1 = rewrite_args->rhs;
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &rewrite_args, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &srewrite_args, 1, rhs);
if (!rewrite_args.out_success) if (!srewrite_args.out_success)
rewriter.reset(NULL); rewrite_args = NULL;
else if (lrtn) else if (lrtn)
rewrite_args.out_rtn.move(-1); rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1);
} else { } else {
lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs); lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs);
} }
...@@ -1558,15 +1582,11 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { ...@@ -1558,15 +1582,11 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
if (lrtn) { if (lrtn) {
if (lrtn != NotImplemented) { if (lrtn != NotImplemented) {
if (rewriter.get() && can_patchpoint) { if (rewrite_args) {
rewriter->commit(); rewrite_args->out_success = true;
} }
//
//printf("lfunc returned NotImplemented\n");
return lrtn; return lrtn;
} }
} else {
//printf("lfunc doesnt exist\n");
} }
// TODO patch these cases // TODO patch these cases
...@@ -1582,8 +1602,19 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { ...@@ -1582,8 +1602,19 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
//printf("rfunc doesn't exist\n"); //printf("rfunc doesn't exist\n");
} }
if (inplace) {
fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n", getInplaceOpSymbol(op_type).c_str(), getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str());
} else {
fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n", getOpSymbol(op_type).c_str(), getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str()); fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n", getOpSymbol(op_type).c_str(), getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str());
}
if (VERBOSITY()) { if (VERBOSITY()) {
if (inplace) {
if (irtn)
fprintf(stderr, "%s has %s, but returned NotImplemented\n", getTypeName(lhs)->c_str(), iop_name.c_str());
else
fprintf(stderr, "%s does not have %s\n", getTypeName(lhs)->c_str(), iop_name.c_str());
}
if (lrtn) if (lrtn)
fprintf(stderr, "%s has %s, but returned NotImplemented\n", getTypeName(lhs)->c_str(), op_name.c_str()); fprintf(stderr, "%s has %s, but returned NotImplemented\n", getTypeName(lhs)->c_str(), op_name.c_str());
else else
...@@ -1593,10 +1624,76 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { ...@@ -1593,10 +1624,76 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
else else
fprintf(stderr, "%s does not have %s\n", getTypeName(rhs)->c_str(), rop_name.c_str()); fprintf(stderr, "%s does not have %s\n", getTypeName(rhs)->c_str(), rop_name.c_str());
} }
}
raiseExc(); raiseExc();
} }
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
static StatCounter slowpath_binop("slowpath_binop");
slowpath_binop.log();
//static StatCounter nopatch_binop("nopatch_binop");
//int id = Stats::getStatId("slowpath_binop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs));
//Stats::log(id);
std::unique_ptr<Rewriter> rewriter((Rewriter*)NULL);
bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls);
if (can_patchpoint)
rewriter.reset(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "binop"));
Box* rtn;
if (rewriter.get()) {
//rewriter->trap();
BinopRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1));
rtn = binopInternal(lhs, rhs, op_type, false, &rewrite_args);
assert(rtn);
if (!rewrite_args.out_success)
rewriter.reset(NULL);
else
rewrite_args.out_rtn.move(-1);
} else {
rtn = binopInternal(lhs, rhs, op_type, false, NULL);
}
if (rewriter.get()) {
rewriter->commit();
}
return rtn;
}
extern "C" Box* augassign(Box* lhs, Box* rhs, int op_type) {
static StatCounter slowpath_binop("slowpath_binop");
slowpath_binop.log();
//static StatCounter nopatch_binop("nopatch_binop");
//int id = Stats::getStatId("slowpath_binop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs));
//Stats::log(id);
std::unique_ptr<Rewriter> rewriter((Rewriter*)NULL);
bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls);
if (can_patchpoint)
rewriter.reset(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "binop"));
Box* rtn;
if (rewriter.get()) {
//rewriter->trap();
BinopRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1));
rtn = binopInternal(lhs, rhs, op_type, true, &rewrite_args);
if (!rewrite_args.out_success)
rewriter.reset(NULL);
else
rewrite_args.out_rtn.move(-1);
} else {
rtn = binopInternal(lhs, rhs, op_type, true, NULL);
}
if (rewriter.get()) {
rewriter->commit();
}
return rtn;
}
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs *rewrite_args) { Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs *rewrite_args) {
if (op_type == AST_TYPE::Is || op_type == AST_TYPE::IsNot) { if (op_type == AST_TYPE::Is || op_type == AST_TYPE::IsNot) {
bool neg = (op_type == AST_TYPE::IsNot); bool neg = (op_type == AST_TYPE::IsNot);
......
...@@ -54,6 +54,7 @@ extern "C" void dump(Box* obj); ...@@ -54,6 +54,7 @@ extern "C" void dump(Box* obj);
//extern "C" Box* trap(); //extern "C" Box* trap();
extern "C" i64 unboxedLen(Box* obj); extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type); extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* augassign(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getGlobal(BoxedModule* m, std::string *name, bool from_global); extern "C" Box* getGlobal(BoxedModule* m, std::string *name, bool from_global);
extern "C" Box* getitem(Box* value, Box* slice); extern "C" Box* getitem(Box* value, Box* slice);
extern "C" void setitem(Box* target, Box* slice, Box* value); extern "C" void setitem(Box* target, Box* slice, Box* value);
......
...@@ -30,9 +30,15 @@ ...@@ -30,9 +30,15 @@
namespace pyston { namespace pyston {
extern "C" BoxedString* strAdd(BoxedString* lhs, BoxedString* rhs) { extern "C" BoxedString* strAdd(BoxedString* lhs, Box* _rhs) {
assert(lhs->cls == str_cls); assert(lhs->cls == str_cls);
assert(rhs->cls == str_cls);
if (_rhs->cls != str_cls) {
fprintf(stderr, "TypeError: cannot concatenate 'str' and '%s' objects", getTypeName(_rhs)->c_str());
raiseExc();
}
BoxedString* rhs = static_cast<BoxedString*>(_rhs);
return new BoxedString(lhs->s + rhs->s); return new BoxedString(lhs->s + rhs->s);
} }
......
# Augassign
def f(a, b):
a += b
a -= b
a *= b
a /= b
a //= b
a **= b
a %= b
a |= b
a &= b
a ^= b
a <<= b
a >>= b
return a
l = range(10)
l2 = l
l += l
print l
print l2
l = range(10)
l2 = l
l = l + l
print l
print l2
print f(4, 2)
print f(4.1, 2.3)
class IntLike(object):
def __radd__(self, rhs):
return "hello world"
def f():
i = 1
print i
# Augassigns can change the type of the variable:
i += IntLike()
print i
i + 1
f()
def f():
return range(10)
for i in xrange(1000000):
f()
print "This will break"
...@@ -246,6 +246,8 @@ if __name__ == "__main__": ...@@ -246,6 +246,8 @@ if __name__ == "__main__":
raise Exception((t, v)) raise Exception((t, v))
TEST_DIR = patterns[0] TEST_DIR = patterns[0]
assert os.path.isdir(TEST_DIR), "%s doesn't look like a directory with tests in it" % TEST_DIR
patterns = patterns[1:] patterns = patterns[1:]
TOSKIP = ["%s/%s.py" % (TEST_DIR, i) for i in ( TOSKIP = ["%s/%s.py" % (TEST_DIR, i) for i in (
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment