Commit 894578a0 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix up a bunch of problems with definedness analysis

Not sure how these didn't show up before...
parent 5db2e270
...@@ -59,7 +59,7 @@ typename BBAnalyzer<T>::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer<T>& ...@@ -59,7 +59,7 @@ typename BBAnalyzer<T>::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer<T>&
CFGBlock* block = q.top(); CFGBlock* block = q.top();
q.pop(); q.pop();
Map initial = states[block]; Map& initial = states[block];
if (VERBOSITY("analysis") >= 2) if (VERBOSITY("analysis") >= 2)
printf("fpc on block %d - %ld entries\n", block->idx, initial.size()); printf("fpc on block %d - %ld entries\n", block->idx, initial.size());
......
...@@ -292,19 +292,19 @@ DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names, ...@@ -292,19 +292,19 @@ DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names,
// printf("%d %s %d\n", p.first->idx, p2.first.c_str(), p2.second); // printf("%d %s %d\n", p.first->idx, p2.first.c_str(), p2.second);
required.insert(p2.first); required.insert(p2.first);
} }
defined.insert(make_pair(p.first, required)); defined_at_end.insert(make_pair(p.first, required));
} }
} }
DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAt(const std::string& name, CFGBlock* block) { DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(const std::string& name, CFGBlock* block) {
std::unordered_map<std::string, DefinitionLevel>& map = results[block]; std::unordered_map<std::string, DefinitionLevel>& map = results[block];
if (map.count(name) == 0) if (map.count(name) == 0)
return Undefined; return Undefined;
return map[name]; return map[name];
} }
const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(CFGBlock* block) { const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEnd(CFGBlock* block) {
return defined[block]; return defined_at_end[block];
} }
PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, LivenessAnalysis* liveness, PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, LivenessAnalysis* liveness,
...@@ -313,19 +313,21 @@ PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, Livene ...@@ -313,19 +313,21 @@ PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, Livene
for (CFGBlock* block : cfg->blocks) { for (CFGBlock* block : cfg->blocks) {
RequiredSet required; RequiredSet required;
if (block->predecessors.size() < 2)
continue;
const RequiredSet& defined = definedness.getDefinedNamesAt(block); if (block->predecessors.size() > 1) {
if (defined.size()) for (CFGBlock* pred : block->predecessors) {
assert(block->predecessors.size()); const RequiredSet& defined = definedness.getDefinedNamesAtEnd(pred);
for (const auto& s : defined) { for (const auto& s : defined) {
if (liveness->isLiveAtEnd(s, block->predecessors[0])) { if (required.count(s) == 0 && liveness->isLiveAtEnd(s, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
required.insert(s); required.insert(s);
} }
} }
}
}
required_phis.insert(make_pair(block, required)); required_phis.insert(make_pair(block, std::move(required)));
} }
} }
...@@ -336,8 +338,8 @@ const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block ...@@ -336,8 +338,8 @@ const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block
return required_phis[block->successors[0]]; return required_phis[block->successors[0]];
} }
const PhiAnalysis::RequiredSet& PhiAnalysis::getAllDefinedAt(CFGBlock* block) { const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) {
return definedness.getDefinedNamesAt(block); return required_phis[block];
} }
bool PhiAnalysis::isRequired(const std::string& name, CFGBlock* block) { bool PhiAnalysis::isRequired(const std::string& name, CFGBlock* block) {
...@@ -358,11 +360,16 @@ bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) { ...@@ -358,11 +360,16 @@ bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) {
bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block) { bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block) {
assert(!startswith(name, "!")); assert(!startswith(name, "!"));
assert(block->successors.size() > 0);
DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAt(name, block->successors[0]);
ASSERT(dlevel != DefinednessAnalysis::Undefined, "%s %d", name.c_str(), block->idx);
return dlevel == DefinednessAnalysis::PotentiallyDefined; if (block->successors.size() != 1)
return false;
for (CFGBlock* pred : block->successors[0]->predecessors) {
DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAtEnd(name, pred);
if (dlevel != DefinednessAnalysis::Defined)
return true;
}
return false;
} }
LivenessAnalysis* computeLivenessInfo(CFG*) { LivenessAnalysis* computeLivenessInfo(CFG*) {
......
...@@ -49,14 +49,14 @@ public: ...@@ -49,14 +49,14 @@ public:
private: private:
std::unordered_map<CFGBlock*, std::unordered_map<std::string, DefinitionLevel> > results; std::unordered_map<CFGBlock*, std::unordered_map<std::string, DefinitionLevel> > results;
std::unordered_map<CFGBlock*, const RequiredSet> defined; std::unordered_map<CFGBlock*, const RequiredSet> defined_at_end;
ScopeInfo* scope_info; ScopeInfo* scope_info;
public: public:
DefinednessAnalysis(const SourceInfo::ArgNames& args, CFG* cfg, ScopeInfo* scope_info); DefinednessAnalysis(const SourceInfo::ArgNames& args, CFG* cfg, ScopeInfo* scope_info);
DefinitionLevel isDefinedAt(const std::string& name, CFGBlock* block); DefinitionLevel isDefinedAtEnd(const std::string& name, CFGBlock* block);
const RequiredSet& getDefinedNamesAt(CFGBlock* block); const RequiredSet& getDefinedNamesAtEnd(CFGBlock* block);
}; };
class PhiAnalysis { class PhiAnalysis {
public: public:
...@@ -73,7 +73,7 @@ public: ...@@ -73,7 +73,7 @@ public:
bool isRequired(const std::string& name, CFGBlock* block); bool isRequired(const std::string& name, CFGBlock* block);
bool isRequiredAfter(const std::string& name, CFGBlock* block); bool isRequiredAfter(const std::string& name, CFGBlock* block);
const RequiredSet& getAllRequiredAfter(CFGBlock* block); const RequiredSet& getAllRequiredAfter(CFGBlock* block);
const RequiredSet& getAllDefinedAt(CFGBlock* block); const RequiredSet& getAllRequiredFor(CFGBlock* block);
bool isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block); bool isPotentiallyUndefinedAfter(const std::string& name, CFGBlock* block);
}; };
......
...@@ -1195,6 +1195,10 @@ public: ...@@ -1195,6 +1195,10 @@ public:
virtual ConcreteCompilerType* getConcreteType() { return this; } virtual ConcreteCompilerType* getConcreteType() { return this; }
// Shouldn't call this: // Shouldn't call this:
virtual ConcreteCompilerType* getBoxType() { RELEASE_ASSERT(0, ""); } virtual ConcreteCompilerType* getBoxType() { RELEASE_ASSERT(0, ""); }
void drop(IREmitter& emitter, VAR* var) override {}
void grab(IREmitter& emitter, VAR* var) override {}
} _CLOSURE; } _CLOSURE;
ConcreteCompilerType* CLOSURE = &_CLOSURE; ConcreteCompilerType* CLOSURE = &_CLOSURE;
...@@ -1263,6 +1267,8 @@ public: ...@@ -1263,6 +1267,8 @@ public:
if (rtn == NULL) { if (rtn == NULL) {
rtn = new VAR(this, var->getValue(), var->isGrabbed()); rtn = new VAR(this, var->getValue(), var->isGrabbed());
while (rtn->getVrefs() < var->getVrefs())
rtn->incvref();
} }
return rtn; return rtn;
} }
......
...@@ -604,12 +604,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua ...@@ -604,12 +604,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
into_hax.insert(b2); into_hax.insert(b2);
} }
const PhiAnalysis::RequiredSet& names = source->phis->getAllDefinedAt(block); const PhiAnalysis::RequiredSet& names = source->phis->getAllRequiredFor(block);
for (const auto& s : names) { for (const auto& s : names) {
// TODO the list from getAllDefinedAt should come filtered:
if (!source->liveness->isLiveAtEnd(s, block->predecessors[0]))
continue;
// printf("adding guessed phi for %s\n", s.c_str()); // printf("adding guessed phi for %s\n", s.c_str());
ConcreteCompilerType* type = types->getTypeAtBlockStart(s, block); ConcreteCompilerType* type = types->getTypeAtBlockStart(s, block);
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s); llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s);
......
...@@ -731,7 +731,7 @@ private: ...@@ -731,7 +731,7 @@ private:
std::vector<CompilerVariable*> args; std::vector<CompilerVariable*> args;
args.push_back(key); args.push_back(key);
args.push_back(value); args.push_back(value);
// TODO could use the internal _listAppend function to avoid incref/decref'ing None // TODO should use callattr
CompilerVariable* rtn = setitem->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(2), args, NULL); CompilerVariable* rtn = setitem->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(2), args, NULL);
rtn->decvref(emitter); rtn->decvref(emitter);
...@@ -1245,30 +1245,29 @@ private: ...@@ -1245,30 +1245,29 @@ private:
snprintf(buf, 40, "!%s_%s", prefix, token); snprintf(buf, 40, "!%s_%s", prefix, token);
return std::string(buf); return std::string(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];
assert(cur == NULL); assert(cur == NULL);
cur = val; cur = val;
} }
CompilerVariable* _clearFake(std::string name) {
assert(name[0] == '!');
CompilerVariable* rtn = symbol_table[name];
assert(rtn == NULL);
symbol_table.erase(name);
return rtn;
}
CompilerVariable* _getFake(std::string name, bool allow_missing = false) { CompilerVariable* _getFake(std::string name, bool allow_missing = false) {
assert(name[0] == '!'); assert(name[0] == '!');
CompilerVariable* rtn = symbol_table[name]; auto it = symbol_table.find(name);
if (!allow_missing) if (it == symbol_table.end()) {
assert(rtn != NULL); assert(allow_missing);
return rtn; return NULL;
} }
return it->second;
}
CompilerVariable* _popFake(std::string name, bool allow_missing = false) { CompilerVariable* _popFake(std::string name, bool allow_missing = false) {
CompilerVariable* rtn = _getFake(name, allow_missing); CompilerVariable* rtn = _getFake(name, allow_missing);
symbol_table.erase(name); symbol_table.erase(name);
if (!allow_missing)
assert(rtn != NULL);
return rtn; return rtn;
} }
...@@ -1670,6 +1669,11 @@ private: ...@@ -1670,6 +1669,11 @@ private:
rtn->ensureGrabbed(emitter); rtn->ensureGrabbed(emitter);
val->decvref(emitter); val->decvref(emitter);
for (auto& p : symbol_table) {
p.second->decvref(emitter);
}
symbol_table.clear();
endBlock(DEAD); endBlock(DEAD);
ASSERT(rtn->getVrefs() == 1, "%d", rtn->getVrefs()); ASSERT(rtn->getVrefs() == 1, "%d", rtn->getVrefs());
...@@ -1747,18 +1751,6 @@ private: ...@@ -1747,18 +1751,6 @@ private:
std::vector<ConcreteCompilerVariable*> converted_args; std::vector<ConcreteCompilerVariable*> converted_args;
SortedSymbolTable sorted_symbol_table(symbol_table.begin(), symbol_table.end()); SortedSymbolTable sorted_symbol_table(symbol_table.begin(), symbol_table.end());
/*
for (SortedSymbolTable::iterator it = sorted_symbol_table.begin(), end = sorted_symbol_table.end(); it != end; )
{
if (!source->liveness->isLiveAtEnd(it->first, myblock)) {
// I think this line can never get hit: nothing can die on a backedge, since control flow can eventually
// reach this block again, where the symbol was live (as shown by it being in the symbol table)
printf("Not sending %s to osr since it will die\n", it->first.c_str());
it = sorted_symbol_table.erase(it);
} else {
++it;
}
}*/
// For OSR calls, we use the same calling convention as in some other places; namely, // For OSR calls, we use the same calling convention as in some other places; namely,
// arg1, arg2, arg3, argarray [nargs is ommitted] // arg1, arg2, arg3, argarray [nargs is ommitted]
...@@ -1792,11 +1784,6 @@ private: ...@@ -1792,11 +1784,6 @@ private:
int arg_num = -1; int arg_num = -1;
for (const auto& p : sorted_symbol_table) { for (const auto& p : sorted_symbol_table) {
arg_num++; arg_num++;
// I don't think this can fail, but if it can we should filter out dead symbols before
// passing them on:
ASSERT(startswith(p.first, "!is_defined")
|| irstate->getSourceInfo()->liveness->isLiveAtEnd(p.first, myblock),
"%d %s", myblock->idx, p.first.c_str());
// This line can never get hit right now since we unnecessarily force every variable to be concrete // This line can never get hit right now since we unnecessarily force every variable to be concrete
// for a loop, since we generate all potential phis: // for a loop, since we generate all potential phis:
...@@ -1828,6 +1815,12 @@ private: ...@@ -1828,6 +1815,12 @@ private:
} else if (var->getType() == FLOAT) { } else if (var->getType() == FLOAT) {
// val = emitter.getBuilder()->CreateBitCast(val, g.llvm_value_type_ptr); // val = emitter.getBuilder()->CreateBitCast(val, g.llvm_value_type_ptr);
ptr = emitter.getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo()); ptr = emitter.getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo());
} else if (var->getType() == UNDEF) {
// TODO if there are any undef variables, we're in 'unreachable' territory.
// Do we even need to generate any of this code?
// Currently we represent 'undef's as 'i16 undef'
val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr);
} else { } else {
assert(val->getType() == g.llvm_value_type_ptr); assert(val->getType() == g.llvm_value_type_ptr);
} }
...@@ -2040,11 +2033,14 @@ private: ...@@ -2040,11 +2033,14 @@ private:
++it; ++it;
} else { } else {
#ifndef NDEBUG #ifndef NDEBUG
// TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't want here, if (myblock->successors.size()) {
// but this is just for debugging so I guess let it happen for now: // TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't want
// here, but this is just for debugging so I guess let it happen for now:
ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock); ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock);
ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s", ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s",
it->first.c_str(), ending_type->debugName().c_str(), it->second->getType()->debugName().c_str()); it->first.c_str(), ending_type->debugName().c_str(),
it->second->getType()->debugName().c_str());
}
#endif #endif
++it; ++it;
...@@ -2099,19 +2095,14 @@ public: ...@@ -2099,19 +2095,14 @@ public:
SymbolTable* st = new SymbolTable(symbol_table); SymbolTable* st = new SymbolTable(symbol_table);
ConcreteSymbolTable* phi_st = new ConcreteSymbolTable(); ConcreteSymbolTable* phi_st = new ConcreteSymbolTable();
for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) {
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());
} else {
ASSERT(source->liveness->isLiveAtEnd(it->first, myblock), "%s", it->first.c_str());
}
}
if (myblock->successors.size() == 0) { if (myblock->successors.size() == 0) {
st->erase(CREATED_CLOSURE_NAME); for (auto& p : *st) {
st->erase(PASSED_CLOSURE_NAME); p.second->decvref(emitter);
assert(st->size() == 0); // shouldn't have anything live if there are no successors! }
st->clear();
symbol_table.clear();
return EndingState(st, phi_st, curblock); return EndingState(st, phi_st, curblock);
} else if (myblock->successors.size() > 1) { } else if (myblock->successors.size() > 1) {
// Since there are no critical edges, all successors come directly from this node, // Since there are no critical edges, all successors come directly from this node,
......
...@@ -379,6 +379,8 @@ private: ...@@ -379,6 +379,8 @@ private:
AST_expr* remapAttribute(AST_Attribute* node) { AST_expr* remapAttribute(AST_Attribute* node) {
AST_Attribute* rtn = new AST_Attribute(); AST_Attribute* rtn = new AST_Attribute();
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
rtn->ctx_type = node->ctx_type; rtn->ctx_type = node->ctx_type;
rtn->attr = node->attr; rtn->attr = node->attr;
rtn->value = remapExpr(node->value); rtn->value = remapExpr(node->value);
...@@ -483,6 +485,8 @@ private: ...@@ -483,6 +485,8 @@ private:
AST_expr* remapClsAttribute(AST_ClsAttribute* node) { AST_expr* remapClsAttribute(AST_ClsAttribute* node) {
AST_ClsAttribute* rtn = new AST_ClsAttribute(); AST_ClsAttribute* rtn = new AST_ClsAttribute();
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
rtn->attr = node->attr; rtn->attr = node->attr;
rtn->value = remapExpr(node->value); rtn->value = remapExpr(node->value);
return rtn; return rtn;
......
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