Commit a404585d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fairly large refactor: do much more during the CFG lowering.

In particular, lower all control-flow-involving expressions (such as boolops,
list comprehensions, if expressions) into actual control flow.  This requires
unfolding the AST into a flat structure, since the control-flow-expression can
be nested inside other expressions, including other control-flow-expressions.

The IRGenerator was doing this before, but was leading to duplication because
it's very similar to what the CFG generator already has to do.

Doing this earlier in the pipeline means that more analysis passes can work on
the lowered expressions, rather than having to be taught how they work.  In
particular, the name analysis does not need to have to special case the fact
that list comprehensions may set names -- but aren't guaranteed to if they don't
get executed or the iterator is empty.  I tried implementing list comprehensions
without doing this, and a bunch of the work was in reimplementing the logic that
the analyzers already implement.

As a side benefit, deopts become much easier since the AST is already unfolded;
this change gets rid of the messy fake-variable-setting way that the IRGenerator
was unfolding the AST to get this same effect.
parent 26f6004f
...@@ -133,6 +133,9 @@ COMMON_LDFLAGS := -B../tools/build_system -L/usr/local/lib -lpthread -ldl -lcurs ...@@ -133,6 +133,9 @@ COMMON_LDFLAGS := -B../tools/build_system -L/usr/local/lib -lpthread -ldl -lcurs
# Make sure that we put all symbols in the dynamic symbol table so that MCJIT can load them; # Make sure that we put all symbols in the dynamic symbol table so that MCJIT can load them;
# TODO should probably do the linking before MCJIT # TODO should probably do the linking before MCJIT
COMMON_LDFLAGS += -Wl,-E COMMON_LDFLAGS += -Wl,-E
# For now, link in libstdc++ statically, since the system libstdc++ is likely to be too old:
COMMON_LDFLAGS += -static-libstdc++
LDFLAGS := $(LLVM_LDFLAGS) $(COMMON_LDFLAGS) LDFLAGS := $(LLVM_LDFLAGS) $(COMMON_LDFLAGS)
LDFLAGS_DEBUG := $(LLVM_DEBUG_LDFLAGS) $(COMMON_LDFLAGS) LDFLAGS_DEBUG := $(LLVM_DEBUG_LDFLAGS) $(COMMON_LDFLAGS)
LDFLAGS_PROFILE = $(LLVM_PROFILE_LDFLAGS) -pg $(COMMON_LDFLAGS) LDFLAGS_PROFILE = $(LLVM_PROFILE_LDFLAGS) -pg $(COMMON_LDFLAGS)
...@@ -238,6 +241,10 @@ run_gcunittests: unittests/gc ...@@ -238,6 +241,10 @@ run_gcunittests: unittests/gc
run_unittests:: run_gcunittests run_unittests:: run_gcunittests
dbg_unittests:: dbg_gcunittests dbg_unittests:: dbg_gcunittests
define checksha
test "$$($1 | sha1sum)" = "$2 -"
endef
.PHONY: test test_debug test_prof test_release .PHONY: test test_debug test_prof test_release
test_debug: pyston_dbg ext test_debug: pyston_dbg ext
python ../tools/tester.py -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS) python ../tools/tester.py -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS)
...@@ -251,7 +258,7 @@ test_prof: pyston_prof ext ...@@ -251,7 +258,7 @@ test_prof: pyston_prof ext
python ../tools/tester.py -P -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS) python ../tools/tester.py -P -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS)
python ../tools/tester.py -P -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS) python ../tools/tester.py -P -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS)
python ../tools/tester.py -P -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS) python ../tools/tester.py -P -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS)
test: ext test: ext pyston_dbg
$(MAKE) pyston_dbg $(MAKE) pyston_dbg
# $(MAKE) run_unittests # $(MAKE) run_unittests
$(MAKE) test_debug $(MAKE) test_debug
...@@ -259,13 +266,12 @@ test: ext ...@@ -259,13 +266,12 @@ test: ext
@# jit_prof forces the use of GCC as the compiler, which can expose other errors, so just build it and see what happens: @# jit_prof forces the use of GCC as the compiler, which can expose other errors, so just build it and see what happens:
# $(MAKE) test_prof # $(MAKE) test_prof
$(MAKE) pyston_prof $(MAKE) pyston_prof
./pyston_prof -q $(TESTS_DIR)/raytrace_small.py | sha1sum $(call checksha,./pyston_prof -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
$(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
echo "All tests passed" echo "All tests passed"
define checksha
test "$$($1 | sha1sum)" = "$2 -"
endef
check: check:
$(MAKE) pyston_dbg $(MAKE) pyston_dbg
$(call checksha,./pyston_dbg -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) $(call checksha,./pyston_dbg -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d)
......
...@@ -310,6 +310,7 @@ static ConcreteCompilerVariable* _call(IREmitter &emitter, llvm::Value* func, vo ...@@ -310,6 +310,7 @@ static ConcreteCompilerVariable* _call(IREmitter &emitter, llvm::Value* func, vo
std::vector<BoxedClass*> guaranteed_classes; std::vector<BoxedClass*> guaranteed_classes;
std::vector<ConcreteCompilerVariable*> converted_args; std::vector<ConcreteCompilerVariable*> converted_args;
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
assert(args[i]);
converted_args.push_back(args[i]->makeConverted(emitter, args[i]->getBoxType())); converted_args.push_back(args[i]->makeConverted(emitter, args[i]->getBoxType()));
guaranteed_classes.push_back(converted_args.back()->guaranteedClass()); guaranteed_classes.push_back(converted_args.back()->guaranteedClass());
} }
...@@ -545,6 +546,14 @@ class AbstractFunctionType : public CompilerType { ...@@ -545,6 +546,14 @@ class AbstractFunctionType : public CompilerType {
} }
}; };
CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*> &arg_types) {
std::vector<AbstractFunctionType::Sig*> sigs;
AbstractFunctionType::Sig *sig = new AbstractFunctionType::Sig();
sig->rtn_type = rtn_type;
sig->arg_types = arg_types;
return AbstractFunctionType::get(sigs);
}
class IntType : public ConcreteCompilerType { class IntType : public ConcreteCompilerType {
public: public:
IntType() {} IntType() {}
......
...@@ -314,6 +314,7 @@ CompilerVariable* makeTuple(const std::vector<CompilerVariable*> &elts); ...@@ -314,6 +314,7 @@ CompilerVariable* makeTuple(const std::vector<CompilerVariable*> &elts);
ConcreteCompilerType* typeFromClass(BoxedClass*); ConcreteCompilerType* typeFromClass(BoxedClass*);
CompilerType* typeOfClassobj(BoxedClass*); CompilerType* typeOfClassobj(BoxedClass*);
CompilerType* makeTupleType(const std::vector<CompilerType*> &elt_types); CompilerType* makeTupleType(const std::vector<CompilerType*> &elt_types);
CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*> &arg_types);
} // namespace pyston } // namespace pyston
......
...@@ -212,10 +212,10 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -212,10 +212,10 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalAttribute(AST_Attribute *node) { CompilerVariable* evalAttribute(AST_Attribute *node) {
assert(state != PARTIAL);
assert(node->ctx_type == AST_TYPE::Load); assert(node->ctx_type == AST_TYPE::Load);
CompilerVariable *value = evalExpr(node->value); CompilerVariable *value = evalExpr(node->value);
if (state == PARTIAL)
return NULL;
CompilerVariable *rtn = value->getattr(emitter, node->attr); CompilerVariable *rtn = value->getattr(emitter, node->attr);
value->decvref(emitter); value->decvref(emitter);
...@@ -223,9 +223,9 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -223,9 +223,9 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalClsAttribute(AST_ClsAttribute *node) { CompilerVariable* evalClsAttribute(AST_ClsAttribute *node) {
assert(state != PARTIAL);
CompilerVariable *value = evalExpr(node->value); CompilerVariable *value = evalExpr(node->value);
if (state == PARTIAL)
return NULL;
//ASSERT((node->attr == "__iter__" || node->attr == "__hasnext__" || node->attr == "next" || node->attr == "__enter__" || node->attr == "__exit__") && (value->getType() == UNDEF || value->getType() == value->getBoxType()) && "inefficient for anything else, should change", "%s", node->attr.c_str()); //ASSERT((node->attr == "__iter__" || node->attr == "__hasnext__" || node->attr == "next" || node->attr == "__enter__" || node->attr == "__exit__") && (value->getType() == UNDEF || value->getType() == value->getBoxType()) && "inefficient for anything else, should change", "%s", node->attr.c_str());
...@@ -257,6 +257,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -257,6 +257,8 @@ class IRGeneratorImpl : public IRGenerator {
Compare, Compare,
}; };
CompilerVariable* _evalBinExp(CompilerVariable *left, CompilerVariable *right, AST_TYPE::AST_TYPE type, BinExpType exp_type) { CompilerVariable* _evalBinExp(CompilerVariable *left, CompilerVariable *right, AST_TYPE::AST_TYPE type, BinExpType exp_type) {
assert(state != PARTIAL);
assert(left); assert(left);
assert(right); assert(right);
...@@ -471,18 +473,10 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -471,18 +473,10 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalBinOp(AST_BinOp *node) { CompilerVariable* evalBinOp(AST_BinOp *node) {
assert(state != PARTIAL);
CompilerVariable *left = evalExpr(node->left); CompilerVariable *left = evalExpr(node->left);
_setFake(_nodeFakeName(0, node), left); // 'fakes' are for handling deopt entries
CompilerVariable *right = evalExpr(node->right); CompilerVariable *right = evalExpr(node->right);
_setFake(_nodeFakeName(1, node), right);
if (state == PARTIAL) {
_clearFake(_nodeFakeName(0, node));
_clearFake(_nodeFakeName(1, node));
return NULL;
}
left = _getFake(_nodeFakeName(0, node));
right = _getFake(_nodeFakeName(1, node));
assert(node->op_type != AST_TYPE::Is && node->op_type != AST_TYPE::IsNot && "not tested yet"); assert(node->op_type != AST_TYPE::Is && node->op_type != AST_TYPE::IsNot && "not tested yet");
...@@ -492,86 +486,13 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -492,86 +486,13 @@ class IRGeneratorImpl : public IRGenerator {
return rtn; return rtn;
} }
CompilerVariable* evalBoolOp(AST_BoolOp *node) { CompilerVariable* evalCompare(AST_Compare *node) {
assert(state != PARTIAL); assert(state != PARTIAL);
assert(node->op_type == AST_TYPE::And || node->op_type == AST_TYPE::Or);
bool is_and = node->op_type == AST_TYPE::And;
int nvals = node->values.size();
assert(nvals >= 2);
std::vector<llvm::BasicBlock*> starting_blocks;
for (int i = 0; i < nvals - 1; i++) {
starting_blocks.push_back(llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction()));
}
llvm::BasicBlock *exit_block = llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction());
std::vector<llvm::BasicBlock*> ending_blocks;
std::vector<llvm::Value*> converted_vals;
ConcreteCompilerVariable *prev = NULL;
for (int i = 0; i < nvals; i++) {
if (i > 0) {
assert(prev);
prev->decvref(emitter);
}
CompilerVariable *v = evalExpr(node->values[i]);
ConcreteCompilerVariable *converted = prev = v->makeConverted(emitter, v->getBoxType());
v->decvref(emitter);
converted_vals.push_back(converted->getValue());
ending_blocks.push_back(curblock);
if (i == nvals - 1) {
emitter.getBuilder()->CreateBr(exit_block);
emitter.getBuilder()->SetInsertPoint(exit_block);
curblock = exit_block;
} else {
ConcreteCompilerVariable *nz = converted->nonzero(emitter);
//ConcreteCompilerVariable *nz = v->nonzero(emitter);
assert(nz->getType() == BOOL);
llvm::Value* nz_v = nz->getValue();
if (is_and)
emitter.getBuilder()->CreateCondBr(nz_v, starting_blocks[i], exit_block);
else
emitter.getBuilder()->CreateCondBr(nz_v, exit_block, starting_blocks[i]);
// Shouldn't generate any code, so should be safe to put after branch instruction;
// if that assumption fails, will fail loudly.
nz->decvref(emitter);
emitter.getBuilder()->SetInsertPoint(starting_blocks[i]);
curblock = starting_blocks[i];
}
}
// TODO prev (from the last block) doesn't get freed!
llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(g.llvm_value_type_ptr, nvals);
for (int i = 0; i < nvals; i++) {
phi->addIncoming(converted_vals[i], ending_blocks[i]);
}
//cf->func->dump();
return new ConcreteCompilerVariable(UNKNOWN, phi, true);
}
CompilerVariable* evalCompare(AST_Compare *node) {
RELEASE_ASSERT(node->ops.size() == 1, ""); RELEASE_ASSERT(node->ops.size() == 1, "");
CompilerVariable *left = evalExpr(node->left); CompilerVariable *left = evalExpr(node->left);
_setFake(_nodeFakeName(0, node), left); // 'fakes' are for handling deopt entries
CompilerVariable *right = evalExpr(node->comparators[0]); CompilerVariable *right = evalExpr(node->comparators[0]);
_setFake(_nodeFakeName(1, node), right);
if (state == PARTIAL) {
_clearFake(_nodeFakeName(0, node));
_clearFake(_nodeFakeName(1, node));
return NULL;
}
left = _getFake(_nodeFakeName(0, node));
right = _getFake(_nodeFakeName(1, node));
assert(left); assert(left);
assert(right); assert(right);
...@@ -583,6 +504,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -583,6 +504,8 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalCall(AST_Call *node) { CompilerVariable* evalCall(AST_Call *node) {
assert(state != PARTIAL);
bool is_callattr; bool is_callattr;
bool callattr_clsonly = false; bool callattr_clsonly = false;
std::string *attr = NULL; std::string *attr = NULL;
...@@ -604,24 +527,10 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -604,24 +527,10 @@ class IRGeneratorImpl : public IRGenerator {
func = evalExpr(node->func); func = evalExpr(node->func);
} }
_setFake(_nodeFakeName(-1, node), func);
std::vector<CompilerVariable*> args; std::vector<CompilerVariable*> args;
for (int i = 0; i < node->args.size(); i++) { for (int i = 0; i < node->args.size(); i++) {
CompilerVariable *a = evalExpr(node->args[i]); CompilerVariable *a = evalExpr(node->args[i]);
_setFake(_nodeFakeName(i, node), a); args.push_back(a);
}
if (state == PARTIAL) {
_clearFake(_nodeFakeName(-1, node));
for (int i = 0; i < node->args.size(); i++) {
_clearFake(_nodeFakeName(i, node));
}
return NULL;
}
func = _getFake(_nodeFakeName(-1, node));
for (int i = 0; i < node->args.size(); i++) {
args.push_back(_getFake(_nodeFakeName(i, node)));
} }
//if (VERBOSITY("irgen") >= 1) //if (VERBOSITY("irgen") >= 1)
...@@ -655,6 +564,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -655,6 +564,8 @@ class IRGeneratorImpl : public IRGenerator {
for (int i = 0; i < node->keys.size(); i++) { for (int i = 0; i < node->keys.size(); i++) {
CompilerVariable *key = evalExpr(node->keys[i]); CompilerVariable *key = evalExpr(node->keys[i]);
CompilerVariable *value = evalExpr(node->values[i]); CompilerVariable *value = evalExpr(node->values[i]);
assert(key);
assert(value);
std::vector<CompilerVariable*> args; std::vector<CompilerVariable*> args;
args.push_back(key); args.push_back(key);
...@@ -679,25 +590,18 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -679,25 +590,18 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalIndex(AST_Index *node) { CompilerVariable* evalIndex(AST_Index *node) {
assert(state != PARTIAL);
return evalExpr(node->value); return evalExpr(node->value);
} }
CompilerVariable* evalList(AST_List *node) { CompilerVariable* evalList(AST_List *node) {
for (int i = 0; i < node->elts.size(); i++) { assert(state != PARTIAL);
CompilerVariable *value = evalExpr(node->elts[i]);
_setFake(_nodeFakeName(i, node), value);
}
if (state == PARTIAL) {
for (int i = 0; i < node->elts.size(); i++) {
_clearFake(_nodeFakeName(i, node));
}
return NULL;
}
std::vector<CompilerVariable*> elts; std::vector<CompilerVariable*> elts;
for (int i = 0; i < node->elts.size(); i++) { for (int i = 0; i < node->elts.size(); i++) {
elts.push_back(_getFake(_nodeFakeName(i, node))); CompilerVariable *value = evalExpr(node->elts[i]);
elts.push_back(value);
} }
llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createList); llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createList);
...@@ -717,21 +621,13 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -717,21 +621,13 @@ class IRGeneratorImpl : public IRGenerator {
return rtn; return rtn;
} }
//CompilerVariable* evalListComp(AST_ListComp *node) {
//assert(node->generators.size() == 1 && "unsupported");
//assert(state != PARTIAL && "unsupported");
//
//assert(0);
//}
CompilerVariable* getNone() { CompilerVariable* getNone() {
ConcreteCompilerVariable *v = new ConcreteCompilerVariable(typeFromClass(none_cls), embedConstantPtr(None, g.llvm_value_type_ptr), false); ConcreteCompilerVariable *v = new ConcreteCompilerVariable(typeFromClass(none_cls), embedConstantPtr(None, g.llvm_value_type_ptr), false);
return v; return v;
} }
CompilerVariable* evalName(AST_Name *node) { CompilerVariable* evalName(AST_Name *node) {
if (state == PARTIAL) assert(state != PARTIAL);
return NULL;
if (irstate->getScopeInfo()->refersToGlobal(node->id)) { if (irstate->getScopeInfo()->refersToGlobal(node->id)) {
if (1) { if (1) {
...@@ -784,8 +680,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -784,8 +680,8 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalNum(AST_Num *node) { CompilerVariable* evalNum(AST_Num *node) {
if (state == PARTIAL) assert(state != PARTIAL);
return NULL;
if (node->num_type == AST_Num::INT) if (node->num_type == AST_Num::INT)
return makeInt(node->n_int); return makeInt(node->n_int);
else if (node->num_type == AST_Num::FLOAT) else if (node->num_type == AST_Num::FLOAT)
...@@ -795,8 +691,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -795,8 +691,7 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalSlice(AST_Slice *node) { CompilerVariable* evalSlice(AST_Slice *node) {
if (state == PARTIAL) assert(state != PARTIAL);
return NULL;
CompilerVariable *start, *stop, *step; CompilerVariable *start, *stop, *step;
start = node->lower ? evalExpr(node->lower) : getNone(); start = node->lower ? evalExpr(node->lower) : getNone();
...@@ -824,24 +719,16 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -824,24 +719,16 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalStr(AST_Str *node) { CompilerVariable* evalStr(AST_Str *node) {
if (state == PARTIAL) assert(state != PARTIAL);
return NULL;
return makeStr(&node->s); return makeStr(&node->s);
} }
CompilerVariable* evalSubscript(AST_Subscript *node) { CompilerVariable* evalSubscript(AST_Subscript *node) {
assert(state != PARTIAL);
CompilerVariable *value = evalExpr(node->value); CompilerVariable *value = evalExpr(node->value);
_setFake(_nodeFakeName(0, node), value); // 'fakes' are for handling deopt entries
CompilerVariable *slice = evalExpr(node->slice); CompilerVariable *slice = evalExpr(node->slice);
_setFake(_nodeFakeName(1, node), slice);
if (state == PARTIAL) {
_clearFake(_nodeFakeName(0, node));
_clearFake(_nodeFakeName(1, node));
return NULL;
}
value = _getFake(_nodeFakeName(0, node));
slice = _getFake(_nodeFakeName(1, node));
CompilerVariable *rtn = value->getitem(emitter, slice); CompilerVariable *rtn = value->getitem(emitter, slice);
value->decvref(emitter); value->decvref(emitter);
...@@ -850,21 +737,12 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -850,21 +737,12 @@ class IRGeneratorImpl : public IRGenerator {
} }
CompilerVariable* evalTuple(AST_Tuple *node) { CompilerVariable* evalTuple(AST_Tuple *node) {
for (int i = 0; i < node->elts.size(); i++) { assert(state != PARTIAL);
CompilerVariable *value = evalExpr(node->elts[i]);
_setFake(_nodeFakeName(i, node), value);
}
if (state == PARTIAL) {
for (int i = 0; i < node->elts.size(); i++) {
_clearFake(_nodeFakeName(i, node));
}
return NULL;
}
std::vector<CompilerVariable*> elts; std::vector<CompilerVariable*> elts;
for (int i = 0; i < node->elts.size(); i++) { for (int i = 0; i < node->elts.size(); i++) {
elts.push_back(_getFake(_nodeFakeName(i, node))); CompilerVariable *value = evalExpr(node->elts[i]);
elts.push_back(value);
} }
// TODO makeTuple should probably just transfer the vref, but I want to keep things consistent // TODO makeTuple should probably just transfer the vref, but I want to keep things consistent
...@@ -902,6 +780,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -902,6 +780,8 @@ class IRGeneratorImpl : public IRGenerator {
} }
ConcreteCompilerVariable* unboxVar(ConcreteCompilerType *t, llvm::Value *v, bool grabbed) { ConcreteCompilerVariable* unboxVar(ConcreteCompilerType *t, llvm::Value *v, bool grabbed) {
assert(state != PARTIAL);
if (t == BOXED_INT) { if (t == BOXED_INT) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(INT, unboxed, true); ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(INT, unboxed, true);
...@@ -918,93 +798,90 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -918,93 +798,90 @@ class IRGeneratorImpl : public IRGenerator {
CompilerVariable* evalExpr(AST_expr *node) { CompilerVariable* evalExpr(AST_expr *node) {
emitter.getBuilder()->SetCurrentDebugLocation(llvm::DebugLoc::get(node->lineno, 0, irstate->getFuncDbgInfo())); emitter.getBuilder()->SetCurrentDebugLocation(llvm::DebugLoc::get(node->lineno, 0, irstate->getFuncDbgInfo()));
CompilerVariable *rtn; CompilerVariable *rtn = NULL;
switch (node->type) { if (state != PARTIAL) {
case AST_TYPE::Attribute: switch (node->type) {
rtn = evalAttribute(static_cast<AST_Attribute*>(node)); case AST_TYPE::Attribute:
break; rtn = evalAttribute(static_cast<AST_Attribute*>(node));
case AST_TYPE::BinOp: break;
rtn = evalBinOp(static_cast<AST_BinOp*>(node)); case AST_TYPE::BinOp:
break; rtn = evalBinOp(static_cast<AST_BinOp*>(node));
case AST_TYPE::BoolOp: break;
rtn = evalBoolOp(static_cast<AST_BoolOp*>(node)); case AST_TYPE::Call:
break; rtn = evalCall(static_cast<AST_Call*>(node));
case AST_TYPE::Call: break;
rtn = evalCall(static_cast<AST_Call*>(node)); case AST_TYPE::Compare:
break; rtn = evalCompare(static_cast<AST_Compare*>(node));
case AST_TYPE::Compare: break;
rtn = evalCompare(static_cast<AST_Compare*>(node)); case AST_TYPE::Dict:
break; rtn = evalDict(static_cast<AST_Dict*>(node));
case AST_TYPE::Dict: break;
rtn = evalDict(static_cast<AST_Dict*>(node)); case AST_TYPE::Index:
break; rtn = evalIndex(static_cast<AST_Index*>(node));
case AST_TYPE::Index: break;
rtn = evalIndex(static_cast<AST_Index*>(node)); case AST_TYPE::List:
break; rtn = evalList(static_cast<AST_List*>(node));
case AST_TYPE::List: break;
rtn = evalList(static_cast<AST_List*>(node)); //case AST_TYPE::ListComp:
break; //rtn = evalListComp(static_cast<AST_ListComp*>(node));
//case AST_TYPE::ListComp: //break;
//rtn = evalListComp(static_cast<AST_ListComp*>(node)); case AST_TYPE::Name:
//break; rtn = evalName(static_cast<AST_Name*>(node));
case AST_TYPE::Name: break;
rtn = evalName(static_cast<AST_Name*>(node)); case AST_TYPE::Num:
break; rtn = evalNum(static_cast<AST_Num*>(node));
case AST_TYPE::Num: break;
rtn = evalNum(static_cast<AST_Num*>(node)); case AST_TYPE::Slice:
break; rtn = evalSlice(static_cast<AST_Slice*>(node));
case AST_TYPE::Slice: break;
rtn = evalSlice(static_cast<AST_Slice*>(node)); case AST_TYPE::Str:
break; rtn = evalStr(static_cast<AST_Str*>(node));
case AST_TYPE::Str: break;
rtn = evalStr(static_cast<AST_Str*>(node)); case AST_TYPE::Subscript:
break; rtn = evalSubscript(static_cast<AST_Subscript*>(node));
case AST_TYPE::Subscript: break;
rtn = evalSubscript(static_cast<AST_Subscript*>(node)); case AST_TYPE::Tuple:
break; rtn = evalTuple(static_cast<AST_Tuple*>(node));
case AST_TYPE::Tuple: break;
rtn = evalTuple(static_cast<AST_Tuple*>(node)); case AST_TYPE::UnaryOp:
break; rtn = evalUnaryOp(static_cast<AST_UnaryOp*>(node));
case AST_TYPE::UnaryOp: break;
rtn = evalUnaryOp(static_cast<AST_UnaryOp*>(node)); case AST_TYPE::ClsAttribute:
break; rtn = evalClsAttribute(static_cast<AST_ClsAttribute*>(node));
case AST_TYPE::ClsAttribute: break;
rtn = evalClsAttribute(static_cast<AST_ClsAttribute*>(node)); default:
break; printf("Unhandled expr type: %d (irgen.cpp:" STRINGIFY(__LINE__) ")\n", node->type);
default: exit(1);
printf("Unhandled expr type: %d (irgen.cpp:" STRINGIFY(__LINE__) ")\n", node->type); }
exit(1);
}
if (rtn == NULL) {
assert(state == PARTIAL);
}
// Out-guarding:
BoxedClass *speculated_class = types->speculatedExprClass(node);
if (speculated_class != NULL && state != PARTIAL) {
assert(rtn); assert(rtn);
ConcreteCompilerType *speculated_type = typeFromClass(speculated_class); // Out-guarding:
if (VERBOSITY("irgen") >= 1) { BoxedClass *speculated_class = types->speculatedExprClass(node);
printf("Speculating that %s is actually %s, at ", rtn->getConcreteType()->debugName().c_str(), speculated_type->debugName().c_str()); if (speculated_class != NULL) {
PrintVisitor printer; assert(rtn);
node->accept(&printer);
printf("\n"); ConcreteCompilerType *speculated_type = typeFromClass(speculated_class);
} if (VERBOSITY("irgen") >= 1) {
printf("Speculating that %s is actually %s, at ", rtn->getConcreteType()->debugName().c_str(), speculated_type->debugName().c_str());
PrintVisitor printer;
node->accept(&printer);
printf("\n");
}
// That's not really a speculation.... could potentially handle this here, but // That's not really a speculation.... could potentially handle this here, but
// I think it's better to just not generate bad speculations: // I think it's better to just not generate bad speculations:
assert(!rtn->canConvertTo(speculated_type)); assert(!rtn->canConvertTo(speculated_type));
ConcreteCompilerVariable *old_rtn = rtn->makeConverted(emitter, UNKNOWN); ConcreteCompilerVariable *old_rtn = rtn->makeConverted(emitter, UNKNOWN);
rtn->decvref(emitter); rtn->decvref(emitter);
llvm::Value* guard_check = old_rtn->makeClassCheck(emitter, speculated_class); llvm::Value* guard_check = old_rtn->makeClassCheck(emitter, speculated_class);
assert(guard_check->getType() == g.i1); assert(guard_check->getType() == g.i1);
createExprTypeGuard(guard_check, node, old_rtn); createExprTypeGuard(guard_check, node, old_rtn);
rtn = unboxVar(speculated_type, old_rtn->getValue(), true); rtn = unboxVar(speculated_type, old_rtn->getValue(), true);
}
} }
// In-guarding: // In-guarding:
...@@ -1098,6 +975,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1098,6 +975,8 @@ class IRGeneratorImpl : public IRGenerator {
} }
} }
assert(rtn || state == PARTIAL);
return rtn; return rtn;
} }
...@@ -1106,11 +985,6 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1106,11 +985,6 @@ class IRGeneratorImpl : public IRGenerator {
snprintf(buf, 40, "!%s_%s", prefix, token); snprintf(buf, 40, "!%s_%s", prefix, token);
return std::string(buf); return std::string(buf);
} }
static std::string _nodeFakeName(int idx, AST* node) {
char buf[40];
snprintf(buf, 40, "%p(%d)_%d", (void*)node, node->type, idx);
return _getFakeName("node", buf);
}
void _setFake(std::string name, CompilerVariable* val) { void _setFake(std::string name, CompilerVariable* val) {
assert(name[0] == '!'); assert(name[0] == '!');
CompilerVariable* &cur = symbol_table[name]; CompilerVariable* &cur = symbol_table[name];
...@@ -1190,6 +1064,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1190,6 +1064,7 @@ class IRGeneratorImpl : public IRGenerator {
} }
void _doUnpackTuple(AST_Tuple* target, CompilerVariable* val) { void _doUnpackTuple(AST_Tuple* target, CompilerVariable* val) {
assert(state != PARTIAL);
int ntargets = target->elts.size(); int ntargets = target->elts.size();
ConcreteCompilerVariable *len = val->len(emitter); ConcreteCompilerVariable *len = val->len(emitter);
emitter.getBuilder()->CreateCall2(g.funcs.checkUnpackingLength, emitter.getBuilder()->CreateCall2(g.funcs.checkUnpackingLength,
...@@ -1203,6 +1078,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1203,6 +1078,7 @@ class IRGeneratorImpl : public IRGenerator {
} }
void _doSet(AST* target, CompilerVariable* val) { void _doSet(AST* target, CompilerVariable* val) {
assert(state != PARTIAL);
switch (target->type) { switch (target->type) {
case AST_TYPE::Attribute: case AST_TYPE::Attribute:
_doSetattr(static_cast<AST_Attribute*>(target), val); _doSetattr(static_cast<AST_Attribute*>(target), val);
...@@ -1226,6 +1102,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1226,6 +1102,7 @@ class IRGeneratorImpl : public IRGenerator {
CompilerVariable *val = evalExpr(node->value); CompilerVariable *val = evalExpr(node->value);
if (state == PARTIAL) if (state == PARTIAL)
return; return;
for (int i = 0; i < node->targets.size(); i++) { for (int i = 0; i < node->targets.size(); i++) {
_doSet(node->targets[i], val); _doSet(node->targets[i], val);
} }
...@@ -1234,18 +1111,9 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1234,18 +1111,9 @@ class IRGeneratorImpl : public IRGenerator {
void doAugAssign(AST_AugAssign *node) { void doAugAssign(AST_AugAssign *node) {
CompilerVariable *target = evalExpr(node->target); CompilerVariable *target = evalExpr(node->target);
_setFake(_nodeFakeName(0, node), target); // 'fakes' are for handling deopt entries
CompilerVariable *val = evalExpr(node->value); CompilerVariable *val = evalExpr(node->value);
_setFake(_nodeFakeName(1, node), val); if (state == PARTIAL)
if (state == PARTIAL) {
_clearFake(_nodeFakeName(0, node));
_clearFake(_nodeFakeName(1, node));
return; return;
}
target = _getFake(_nodeFakeName(0, node));
val = _getFake(_nodeFakeName(1, node));
CompilerVariable *rtn = this->_evalBinExp(target, val, node->op_type, AugAssign); CompilerVariable *rtn = this->_evalBinExp(target, val, node->op_type, AugAssign);
target->decvref(emitter); target->decvref(emitter);
...@@ -1320,11 +1188,10 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1320,11 +1188,10 @@ class IRGeneratorImpl : public IRGenerator {
func->decvref(emitter); func->decvref(emitter);
} }
void doIf(AST_If *node) {
assert(0);
}
void doImport(AST_Import *node) { void doImport(AST_Import *node) {
if (state == PARTIAL)
return;
for (int i = 0; i < node->names.size(); i++) { for (int i = 0; i < node->names.size(); i++) {
AST_alias *alias = node->names[i]; AST_alias *alias = node->names[i];
...@@ -1339,26 +1206,27 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1339,26 +1206,27 @@ class IRGeneratorImpl : public IRGenerator {
} }
void doPrint(AST_Print *node) { void doPrint(AST_Print *node) {
if (state == PARTIAL)
return;
assert(node->dest == NULL); assert(node->dest == NULL);
for (int i = 0; i < node->values.size(); i++) { for (int i = 0; i < node->values.size(); i++) {
if (i > 0) { if (i > 0) {
emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" ")); emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" "));
} }
CompilerVariable* var = evalExpr(node->values[i]); CompilerVariable* var = evalExpr(node->values[i]);
if (state != PARTIAL) { var->print(emitter);
var->print(emitter); var->decvref(emitter);
var->decvref(emitter);
}
}
if (state != PARTIAL) {
if (node->nl)
emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr("\n"));
else
emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" "));
} }
if (node->nl)
emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr("\n"));
else
emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" "));
} }
void doReturn(AST_Return *node) { void doReturn(AST_Return *node) {
CompilerVariable *val; CompilerVariable *val;
if (node->value == NULL) { if (node->value == NULL) {
if (irstate->getReturnType() == VOID) { if (irstate->getReturnType() == VOID) {
...@@ -1370,8 +1238,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1370,8 +1238,8 @@ class IRGeneratorImpl : public IRGenerator {
val = new ConcreteCompilerVariable(NONE, embedConstantPtr(None, g.llvm_value_type_ptr), false); val = new ConcreteCompilerVariable(NONE, embedConstantPtr(None, g.llvm_value_type_ptr), false);
} else { } else {
val = evalExpr(node->value); val = evalExpr(node->value);
assert(state != PARTIAL);
} }
assert(state != PARTIAL);
assert(val); assert(val);
// If we ask the return variable to become UNKNOWN (the typical return type), // If we ask the return variable to become UNKNOWN (the typical return type),
...@@ -1401,6 +1269,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1401,6 +1269,7 @@ class IRGeneratorImpl : public IRGenerator {
CompilerVariable *val = evalExpr(node->test); CompilerVariable *val = evalExpr(node->test);
assert(state != PARTIAL); assert(state != PARTIAL);
assert(val);
ConcreteCompilerVariable* nonzero = val->nonzero(emitter); ConcreteCompilerVariable* nonzero = val->nonzero(emitter);
assert(nonzero->getType() == BOOL); assert(nonzero->getType() == BOOL);
...@@ -1419,11 +1288,15 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1419,11 +1288,15 @@ class IRGeneratorImpl : public IRGenerator {
void doExpr(AST_Expr *node) { void doExpr(AST_Expr *node) {
CompilerVariable *var = evalExpr(node->value); CompilerVariable *var = evalExpr(node->value);
if (state != PARTIAL) if (state == PARTIAL)
var->decvref(emitter); return;
var->decvref(emitter);
} }
void doOSRExit(llvm::BasicBlock *normal_target, AST_Jump* osr_key) { void doOSRExit(llvm::BasicBlock *normal_target, AST_Jump* osr_key) {
assert(state != PARTIAL);
llvm::BasicBlock *starting_block = curblock; llvm::BasicBlock *starting_block = curblock;
llvm::BasicBlock *onramp = llvm::BasicBlock::Create(g.context, "onramp", irstate->getLLVMFunction()); llvm::BasicBlock *onramp = llvm::BasicBlock::Create(g.context, "onramp", irstate->getLLVMFunction());
...@@ -1573,6 +1446,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1573,6 +1446,8 @@ class IRGeneratorImpl : public IRGenerator {
} }
void doJump(AST_Jump *node) { void doJump(AST_Jump *node) {
assert(state != PARTIAL);
endBlock(FINISHED); endBlock(FINISHED);
llvm::BasicBlock *target = entry_blocks[node->target->idx]; llvm::BasicBlock *target = entry_blocks[node->target->idx];
...@@ -1602,9 +1477,9 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1602,9 +1477,9 @@ class IRGeneratorImpl : public IRGenerator {
case AST_TYPE::FunctionDef: case AST_TYPE::FunctionDef:
doFunction(static_cast<AST_FunctionDef*>(node)); doFunction(static_cast<AST_FunctionDef*>(node));
break; break;
case AST_TYPE::If: //case AST_TYPE::If:
doIf(static_cast<AST_If*>(node)); //doIf(static_cast<AST_If*>(node));
break; //break;
case AST_TYPE::Import: case AST_TYPE::Import:
doImport(static_cast<AST_Import*>(node)); doImport(static_cast<AST_Import*>(node));
break; break;
...@@ -1647,7 +1522,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1647,7 +1522,7 @@ class IRGeneratorImpl : public IRGenerator {
ScopeInfo *scope_info = irstate->getScopeInfo(); ScopeInfo *scope_info = irstate->getScopeInfo();
for (SymbolTable::iterator it = symbol_table.begin(); it != symbol_table.end();) { for (SymbolTable::iterator it = symbol_table.begin(); it != symbol_table.end();) {
ASSERT(it->first[0] != '!' || startswith(it->first, "!is_defined"), "left a fake variable in the real symbol table? '%s'", it->first.c_str()); //ASSERT(it->first[0] != '!' || startswith(it->first, "!is_defined"), "left a fake variable in the real symbol table? '%s'", it->first.c_str());
if (!source->liveness->isLiveAtEnd(it->first, myblock)) { if (!source->liveness->isLiveAtEnd(it->first, myblock)) {
//printf("%s dead at end of %d; grabbed = %d, %d vrefs\n", it->first.c_str(), myblock->idx, it->second->isGrabbed(), it->second->getVrefs()); //printf("%s dead at end of %d; grabbed = %d, %d vrefs\n", it->first.c_str(), myblock->idx, it->second->isGrabbed(), it->second->getVrefs());
...@@ -1712,7 +1587,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1712,7 +1587,7 @@ class IRGeneratorImpl : public IRGenerator {
ConcreteSymbolTable *phi_st = new ConcreteSymbolTable(); ConcreteSymbolTable *phi_st = new ConcreteSymbolTable();
for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) { for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) {
if (it->first[0] == '!') { if (it->first[0] == '!') {
ASSERT(startswith(it->first, _getFakeName("is_defined", "")), "left a fake variable in the real symbol table? '%s'", it->first.c_str()); //ASSERT(startswith(it->first, _getFakeName("is_defined", "")), "left a fake variable in the real symbol table? '%s'", it->first.c_str());
} else { } else {
ASSERT(source->liveness->isLiveAtEnd(it->first, myblock), "%s", it->first.c_str()); ASSERT(source->liveness->isLiveAtEnd(it->first, myblock), "%s", it->first.c_str());
} }
......
...@@ -59,11 +59,6 @@ class MyMaterializer : public llvm::ValueMaterializer { ...@@ -59,11 +59,6 @@ class MyMaterializer : public llvm::ValueMaterializer {
//llvm::errs() << " is gv\n"; //llvm::errs() << " is gv\n";
assert(gv->getLinkage() != llvm::GlobalVariable::PrivateLinkage); assert(gv->getLinkage() != llvm::GlobalVariable::PrivateLinkage);
r = new_module->getOrInsertGlobal(gv->getName(), gv->getType()->getElementType()); r = new_module->getOrInsertGlobal(gv->getName(), gv->getType()->getElementType());
} else if (llvm::LoadInst *load = llvm::dyn_cast<llvm::LoadInst>(v)) {
//llvm::errs() << " is LoadInst\n";
//load->getPointerOperand()->dump();
llvm::GlobalVariable *gv = llvm::dyn_cast<llvm::GlobalVariable>(load->getPointerOperand());
r = v;
} else if (llvm::GlobalAlias *alias = llvm::dyn_cast<llvm::GlobalAlias>(v)) { } else if (llvm::GlobalAlias *alias = llvm::dyn_cast<llvm::GlobalAlias>(v)) {
llvm::Value* addressee = llvm::cast<llvm::Constant>(materializeValueFor(alias->getAliasedGlobal())); llvm::Value* addressee = llvm::cast<llvm::Constant>(materializeValueFor(alias->getAliasedGlobal()));
assert(addressee); assert(addressee);
......
...@@ -118,7 +118,7 @@ def convert(n, f): ...@@ -118,7 +118,7 @@ def convert(n, f):
else: else:
raise Exception(type(n.n)) raise Exception(type(n.n))
# print n, sorted(n.__dict__.items()) # print >>sys.stderr, n, sorted(n.__dict__.items())
for k, v in sorted(n.__dict__.items()): for k, v in sorted(n.__dict__.items()):
if k.startswith('_'): if k.startswith('_'):
continue continue
......
...@@ -380,6 +380,17 @@ AST_If* read_if(BufferedReader *reader) { ...@@ -380,6 +380,17 @@ AST_If* read_if(BufferedReader *reader) {
return rtn; return rtn;
} }
AST_IfExp* read_ifexp(BufferedReader *reader) {
AST_IfExp *rtn = new AST_IfExp();
rtn->body = readASTExpr(reader);
rtn->col_offset = readColOffset(reader);
rtn->lineno = reader->readULL();
rtn->orelse = readASTExpr(reader);
rtn->test = readASTExpr(reader);
return rtn;
}
AST_Import* read_import(BufferedReader *reader) { AST_Import* read_import(BufferedReader *reader) {
AST_Import *rtn = new AST_Import(); AST_Import *rtn = new AST_Import();
...@@ -595,6 +606,8 @@ AST_expr* readASTExpr(BufferedReader *reader) { ...@@ -595,6 +606,8 @@ AST_expr* readASTExpr(BufferedReader *reader) {
return read_compare(reader); return read_compare(reader);
case AST_TYPE::Dict: case AST_TYPE::Dict:
return read_dict(reader); return read_dict(reader);
case AST_TYPE::IfExp:
return read_ifexp(reader);
case AST_TYPE::Index: case AST_TYPE::Index:
return read_index(reader); return read_index(reader);
case AST_TYPE::List: case AST_TYPE::List:
......
...@@ -383,6 +383,19 @@ void AST_If::accept_stmt(StmtVisitor *v) { ...@@ -383,6 +383,19 @@ void AST_If::accept_stmt(StmtVisitor *v) {
v->visit_if(this); v->visit_if(this);
} }
void AST_IfExp::accept(ASTVisitor *v) {
bool skip = v->visit_ifexp(this);
if (skip) return;
this->test->accept(v);
this->body->accept(v);
this->orelse->accept(v);
}
void* AST_IfExp::accept_expr(ExprVisitor *v) {
return v->visit_ifexp(this);
}
void AST_Import::accept(ASTVisitor *v) { void AST_Import::accept(ASTVisitor *v) {
bool skip = v->visit_import(this); bool skip = v->visit_import(this);
if (skip) return; if (skip) return;
...@@ -595,6 +608,7 @@ void* AST_ClsAttribute::accept_expr(ExprVisitor *v) { ...@@ -595,6 +608,7 @@ void* AST_ClsAttribute::accept_expr(ExprVisitor *v) {
void print_ast(AST* ast) { void print_ast(AST* ast) {
PrintVisitor v; PrintVisitor v;
ast->accept(&v); ast->accept(&v);
...@@ -881,6 +895,15 @@ bool PrintVisitor::visit_if(AST_If *node) { ...@@ -881,6 +895,15 @@ bool PrintVisitor::visit_if(AST_If *node) {
return true; return true;
} }
bool PrintVisitor::visit_ifexp(AST_IfExp *node) {
node->body->accept(this);
printf(" if ");
node->test->accept(this);
printf(" else ");
node->orelse->accept(this);
return true;
}
bool PrintVisitor::visit_import(AST_Import *node) { bool PrintVisitor::visit_import(AST_Import *node) {
printf("import "); printf("import ");
for (int i = 0; i < node->names.size(); i++) { for (int i = 0; i < node->names.size(); i++) {
......
...@@ -350,6 +350,17 @@ class AST_If : public AST_stmt { ...@@ -350,6 +350,17 @@ class AST_If : public AST_stmt {
AST_If() : AST_stmt(AST_TYPE::If) {} AST_If() : AST_stmt(AST_TYPE::If) {}
}; };
class AST_IfExp : public AST_expr {
public:
const static AST_TYPE::AST_TYPE TYPE = AST_TYPE::IfExp;
AST_expr *body, *test, *orelse;
virtual void accept(ASTVisitor *v);
virtual void* accept_expr(ExprVisitor *v);
AST_IfExp() : AST_expr(AST_TYPE::IfExp) {}
};
class AST_Import : public AST_stmt { class AST_Import : public AST_stmt {
public: public:
std::vector<AST_alias*> names; std::vector<AST_alias*> names;
...@@ -580,7 +591,6 @@ class AST_ClsAttribute : public AST_expr { ...@@ -580,7 +591,6 @@ class AST_ClsAttribute : public AST_expr {
AST_ClsAttribute() : AST_expr(AST_TYPE::ClsAttribute) {} AST_ClsAttribute() : AST_expr(AST_TYPE::ClsAttribute) {}
}; };
class ASTVisitor { class ASTVisitor {
protected: protected:
public: public:
...@@ -605,6 +615,7 @@ class ASTVisitor { ...@@ -605,6 +615,7 @@ class ASTVisitor {
virtual bool visit_functiondef(AST_FunctionDef *node) { assert(0); abort(); } virtual bool visit_functiondef(AST_FunctionDef *node) { assert(0); abort(); }
virtual bool visit_global(AST_Global *node) { assert(0); abort(); } virtual bool visit_global(AST_Global *node) { assert(0); abort(); }
virtual bool visit_if(AST_If *node) { assert(0); abort(); } virtual bool visit_if(AST_If *node) { assert(0); abort(); }
virtual bool visit_ifexp(AST_IfExp *node) { assert(0); abort(); }
virtual bool visit_import(AST_Import *node) { assert(0); abort(); } virtual bool visit_import(AST_Import *node) { assert(0); abort(); }
virtual bool visit_index(AST_Index *node) { assert(0); abort(); } virtual bool visit_index(AST_Index *node) { assert(0); abort(); }
virtual bool visit_keyword(AST_keyword *node) { assert(0); abort(); } virtual bool visit_keyword(AST_keyword *node) { assert(0); abort(); }
...@@ -651,6 +662,7 @@ class NoopASTVisitor : public ASTVisitor { ...@@ -651,6 +662,7 @@ class NoopASTVisitor : public ASTVisitor {
virtual bool visit_functiondef(AST_FunctionDef *node) { return false; } virtual bool visit_functiondef(AST_FunctionDef *node) { return false; }
virtual bool visit_global(AST_Global *node) { return false; } virtual bool visit_global(AST_Global *node) { return false; }
virtual bool visit_if(AST_If *node) { return false; } virtual bool visit_if(AST_If *node) { return false; }
virtual bool visit_ifexp(AST_IfExp *node) { return false; }
virtual bool visit_import(AST_Import *node) { return false; } virtual bool visit_import(AST_Import *node) { return false; }
virtual bool visit_index(AST_Index *node) { return false; } virtual bool visit_index(AST_Index *node) { return false; }
virtual bool visit_keyword(AST_keyword *node) { return false; } virtual bool visit_keyword(AST_keyword *node) { return false; }
...@@ -685,6 +697,7 @@ class ExprVisitor { ...@@ -685,6 +697,7 @@ class ExprVisitor {
virtual void* visit_clsattribute(AST_ClsAttribute *node) { assert(0); abort(); } virtual void* visit_clsattribute(AST_ClsAttribute *node) { assert(0); abort(); }
virtual void* visit_compare(AST_Compare *node) { assert(0); abort(); } virtual void* visit_compare(AST_Compare *node) { assert(0); abort(); }
virtual void* visit_dict(AST_Dict *node) { assert(0); abort(); } virtual void* visit_dict(AST_Dict *node) { assert(0); abort(); }
virtual void* visit_ifexp(AST_IfExp *node) { assert(0); abort(); }
virtual void* visit_index(AST_Index *node) { assert(0); abort(); } virtual void* visit_index(AST_Index *node) { assert(0); abort(); }
virtual void* visit_list(AST_List *node) { assert(0); abort(); } virtual void* visit_list(AST_List *node) { assert(0); abort(); }
virtual void* visit_name(AST_Name *node) { assert(0); abort(); } virtual void* visit_name(AST_Name *node) { assert(0); abort(); }
...@@ -750,6 +763,7 @@ class PrintVisitor : public ASTVisitor { ...@@ -750,6 +763,7 @@ class PrintVisitor : public ASTVisitor {
virtual bool visit_functiondef(AST_FunctionDef *node); virtual bool visit_functiondef(AST_FunctionDef *node);
virtual bool visit_global(AST_Global *node); virtual bool visit_global(AST_Global *node);
virtual bool visit_if(AST_If *node); virtual bool visit_if(AST_If *node);
virtual bool visit_ifexp(AST_IfExp *node);
virtual bool visit_import(AST_Import *node); virtual bool visit_import(AST_Import *node);
virtual bool visit_index(AST_Index *node); virtual bool visit_index(AST_Index *node);
virtual bool visit_keyword(AST_keyword *node); virtual bool visit_keyword(AST_keyword *node);
......
...@@ -153,7 +153,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -153,7 +153,7 @@ class CFGVisitor : public ASTVisitor {
return call; return call;
} }
AST_expr* makeName(const std::string &id, AST_TYPE::AST_TYPE ctx_type, int lineno=-1, int col_offset=-1) { AST_Name* makeName(const std::string &id, AST_TYPE::AST_TYPE ctx_type, int lineno=-1, int col_offset=-1) {
AST_Name *name = new AST_Name(); AST_Name *name = new AST_Name();
name->id = id; name->id = id;
name->col_offset = col_offset; name->col_offset = col_offset;
...@@ -185,6 +185,316 @@ class CFGVisitor : public ASTVisitor { ...@@ -185,6 +185,316 @@ class CFGVisitor : public ASTVisitor {
return stmt; return stmt;
} }
std::string nodeName(AST_expr* node) {
char buf[40];
snprintf(buf, 40, "!%p", node);
return std::string(buf);
}
AST_expr* remapAttribute(AST_Attribute* node) {
AST_Attribute *rtn = new AST_Attribute();
rtn->ctx_type = node->ctx_type;
rtn->attr = node->attr;
rtn->value = remapExpr(node->value);
return rtn;
}
AST_expr* remapBinOp(AST_BinOp* node) {
AST_BinOp *rtn = new AST_BinOp();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->op_type = node->op_type;
rtn->left = remapExpr(node->left);
rtn->right = remapExpr(node->right);
return rtn;
}
AST_expr* remapBoolOp(AST_BoolOp* node) {
std::string name = nodeName(node);
CFGBlock *starting_block = curblock;
CFGBlock *exit_block = cfg->addDeferredBlock();
for (int i = 0; i < node->values.size() - 1; i++) {
AST_expr* val = remapExpr(node->values[i]);
push_back(makeAssign(name, val));
AST_Branch *br = new AST_Branch();
br->test = val;
push_back(br);
CFGBlock *was_block = curblock;
CFGBlock *next_block = cfg->addBlock();
CFGBlock *crit_break_block = cfg->addBlock();
was_block->connectTo(next_block);
was_block->connectTo(crit_break_block);
if (node->op_type == AST_TYPE::Or) {
br->iftrue = crit_break_block;
br->iffalse = next_block;
} else {
br->iffalse = crit_break_block;
br->iftrue = next_block;
}
curblock = crit_break_block;
AST_Jump* j = new AST_Jump();
j->target = exit_block;
push_back(j);
crit_break_block->connectTo(exit_block);
curblock = next_block;
}
AST_expr* final_val = remapExpr(node->values[node->values.size()-1]);
push_back(makeAssign(name, final_val));
AST_Jump* j = new AST_Jump();
push_back(j);
j->target = exit_block;
curblock->connectTo(exit_block);
cfg->placeBlock(exit_block);
curblock = exit_block;
return makeName(name, AST_TYPE::Load);
}
AST_expr* remapCall(AST_Call* node) {
AST_Call *rtn = new AST_Call();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
if (node->func->type == AST_TYPE::Attribute) {
// TODO this is a cludge to make sure that "callattrs" stick together.
// Probably better to create an AST_Callattr type, and solidify the
// idea that a callattr is a single expression.
rtn->func = remapAttribute(static_cast<AST_Attribute*>(node->func));
} else {
rtn->func = remapExpr(node->func);
}
for (auto e : node->args) {
rtn->args.push_back(remapExpr(e));
}
for (auto e : node->keywords) {
AST_keyword *kw = new AST_keyword();
kw->value = remapExpr(e->value);
kw->arg = e->arg;
rtn->keywords.push_back(kw);
}
rtn->starargs = remapExpr(node->starargs);
rtn->kwargs = remapExpr(node->kwargs);
return rtn;
}
AST_expr* remapCompare(AST_Compare* node) {
AST_Compare *rtn = new AST_Compare();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->ops = node->ops;
rtn->left = remapExpr(node->left);
for (auto elt : node->comparators) {
rtn->comparators.push_back(remapExpr(elt));
}
return rtn;
}
AST_expr* remapDict(AST_Dict* node) {
AST_Dict *rtn = new AST_Dict();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
for (auto k : node->keys) {
rtn->keys.push_back(remapExpr(k));
}
for (auto v : node->values) {
rtn->values.push_back(remapExpr(v));
}
return rtn;
};
AST_expr* remapIfExp(AST_IfExp* node) {
std::string rtn_name = nodeName(node);
AST_expr* test = remapExpr(node->test);
CFGBlock *starting_block = curblock;
AST_Branch *br = new AST_Branch();
br->col_offset = node->col_offset;
br->lineno = node->lineno;
br->test = node->test;
push_back(br);
CFGBlock* iftrue = cfg->addBlock();
iftrue->info = "iftrue";
br->iftrue = iftrue;
starting_block->connectTo(iftrue);
curblock = iftrue;
push_back(makeAssign(rtn_name, remapExpr(node->body)));
AST_Jump* jtrue = new AST_Jump();
push_back(jtrue);
CFGBlock* endtrue = curblock;
CFGBlock* iffalse = cfg->addBlock();
iffalse->info = "iffalse";
br->iffalse = iffalse;
starting_block->connectTo(iffalse);
curblock = iffalse;
push_back(makeAssign(rtn_name, remapExpr(node->orelse)));
AST_Jump* jfalse = new AST_Jump();
push_back(jfalse);
CFGBlock* endfalse = curblock;
CFGBlock* exit_block = cfg->addBlock();
jtrue->target = exit_block;
endtrue->connectTo(exit_block);
jfalse->target = exit_block;
endfalse->connectTo(exit_block);
curblock = exit_block;
return makeName(rtn_name, AST_TYPE::Load);
}
AST_expr* remapIndex(AST_Index* node) {
AST_Index *rtn = new AST_Index();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->value = remapExpr(node->value);
return rtn;
}
AST_expr* remapList(AST_List* node) {
assert(node->ctx_type == AST_TYPE::Load);
AST_List *rtn = new AST_List();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->ctx_type == node->ctx_type;
for (auto elt : node->elts) {
rtn->elts.push_back(remapExpr(elt));
}
return rtn;
}
AST_expr* remapSlice(AST_Slice* node) {
AST_Slice *rtn = new AST_Slice();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->lower = remapExpr(node->lower);
rtn->upper = remapExpr(node->upper);
rtn->step = remapExpr(node->step);
return rtn;
}
AST_expr* remapTuple(AST_Tuple* node) {
assert(node->ctx_type == AST_TYPE::Load);
AST_Tuple *rtn = new AST_Tuple();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->ctx_type == node->ctx_type;
for (auto elt : node->elts) {
rtn->elts.push_back(remapExpr(elt));
}
return rtn;
}
AST_expr* remapSubscript(AST_Subscript* node) {
AST_Subscript *rtn = new AST_Subscript();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->ctx_type = node->ctx_type;
rtn->value = remapExpr(node->value);
rtn->slice = remapExpr(node->slice);
return rtn;
}
AST_expr* remapUnaryOp(AST_UnaryOp* node) {
AST_UnaryOp *rtn = new AST_UnaryOp();
rtn->lineno = node->lineno;
rtn->col_offset = node->col_offset;
rtn->op_type = node->op_type;
rtn->operand = remapExpr(node->operand);
return rtn;
}
AST_expr* remapExpr(AST_expr* node, bool wrap_with_assign=true) {
if (node == NULL)
return NULL;
AST_expr* rtn;
switch (node->type) {
case AST_TYPE::Attribute:
rtn = remapAttribute(static_cast<AST_Attribute*>(node));
break;
case AST_TYPE::BinOp:
rtn = remapBinOp(static_cast<AST_BinOp*>(node));
break;
case AST_TYPE::BoolOp:
rtn = remapBoolOp(static_cast<AST_BoolOp*>(node));
break;
case AST_TYPE::Call:
rtn = remapCall(static_cast<AST_Call*>(node));
break;
case AST_TYPE::Compare:
rtn = remapCompare(static_cast<AST_Compare*>(node));
break;
case AST_TYPE::Dict:
rtn = remapDict(static_cast<AST_Dict*>(node));
break;
case AST_TYPE::IfExp:
rtn = remapIfExp(static_cast<AST_IfExp*>(node));
break;
case AST_TYPE::Index:
rtn = remapIndex(static_cast<AST_Index*>(node));
break;
case AST_TYPE::List:
rtn = remapList(static_cast<AST_List*>(node));
break;
case AST_TYPE::Name:
return node;
case AST_TYPE::Num:
return node;
case AST_TYPE::Slice:
rtn = remapSlice(static_cast<AST_Slice*>(node));
break;
case AST_TYPE::Str:
return node;
case AST_TYPE::Subscript:
rtn = remapSubscript(static_cast<AST_Subscript*>(node));
break;
case AST_TYPE::Tuple:
rtn = remapTuple(static_cast<AST_Tuple*>(node));
break;
case AST_TYPE::UnaryOp:
rtn = remapUnaryOp(static_cast<AST_UnaryOp*>(node));
break;
default:
RELEASE_ASSERT(0, "%d", node->type);
}
if (wrap_with_assign && rtn->type != AST_TYPE::Name) {
std::string name = nodeName(node);
push_back(makeAssign(name, rtn));
return makeName(name, AST_TYPE::Load);
} else {
return rtn;
}
}
public: public:
CFGVisitor(AST_TYPE::AST_TYPE root_type, CFG* cfg) : root_type(root_type), cfg(cfg) { CFGVisitor(AST_TYPE::AST_TYPE root_type, CFG* cfg) : root_type(root_type), cfg(cfg) {
curblock = cfg->addBlock(); curblock = cfg->addBlock();
...@@ -201,15 +511,76 @@ class CFGVisitor : public ASTVisitor { ...@@ -201,15 +511,76 @@ class CFGVisitor : public ASTVisitor {
curblock->push_back(node); curblock->push_back(node);
} }
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_functiondef(AST_FunctionDef* node) { push_back(node); return true; } virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; }
virtual bool visit_global(AST_Global* node) { push_back(node); return true; } virtual bool visit_global(AST_Global* node) { push_back(node); return true; }
virtual bool visit_import(AST_Import* node) { push_back(node); return true; } virtual bool visit_import(AST_Import* node) { push_back(node); return true; }
virtual bool visit_pass(AST_Pass* node) { push_back(node); return true; } virtual bool visit_pass(AST_Pass* node) { push_back(node); return true; }
virtual bool visit_print(AST_Print* node) { push_back(node); return true; }
virtual bool visit_assign(AST_Assign* node) {
AST_Assign* remapped = new AST_Assign();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapExpr(node->value);
// TODO bad that it's reusing the AST nodes?
remapped->targets = node->targets;
push_back(remapped);
return true;
}
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);
// TODO bad that it's reusing the AST nodes?
remapped->target = node->target;
remapped->op_type = node->op_type;
push_back(remapped);
return true;
}
virtual bool visit_expr(AST_Expr* node) {
AST_Expr* remapped = new AST_Expr();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapExpr(node->value, false);
push_back(remapped);
return true;
}
virtual bool visit_print(AST_Print* node) {
AST_expr *dest = remapExpr(node->dest);
int i = 0;
for (auto v : node->values) {
AST_Print* remapped = new AST_Print();
// TODO not good to reuse 'dest' like this
remapped->dest = dest;
if (i < node->values.size() - 1)
remapped->nl = false;
else
remapped->nl = node->nl;
remapped->values.push_back(remapExpr(v));
push_back(remapped);
i++;
}
if (node->values.size() == 0) {
assert(node->nl);
AST_Print* final = new AST_Print();
// TODO not good to reuse 'dest' like this
final->dest = dest;
final->nl = node->nl;
push_back(final);
}
return true;
}
virtual bool visit_return(AST_Return* node) { virtual bool visit_return(AST_Return* node) {
if (root_type != AST_TYPE::FunctionDef) { if (root_type != AST_TYPE::FunctionDef) {
...@@ -217,7 +588,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -217,7 +588,7 @@ class CFGVisitor : public ASTVisitor {
exit(1); exit(1);
} }
AST_expr *value = node->value; AST_expr *value = remapExpr(node->value);
if (value == NULL) if (value == NULL)
value = makeName("None", AST_TYPE::Load); value = makeName("None", AST_TYPE::Load);
doReturn(value); doReturn(value);
...@@ -230,7 +601,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -230,7 +601,7 @@ class CFGVisitor : public ASTVisitor {
AST_Branch *br = new AST_Branch(); AST_Branch *br = new AST_Branch();
br->col_offset = node->col_offset; br->col_offset = node->col_offset;
br->lineno = node->lineno; br->lineno = node->lineno;
br->test = node->test; br->test = remapExpr(node->test);
push_back(br); push_back(br);
CFGBlock *starting_block = curblock; CFGBlock *starting_block = curblock;
...@@ -328,7 +699,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -328,7 +699,7 @@ class CFGVisitor : public ASTVisitor {
curblock->connectTo(test_block); curblock->connectTo(test_block);
curblock = test_block; curblock = test_block;
AST_Branch *br = makeBranch(node->test); AST_Branch *br = makeBranch(remapExpr(node->test));
push_back(br); push_back(br);
// We need a reference to this block early on so we can break to it, // We need a reference to this block early on so we can break to it,
...@@ -381,7 +752,8 @@ class CFGVisitor : public ASTVisitor { ...@@ -381,7 +752,8 @@ class CFGVisitor : public ASTVisitor {
// is it really worth it? It got so bad because all the edges became // is it really worth it? It got so bad because all the edges became
// critical edges and needed to be broken, otherwise it's not too different. // critical edges and needed to be broken, otherwise it's not too different.
AST_expr *iter_attr = makeLoadAttribute(node->iter, "__iter__", true); AST_expr *remapped_iter = remapExpr(node->iter);
AST_expr *iter_attr = makeLoadAttribute(remapped_iter, "__iter__", true);
AST_expr *iter_call = makeCall(iter_attr); AST_expr *iter_call = makeCall(iter_attr);
char itername_buf[80]; char itername_buf[80];
...@@ -510,7 +882,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -510,7 +882,7 @@ class CFGVisitor : public ASTVisitor {
char exitname_buf[80]; char exitname_buf[80];
snprintf(exitname_buf, 80, "#exit_%p", node); snprintf(exitname_buf, 80, "#exit_%p", node);
push_back(makeAssign(ctxmgrname_buf, node->context_expr)); push_back(makeAssign(ctxmgrname_buf, remapExpr(node->context_expr)));
AST_expr *enter = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__enter__", true); AST_expr *enter = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__enter__", true);
AST_expr *exit = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__exit__", true); AST_expr *exit = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__exit__", true);
......
...@@ -26,3 +26,5 @@ for i in xrange(-5, 4): ...@@ -26,3 +26,5 @@ for i in xrange(-5, 4):
l3 = range(5) l3 = range(5)
l3[:i] = [7, 8] l3[:i] = [7, 8]
print l3 print l3
print [1, 2, 3, 4, 5]
def f(c): t = (1, "h")
c.x = None print t, str(t), repr(t)
c.x = 1 if 1:
# return None t = (3,)
print t
class C(object):
pass def f():
print f(C()) t = (1, 3)
print t
f()
print ()
print (1,)
print (1, 2)
print (1, 2, 3)
t = 1, 3
print t
print (2,) < (2,)
print (2,) < (2, 3)
print (3,) < (2, 3)
print
...@@ -275,10 +275,6 @@ if __name__ == "__main__": ...@@ -275,10 +275,6 @@ if __name__ == "__main__":
nostat(["nondirectly_callable_ics"]) # WIP nostat(["nondirectly_callable_ics"]) # WIP
skip(["finalization_cycles", "resurrection", "nonself_resurrection"]) # WIP skip(["finalization_cycles", "resurrection", "nonself_resurrection"]) # WIP
if '-O' in EXTRA_JIT_ARGS:
# Have guard issues:
skip(["dict", "tuple_iteration"])
if datetime.datetime.now() < datetime.datetime(2014,4,28): if datetime.datetime.now() < datetime.datetime(2014,4,28):
skip(["class_noctor", "non_function_ctors"]) # object.__new__ skip(["class_noctor", "non_function_ctors"]) # object.__new__
skip(["setattr_patching_under"]) # requires __del__ skip(["setattr_patching_under"]) # requires __del__
......
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