Commit 5bbd4c50 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Wow, I guess augassign is quite a bit more complicated than I thought

parent d498e5ca
......@@ -72,23 +72,6 @@ class LivenessBBVisitor : public NoopASTVisitor {
}
return true;
}
bool visit_augassign(AST_AugAssign* node) {
AST* target = node->target;
switch(target->type) {
case AST_TYPE::Name: {
AST_Name* n = static_cast<AST_Name*>(target);
_doLoad(n->id);
_doStore(n->id);
break;
}
default:
RELEASE_ASSERT(0, "%d", target->type);
}
node->value->accept(this);
return true;
}
};
bool LivenessAnalysis::isLiveAtEnd(const std::string &name, CFGBlock *block) {
......@@ -227,11 +210,6 @@ class DefinednessVisitor : public ASTVisitor {
return true;
}
virtual bool visit_augassign(AST_AugAssign *node) {
_doSet(node->target);
return true;
}
virtual bool visit_arguments(AST_arguments *node) {
if (node->kwarg) _doSet(node->kwarg);
if (node->vararg.size()) _doSet(node->vararg);
......
......@@ -158,7 +158,6 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
virtual void* visit_attribute(AST_Attribute *node) {
CompilerType *t = getType(node->value);
assert(node->ctx_type == AST_TYPE::Load);
CompilerType *rtn = t->getattrType(&node->attr, false);
//if (speculation != TypeAnalysis::NONE && (node->attr == "x" || node->attr == "y" || node->attr == "z")) {
......@@ -184,6 +183,31 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
return rtn;
}
virtual void* visit_augbinop(AST_AugBinOp *node) {
CompilerType *left = getType(node->left);
CompilerType *right = getType(node->right);
// TODO this isn't the exact behavior
std::string name = getOpName(node->op_type);
name = "__i" + name.substr(2);
CompilerType *attr_type = left->getattrType(&name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
std::vector<CompilerType*> arg_types;
arg_types.push_back(right);
CompilerType *rtn = attr_type->callType(arg_types);
if (left == right && (left == INT || left == FLOAT)) {
ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into", "%s %s %s -> %s", left->debugName().c_str(), name.c_str(), right->debugName().c_str(), rtn->debugName().c_str());
}
ASSERT(rtn != UNDEF, "need to implement the actual semantics here for %s.%s", left->debugName().c_str(), name.c_str());
return rtn;
}
virtual void* visit_binop(AST_BinOp *node) {
CompilerType *left = getType(node->left);
CompilerType *right = getType(node->right);
......@@ -192,14 +216,19 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
std::string name = getOpName(node->op_type);
CompilerType *attr_type = left->getattrType(&name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
std::vector<CompilerType*> arg_types;
arg_types.push_back(right);
CompilerType *rtn = attr_type->callType(arg_types);
if (left == right && (left == INT || left == FLOAT)) {
ASSERT((rtn == left || rtn == UNDEF) && "not strictly required but probably something worth looking into", "%s %s", name.c_str(), rtn->debugName().c_str());
ASSERT((rtn == left || rtn == UNKNOWN) && "not strictly required but probably something worth looking into", "%s %s %s -> %s", left->debugName().c_str(), name.c_str(), right->debugName().c_str(), rtn->debugName().c_str());
}
ASSERT(rtn != UNDEF, "need to implement the actual semantics here for %s.%s", left->debugName().c_str(), name.c_str());
return rtn;
}
......@@ -254,6 +283,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
}
std::string name = getOpName(node->ops[0]);
CompilerType *attr_type = left->getattrType(&name, true);
if (attr_type == UNDEF)
attr_type = UNKNOWN;
std::vector<CompilerType*> arg_types;
arg_types.push_back(right);
return attr_type->callType(arg_types);
......@@ -297,10 +330,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
CompilerType* &t = sym_table[node->id];
if (t == NULL) {
if (VERBOSITY() >= 2) {
printf("%s is undefined!\n", node->id.c_str());
raise(SIGTRAP);
}
//if (VERBOSITY() >= 2) {
//printf("%s is undefined!\n", node->id.c_str());
//raise(SIGTRAP);
//}
t = UNDEF;
}
return t;
......@@ -362,31 +395,6 @@ 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, true);
ASSERT(attr_type != UNDEF, "need to implement the actual semantics here");
std::vector<CompilerType*> arg_types;
arg_types.push_back(v);
CompilerType *rtn = attr_type->callType(arg_types);
if (VERBOSITY() >= 2) printf("%s aug= %s -> %s\n", t->debugName().c_str(), v->debugName().c_str(), rtn->debugName().c_str());
if (t == INT && v == INT)
assert(rtn == INT);
if (t == FLOAT && v == FLOAT)
assert(rtn == FLOAT);
_doSet(node->target, rtn);
}
virtual void visit_branch(AST_Branch* node) {
if (EXPAND_UNNEEDED) {
getType(node->test);
......@@ -483,9 +491,14 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
return true;
}
if (lhs == UNDEF || rhs == UNDEF)
if (lhs == UNDEF)
return false;
if (rhs == UNDEF) {
rhs = lhs;
return true;
}
if (lhs == rhs)
return false;
if (rhs == UNKNOWN)
......
......@@ -1081,6 +1081,15 @@ class StrConstantType : public ValuedCompilerType<std::string*> {
return rtn;
}
virtual CompilerVariable* dup(VAR *var, DupCache &cache) {
CompilerVariable* &rtn = cache[var];
if (rtn == NULL) {
rtn = new VAR(this, var->getValue(), var->isGrabbed());
}
return rtn;
}
};
ValuedCompilerType<std::string*> *STR_CONSTANT = new StrConstantType();
......
......@@ -218,7 +218,6 @@ class IRGeneratorImpl : public IRGenerator {
CompilerVariable* evalAttribute(AST_Attribute *node) {
assert(state != PARTIAL);
assert(node->ctx_type == AST_TYPE::Load);
CompilerVariable *value = evalExpr(node->value);
......@@ -237,7 +236,7 @@ class IRGeneratorImpl : public IRGenerator {
}
enum BinExpType {
AugAssign,
AugBinOp,
BinOp,
Compare,
};
......@@ -257,7 +256,7 @@ class IRGeneratorImpl : public IRGenerator {
v = emitter.getBuilder()->CreateCall2(g.funcs.div_i64_i64, converted_left->getValue(), converted_right->getValue());
} else if (type == AST_TYPE::Pow) {
v = emitter.getBuilder()->CreateCall2(g.funcs.pow_i64_i64, converted_left->getValue(), converted_right->getValue());
} else if (exp_type == BinOp || exp_type == AugAssign) {
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
......@@ -347,7 +346,7 @@ class IRGeneratorImpl : public IRGenerator {
v = emitter.getBuilder()->CreateCall2(g.funcs.div_float_float, converted_left->getValue(), converted_right->getValue());
} else if (type == AST_TYPE::Pow) {
v = emitter.getBuilder()->CreateCall2(g.funcs.pow_float_float, converted_left->getValue(), converted_right->getValue());
} else if (exp_type == BinOp || exp_type == AugAssign) {
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
......@@ -428,9 +427,9 @@ class IRGeneratorImpl : public IRGenerator {
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} else if (exp_type == AugAssign) {
rt_func = g.funcs.augassign;
rt_func_addr = (void*)augassign;
} else if (exp_type == AugBinOp) {
rt_func = g.funcs.augbinop;
rt_func_addr = (void*)augbinop;
} else {
rt_func = g.funcs.compare;
rt_func_addr = (void*)compare;
......@@ -471,6 +470,20 @@ class IRGeneratorImpl : public IRGenerator {
return rtn;
}
CompilerVariable* evalAugBinOp(AST_AugBinOp *node) {
assert(state != PARTIAL);
CompilerVariable *left = evalExpr(node->left);
CompilerVariable *right = evalExpr(node->right);
assert(node->op_type != AST_TYPE::Is && node->op_type != AST_TYPE::IsNot && "not tested yet");
CompilerVariable *rtn = this->_evalBinExp(left, right, node->op_type, AugBinOp);
left->decvref(emitter);
right->decvref(emitter);
return rtn;
}
CompilerVariable* evalCompare(AST_Compare *node) {
assert(state != PARTIAL);
......@@ -790,6 +803,9 @@ class IRGeneratorImpl : public IRGenerator {
case AST_TYPE::Attribute:
rtn = evalAttribute(static_cast<AST_Attribute*>(node));
break;
case AST_TYPE::AugBinOp:
rtn = evalAugBinOp(static_cast<AST_AugBinOp*>(node));
break;
case AST_TYPE::BinOp:
rtn = evalBinOp(static_cast<AST_BinOp*>(node));
break;
......@@ -1097,20 +1113,6 @@ class IRGeneratorImpl : public IRGenerator {
val->decvref(emitter);
}
void doAugAssign(AST_AugAssign *node) {
CompilerVariable *target = evalExpr(node->target);
CompilerVariable *val = evalExpr(node->value);
if (state == PARTIAL)
return;
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) {
if (state == PARTIAL)
return;
......@@ -1453,9 +1455,6 @@ class IRGeneratorImpl : public IRGenerator {
case AST_TYPE::Assign:
doAssign(static_cast<AST_Assign*>(node));
break;
case AST_TYPE::AugAssign:
doAugAssign(static_cast<AST_AugAssign*>(node));
break;
case AST_TYPE::ClassDef:
doClassDef(static_cast<AST_ClassDef*>(node));
break;
......
......@@ -140,7 +140,7 @@ PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction *parent_cf) {
}
PatchpointSetupInfo* createBinexpPatchpoint(CompiledFunction *parent_cf) {
return PatchpointSetupInfo::initialize(true, 4, 160, parent_cf, Binexp);
return PatchpointSetupInfo::initialize(true, 4, 196, parent_cf, Binexp);
}
PatchpointSetupInfo* createNonzeroPatchpoint(CompiledFunction *parent_cf) {
......
......@@ -151,7 +151,7 @@ void initGlobalFuncs(GlobalState &g) {
GET(getGlobal);
GET(binop);
GET(compare);
GET(augassign);
GET(augbinop);
GET(nonzero);
GET(print);
GET(unboxedLen);
......
......@@ -21,7 +21,7 @@ struct GlobalFuncs {
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 *getattr, *setattr, *print, *nonzero, *binop, *compare, *augassign, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import;
llvm::Value *getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import;
llvm::Value *checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, *assertNameDefined;
llvm::Value *printFloat, *listAppendInternal;
llvm::Value *dump;
......
......@@ -217,6 +217,18 @@ void AST_AugAssign::accept_stmt(StmtVisitor *v) {
v->visit_augassign(this);
}
void AST_AugBinOp::accept(ASTVisitor *v) {
bool skip = v->visit_augbinop(this);
if (skip) return;
left->accept(v);
right->accept(v);
}
void* AST_AugBinOp::accept_expr(ExprVisitor *v) {
return v->visit_augbinop(this);
}
void AST_Attribute::accept(ASTVisitor *v) {
bool skip = v->visit_attribute(this);
if (skip) return;
......@@ -726,6 +738,14 @@ bool PrintVisitor::visit_augassign(AST_AugAssign *node) {
return true;
}
bool PrintVisitor::visit_augbinop(AST_AugBinOp *node) {
node->left->accept(this);
printf("=");
printOp(node->op_type);
node->right->accept(this);
return true;
}
bool PrintVisitor::visit_attribute(AST_Attribute *node) {
node->value->accept(this);
putchar('.');
......@@ -996,6 +1016,7 @@ bool PrintVisitor::visit_module(AST_Module *node) {
bool PrintVisitor::visit_name(AST_Name *node) {
printf("%s", node->id.c_str());
//printf("%s(%d)", node->id.c_str(), node->ctx_type);
return false;
}
......@@ -1179,6 +1200,7 @@ class FlattenVisitor : public ASTVisitor {
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_augassign(AST_AugAssign *node) { output->push_back(node); return false; }
virtual bool visit_augbinop(AST_AugBinOp *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_boolop(AST_BoolOp *node) { output->push_back(node); return false; }
......
......@@ -119,6 +119,7 @@ namespace AST_TYPE {
Branch = 200,
Jump = 201,
ClsAttribute = 202,
AugBinOp = 203,
};
};
......@@ -197,6 +198,17 @@ class AST_AugAssign : public AST_stmt {
AST_AugAssign() : AST_stmt(AST_TYPE::AugAssign) {}
};
class AST_AugBinOp : public AST_expr {
public:
AST_TYPE::AST_TYPE op_type;
AST_expr *left, *right;
virtual void accept(ASTVisitor *v);
virtual void* accept_expr(ExprVisitor *v);
AST_AugBinOp() : AST_expr(AST_TYPE::AugBinOp) {}
};
class AST_Attribute : public AST_expr {
public:
AST_expr* value;
......@@ -630,6 +642,7 @@ class ASTVisitor {
virtual bool visit_arguments(AST_arguments *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_augbinop(AST_AugBinOp *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_boolop(AST_BoolOp *node) { assert(0); abort(); }
......@@ -679,6 +692,7 @@ class NoopASTVisitor : public ASTVisitor {
virtual bool visit_arguments(AST_arguments *node) { return false; }
virtual bool visit_assign(AST_Assign *node) { return false; }
virtual bool visit_augassign(AST_AugAssign *node) { return false; }
virtual bool visit_augbinop(AST_AugBinOp *node) { return false; }
virtual bool visit_attribute(AST_Attribute *node) { return false; }
virtual bool visit_binop(AST_BinOp *node) { return false; }
virtual bool visit_boolop(AST_BoolOp *node) { return false; }
......@@ -724,6 +738,7 @@ class ExprVisitor {
public:
virtual ~ExprVisitor() {}
virtual void* visit_augbinop(AST_AugBinOp *node) { assert(0); abort(); }
virtual void* visit_attribute(AST_Attribute *node) { assert(0); abort(); }
virtual void* visit_binop(AST_BinOp *node) { assert(0); abort(); }
virtual void* visit_boolop(AST_BoolOp *node) { assert(0); abort(); }
......@@ -783,6 +798,7 @@ class PrintVisitor : public ASTVisitor {
virtual bool visit_arguments(AST_arguments *node);
virtual bool visit_assign(AST_Assign *node);
virtual bool visit_augassign(AST_AugAssign *node);
virtual bool visit_augbinop(AST_AugBinOp *node);
virtual bool visit_attribute(AST_Attribute *node);
virtual bool visit_binop(AST_BinOp *node);
virtual bool visit_boolop(AST_BoolOp *node);
......
......@@ -198,7 +198,7 @@ class CFGVisitor : public ASTVisitor {
std::string nodeName(AST_expr* node) {
std::string nodeName(AST* node) {
char buf[40];
snprintf(buf, 40, "#%p", node);
return std::string(buf);
......@@ -670,7 +670,7 @@ class CFGVisitor : public ASTVisitor {
AST_Assign* remapped = new AST_Assign();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapExpr(node->value);
remapped->value = remapExpr(node->value, false);
// TODO bad that it's reusing the AST nodes?
remapped->targets = node->targets;
push_back(remapped);
......@@ -678,14 +678,79 @@ class CFGVisitor : public ASTVisitor {
}
virtual bool visit_augassign(AST_AugAssign* node) {
AST_AugAssign* remapped = new AST_AugAssign();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapExpr(node->value);
// augassign is pretty tricky; "x" += "y" mostly textually maps to
// "x" = "x" =+ "y" (using "=+" to represent an augbinop)
// except that "x" only gets evaluated once. So it's something like
// "target", val = eval("x")
// "target" = val =+ "y"
// where "target" is handled specially, because it can't just be a name;
// it has to be a name-only version of the target type (ex subscript, attribute).
// So for "f().x += g()", it has to translate to
// "c = f(); y = c.x; z = g(); c.x = y =+ z"
//
// Even if the target is a simple name, it can be complicated, because the
// value can change the name. For "x += f()", have to translate to
// "y = x; z = f(); x = y =+ z"
AST_expr* remapped_target;
AST_expr* remapped_lhs;
// TODO bad that it's reusing the AST nodes?
remapped->target = node->target;
remapped->op_type = node->op_type;
push_back(remapped);
switch (node->target->type) {
case AST_TYPE::Name: {
AST_Name* n = static_cast<AST_Name*>(node->target);
assert(n->ctx_type == AST_TYPE::Store);
push_back(makeAssign(nodeName(node), makeName(n->id, AST_TYPE::Load)));
remapped_target = n;
remapped_lhs = makeName(nodeName(node), AST_TYPE::Load);
break;
}
case AST_TYPE::Subscript: {
AST_Subscript *s = static_cast<AST_Subscript*>(node->target);
assert(s->ctx_type == AST_TYPE::Store);
AST_Subscript *s_target = new AST_Subscript();
s_target->value = remapExpr(s->value);
s_target->slice = remapExpr(s->slice);
s_target->ctx_type = AST_TYPE::Store;
remapped_target = s_target;
AST_Subscript *s_lhs = new AST_Subscript();
s_lhs->value = s_target->value;
s_lhs->slice = s_target->slice;
s_lhs->ctx_type = AST_TYPE::Load;
remapped_lhs = remapExpr(s_lhs);
break;
}
case AST_TYPE::Attribute: {
AST_Attribute *a = static_cast<AST_Attribute*>(node->target);
assert(a->ctx_type == AST_TYPE::Store);
AST_Attribute *a_target = new AST_Attribute();
a_target->value = remapExpr(a->value);
a_target->attr = a->attr;
a_target->ctx_type = AST_TYPE::Store;
remapped_target = a_target;
AST_Attribute *a_lhs = new AST_Attribute();
a_lhs->value = a_target->value;
a_lhs->attr = a->attr;
a_lhs->ctx_type = AST_TYPE::Load;
remapped_lhs = remapExpr(a_lhs);
break;
}
default:
RELEASE_ASSERT(0, "%d", node->target->type);
}
AST_AugBinOp* binop = new AST_AugBinOp();
binop->op_type = node->op_type;
binop->left = remapped_lhs;
binop->right = remapExpr(node->value);
AST_stmt* assign = makeAssign(remapped_target, binop);
push_back(assign);
return true;
}
......
......@@ -62,7 +62,7 @@ void force() {
FORCE(nonzero);
FORCE(binop);
FORCE(compare);
FORCE(augassign);
FORCE(augbinop);
FORCE(unboxedLen);
FORCE(getitem);
FORCE(getclsattr);
......
......@@ -1661,7 +1661,7 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
return rtn;
}
extern "C" Box* augassign(Box* lhs, Box* rhs, int op_type) {
extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type) {
static StatCounter slowpath_binop("slowpath_binop");
slowpath_binop.log();
//static StatCounter nopatch_binop("nopatch_binop");
......
......@@ -54,7 +54,7 @@ extern "C" void dump(Box* obj);
//extern "C" Box* trap();
extern "C" i64 unboxedLen(Box* obj);
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* augbinop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getGlobal(BoxedModule* m, std::string *name, bool from_global);
extern "C" Box* getitem(Box* value, Box* slice);
extern "C" void setitem(Box* target, Box* slice, Box* value);
......
......@@ -28,5 +28,20 @@ l = l + l
print l
print l2
def f2():
# It is *not* ok to translate "expr += y" into "name = expr; name += y"
l = range(10)
l[0] += 5
print l[0]
class C(object):
pass
c = C()
c.x = 1
c.x += 2
print c.x
f2()
print f(4, 2)
print f(4.1, 2.3)
......@@ -48,7 +48,70 @@ def f5():
f5()
def f6():
x = -100
x += [x for x in [50, 51, 52]][0]
print x
# Prints "-50"
f6()
def f7():
global c
class C(object):
pass
c = C()
c.x = 0
def inner1():
global c
print "inner1"
c.x = 25
return c
def inner2():
global c
print "inner2"
c.x = 50
return 1
inner1().x += inner2()
print c.x # prints "26"
f7()
def f8():
global l
l = [0]
def inner1():
global l
print "inner1"
l[0] = 25
return l
def inner2():
global l
print "inner2"
l[0] = 50
return 1
inner1()[0] += inner2()
print l[0] # prints "26"
f8()
x = 9
def f9():
global x
def inner():
global x
x = 5
return 1
x += inner()
print x
f9()
def f10():
# This should error: the lhs is evaluated first
x += [x for x in xrange(5)][0]
print x
f6()
f10()
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