Commit 45fc5847 authored by Marius Wachtler's avatar Marius Wachtler

Merge branch 'master' of https://github.com/dropbox/pyston into generators

Conflicts:
	src/codegen/irgen/irgenerator.cpp
	src/codegen/runtime_hooks.h
parents bc512baf 07af2757
...@@ -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());
......
...@@ -95,6 +95,9 @@ public: ...@@ -95,6 +95,9 @@ public:
}; };
bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) { bool LivenessAnalysis::isLiveAtEnd(const std::string& name, CFGBlock* block) {
if (name[0] != '#')
return true;
if (block->successors.size() == 0) if (block->successors.size() == 0)
return false; return false;
...@@ -292,19 +295,19 @@ DefinednessAnalysis::DefinednessAnalysis(const SourceInfo::ArgNames& arg_names, ...@@ -292,19 +295,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 +316,21 @@ PhiAnalysis::PhiAnalysis(const SourceInfo::ArgNames& arg_names, CFG* cfg, Livene ...@@ -313,19 +316,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)) {
required.insert(s); // printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
required.insert(s);
}
}
} }
} }
required_phis.insert(make_pair(block, required)); required_phis.insert(make_pair(block, std::move(required)));
} }
} }
...@@ -336,8 +341,8 @@ const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block ...@@ -336,8 +341,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 +363,16 @@ bool PhiAnalysis::isRequiredAfter(const std::string& name, CFGBlock* block) { ...@@ -358,11 +363,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);
}; };
......
...@@ -61,6 +61,8 @@ public: ...@@ -61,6 +61,8 @@ public:
virtual bool takesClosure() { return false; } virtual bool takesClosure() { return false; }
bool passesThroughClosure() override { return false; }
virtual bool refersToGlobal(const std::string& name) { virtual bool refersToGlobal(const std::string& name) {
if (isCompilerCreatedName(name)) if (isCompilerCreatedName(name))
return false; return false;
...@@ -88,6 +90,7 @@ struct ScopingAnalysis::ScopeNameUsage { ...@@ -88,6 +90,7 @@ struct ScopingAnalysis::ScopeNameUsage {
// Properties determined by looking at other scopes as well: // Properties determined by looking at other scopes as well:
StrSet referenced_from_nested; StrSet referenced_from_nested;
StrSet got_from_closure; StrSet got_from_closure;
StrSet passthrough_accesses; // what names a child scope accesses a name from a parent scope
ScopeNameUsage(AST* node, ScopeNameUsage* parent) : node(node), parent(parent) { ScopeNameUsage(AST* node, ScopeNameUsage* parent) : node(node), parent(parent) {
if (node->type == AST_TYPE::ClassDef) { if (node->type == AST_TYPE::ClassDef) {
...@@ -123,7 +126,9 @@ public: ...@@ -123,7 +126,9 @@ public:
virtual bool createsClosure() { return usage->referenced_from_nested.size() > 0; } virtual bool createsClosure() { return usage->referenced_from_nested.size() > 0; }
virtual bool takesClosure() { return usage->got_from_closure.size() > 0; } virtual bool takesClosure() { return usage->got_from_closure.size() > 0 || usage->passthrough_accesses.size() > 0; }
bool passesThroughClosure() override { return usage->passthrough_accesses.size() > 0 && !createsClosure(); }
virtual bool refersToGlobal(const std::string& name) { virtual bool refersToGlobal(const std::string& name) {
// HAX // HAX
...@@ -235,6 +240,13 @@ public: ...@@ -235,6 +240,13 @@ public:
virtual bool visit_jump(AST_Jump* node) { return false; } virtual bool visit_jump(AST_Jump* node) { return false; }
virtual bool visit_delete(AST_Delete* node) {
for (auto t : node->targets) {
RELEASE_ASSERT(t->type != AST_TYPE::Name, "");
}
return false;
}
virtual bool visit_global(AST_Global* node) { virtual bool visit_global(AST_Global* node) {
for (int i = 0; i < node->names.size(); i++) { for (int i = 0; i < node->names.size(); i++) {
const std::string& name = node->names[i]; const std::string& name = node->names[i];
...@@ -364,6 +376,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { ...@@ -364,6 +376,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
ScopeNameUsage* parent = usage->parent; ScopeNameUsage* parent = usage->parent;
while (parent) { while (parent) {
if (parent->node->type == AST_TYPE::ClassDef) { if (parent->node->type == AST_TYPE::ClassDef) {
intermediate_parents.push_back(parent);
parent = parent->parent; parent = parent->parent;
} else if (parent->forced_globals.count(name)) { } else if (parent->forced_globals.count(name)) {
break; break;
...@@ -372,8 +385,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { ...@@ -372,8 +385,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
parent->referenced_from_nested.insert(name); parent->referenced_from_nested.insert(name);
for (ScopeNameUsage* iparent : intermediate_parents) { for (ScopeNameUsage* iparent : intermediate_parents) {
iparent->referenced_from_nested.insert(name); iparent->passthrough_accesses.insert(name);
iparent->got_from_closure.insert(name);
} }
break; break;
......
...@@ -30,6 +30,7 @@ public: ...@@ -30,6 +30,7 @@ public:
virtual bool createsClosure() = 0; virtual bool createsClosure() = 0;
virtual bool takesClosure() = 0; virtual bool takesClosure() = 0;
virtual bool passesThroughClosure() = 0;
virtual bool takesGenerator() { return isGeneratorValue; } virtual bool takesGenerator() { return isGeneratorValue; }
virtual void setTakesGenerator(bool b = true) { isGeneratorValue = b; } virtual void setTakesGenerator(bool b = true) { isGeneratorValue = b; }
......
...@@ -359,6 +359,8 @@ private: ...@@ -359,6 +359,8 @@ private:
return BOOL; return BOOL;
case AST_LangPrimitive::LANDINGPAD: case AST_LangPrimitive::LANDINGPAD:
return UNKNOWN; return UNKNOWN;
case AST_LangPrimitive::LOCALS:
return DICT;
default: default:
RELEASE_ASSERT(0, "%d", node->opcode); RELEASE_ASSERT(0, "%d", node->opcode);
} }
...@@ -384,6 +386,10 @@ private: ...@@ -384,6 +386,10 @@ private:
return UNKNOWN; return UNKNOWN;
} }
if (scope_info->refersToClosure(node->id)) {
return UNKNOWN;
}
CompilerType*& t = sym_table[node->id]; CompilerType*& t = sym_table[node->id];
if (t == NULL) { if (t == NULL) {
// if (VERBOSITY() >= 2) { // if (VERBOSITY() >= 2) {
......
...@@ -288,6 +288,55 @@ public: ...@@ -288,6 +288,55 @@ public:
converted_slice->decvref(emitter); converted_slice->decvref(emitter);
return new ConcreteCompilerVariable(UNKNOWN, rtn, true); return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && !info.isInterpreted();
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} 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;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp
= patchpoints::createBinexpPatchpoint(emitter.currentFunction(), info.getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(var->getValue());
llvm_args.push_back(converted_rhs->getValue());
llvm_args.push_back(getConstantInt(op_type, g.i32));
llvm::Value* uncasted
= emitter.createPatchpoint(pp, rt_func_addr, llvm_args, info.exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(info.exc_info, rt_func, var->getValue(), converted_rhs->getValue(),
getConstantInt(op_type, g.i32)).getInstruction();
}
converted_rhs->decvref(emitter);
if (op_type == AST_TYPE::In || op_type == AST_TYPE::NotIn || op_type == AST_TYPE::Is
|| op_type == AST_TYPE::IsNot) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, rtn);
ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(BOOL, unboxed, true);
return rtn;
}
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
}; };
ConcreteCompilerType* UNKNOWN = new UnknownType(); ConcreteCompilerType* UNKNOWN = new UnknownType();
...@@ -564,6 +613,7 @@ public: ...@@ -564,6 +613,7 @@ public:
struct Sig { struct Sig {
std::vector<ConcreteCompilerType*> arg_types; std::vector<ConcreteCompilerType*> arg_types;
CompilerType* rtn_type; CompilerType* rtn_type;
int ndefaults;
}; };
private: private:
...@@ -589,11 +639,11 @@ public: ...@@ -589,11 +639,11 @@ public:
for (int i = 0; i < sigs.size(); i++) { for (int i = 0; i < sigs.size(); i++) {
Sig* sig = sigs[i]; Sig* sig = sigs[i];
if (sig->arg_types.size() != arg_types.size()) if (arg_types.size() < sig->arg_types.size() - sig->ndefaults || arg_types.size() > sig->arg_types.size())
continue; continue;
bool works = true; bool works = true;
for (int j = 0; j < sig->arg_types.size(); j++) { for (int j = 0; j < arg_types.size(); j++) {
if (!arg_types[j]->canConvertTo(sig->arg_types[j])) { if (!arg_types[j]->canConvertTo(sig->arg_types[j])) {
works = false; works = false;
break; break;
...@@ -621,6 +671,7 @@ public: ...@@ -621,6 +671,7 @@ public:
Sig* type_sig = new Sig(); Sig* type_sig = new Sig();
type_sig->rtn_type = fspec->rtn_type; type_sig->rtn_type = fspec->rtn_type;
type_sig->ndefaults = clf->num_defaults;
if (stripfirst) { if (stripfirst) {
assert(fspec->arg_types.size() >= 1); assert(fspec->arg_types.size() >= 1);
...@@ -637,14 +688,6 @@ public: ...@@ -637,14 +688,6 @@ public:
static CompilerType* get(const std::vector<Sig*>& sigs) { return new AbstractFunctionType(sigs); } static CompilerType* get(const std::vector<Sig*>& sigs) { return new AbstractFunctionType(sigs); }
}; };
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() {}
...@@ -755,6 +798,95 @@ public: ...@@ -755,6 +798,95 @@ public:
return new ConcreteCompilerVariable(BOOL, cmp, true); return new ConcreteCompilerVariable(BOOL, cmp, true);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* v;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_i64_i64, var->getValue(), converted_right->getValue())
.getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_INT; } virtual ConcreteCompilerType* getBoxType() { return BOXED_INT; }
} _INT; } _INT;
ConcreteCompilerType* INT = &_INT; ConcreteCompilerType* INT = &_INT;
...@@ -849,6 +981,110 @@ public: ...@@ -849,6 +981,110 @@ public:
llvm::Value* cmp = emitter.getBuilder()->CreateFCmpUNE(var->getValue(), llvm::ConstantFP::get(g.double_, 0)); llvm::Value* cmp = emitter.getBuilder()->CreateFCmpUNE(var->getValue(), llvm::ConstantFP::get(g.double_, 0));
return new ConcreteCompilerVariable(BOOL, cmp, true); return new ConcreteCompilerVariable(BOOL, cmp, true);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
if (rhs->getType() != INT && rhs->getType() != FLOAT) {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* converted_right;
if (rhs->getType() == FLOAT) {
converted_right = rhs->makeConverted(emitter, FLOAT);
} else {
converted_right = rhs->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (op_type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
if (succeeded) {
v = emitter.getBuilder()->CreateBinOp(binopcode, var->getValue(), converted_right->getValue());
}
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (op_type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::FCMP_OEQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::FCMP_OLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::FCMP_OLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::FCMP_OGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::FCMP_OGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(op_type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateFCmp(cmp_pred, var->getValue(), converted_right->getValue());
}
converted_right->decvref(emitter);
if (succeeded) {
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
}
// TODO duplication with top of function, other functions, etc
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_FLOAT; } virtual ConcreteCompilerType* getBoxType() { return BOXED_FLOAT; }
} _FLOAT; } _FLOAT;
ConcreteCompilerType* FLOAT = &_FLOAT; ConcreteCompilerType* FLOAT = &_FLOAT;
...@@ -1022,19 +1258,20 @@ public: ...@@ -1022,19 +1258,20 @@ public:
if (rtattr->cls != function_cls) if (rtattr->cls != function_cls)
return NULL; return NULL;
BoxedFunction* rtattr_func = static_cast<BoxedFunction*>(rtattr);
RELEASE_ASSERT(!argspec.has_starargs, ""); RELEASE_ASSERT(!argspec.has_starargs, "");
RELEASE_ASSERT(!argspec.has_kwargs, ""); RELEASE_ASSERT(!argspec.has_kwargs, "");
RELEASE_ASSERT(argspec.num_keywords == 0, ""); RELEASE_ASSERT(argspec.num_keywords == 0, "");
CLFunction* cl = unboxRTFunction(rtattr); CLFunction* cl = rtattr_func->f;
assert(cl); assert(cl);
if (cl->num_defaults || cl->takes_varargs || cl->takes_kwargs) if (cl->takes_varargs || cl->takes_kwargs)
return NULL; return NULL;
RELEASE_ASSERT(cl->num_args == cl->numReceivedArgs(), ""); RELEASE_ASSERT(cl->num_args == cl->numReceivedArgs(), "");
RELEASE_ASSERT(cl->num_args == args.size() + 1, ""); RELEASE_ASSERT(args.size() + 1 >= cl->num_args - cl->num_defaults && args.size() + 1 <= cl->num_args, "");
CompiledFunction* cf = NULL; CompiledFunction* cf = NULL;
bool found = false; bool found = false;
...@@ -1044,13 +1281,8 @@ public: ...@@ -1044,13 +1281,8 @@ public:
assert(cf->spec->arg_types.size() == cl->numReceivedArgs()); assert(cf->spec->arg_types.size() == cl->numReceivedArgs());
bool fits = true; bool fits = true;
for (int j = 1; j < cl->num_args; j++) { for (int j = 0; j < args.size(); j++) {
// if (cf->sig->arg_types[j] != UNKNOWN) { if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) {
// if (cf->sig->arg_types[j]->isFitBy(args[j-1]->guaranteedClass())) {
if (!args[j - 1]->canConvertTo(cf->spec->arg_types[j])) {
// printf("Can't use version %d since arg %d (%s) doesn't fit into spec arg of %s\n", i, j,
// args[j - 1]->getType()->debugName().c_str(),
// cf->spec->arg_types[j]->debugName().c_str());
fits = false; fits = false;
break; break;
} }
...@@ -1086,6 +1318,13 @@ public: ...@@ -1086,6 +1318,13 @@ public:
new_args.push_back(var); new_args.push_back(var);
new_args.insert(new_args.end(), args.begin(), args.end()); new_args.insert(new_args.end(), args.begin(), args.end());
for (int i = args.size() + 1; i < cl->num_args; i++) {
// TODO should _call() be able to take llvm::Value's directly?
new_args.push_back(new ConcreteCompilerVariable(
UNKNOWN, embedConstantPtr(rtattr_func->defaults->elts[i - args.size() - 1], g.llvm_value_type_ptr),
true));
}
std::vector<llvm::Value*> other_args; std::vector<llvm::Value*> other_args;
ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->code, other_args, argspec, new_args, ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->code, other_args, argspec, new_args,
...@@ -1128,6 +1367,31 @@ public: ...@@ -1128,6 +1367,31 @@ public:
return rtn; return rtn;
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
BoxedClass* rhs_cls = converted_rhs->guaranteedClass();
if (rhs_cls && rhs_cls->is_constant && !rhs_cls->is_user_defined) {
// Ugly, but for now special-case the set of type-pairs that we know will always work
if (exp_type == BinOp
&& ((cls == int_cls && rhs_cls == int_cls) || (cls == float_cls && rhs_cls == float_cls)
|| (cls == list_cls && rhs_cls == int_cls))) {
const std::string& left_side_name = getOpName(op_type);
ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, &left_side_name, true, ArgPassSpec(1, 0, 0, 0), { converted_rhs }, NULL, false);
if (called_constant)
return called_constant;
}
}
auto rtn = UNKNOWN->binexp(emitter, info, var, converted_rhs, op_type, exp_type);
converted_rhs->decvref(emitter);
return rtn;
}
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) { virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) {
static const std::string attr("__getitem__"); static const std::string attr("__getitem__");
ConcreteCompilerVariable* called_constant ConcreteCompilerVariable* called_constant
...@@ -1201,6 +1465,10 @@ public: ...@@ -1201,6 +1465,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;
...@@ -1277,6 +1545,14 @@ public: ...@@ -1277,6 +1545,14 @@ public:
return rtn; return rtn;
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) override { ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) override {
return makeBool(var->getValue()->size() != 0); return makeBool(var->getValue()->size() != 0);
} }
...@@ -1286,6 +1562,8 @@ public: ...@@ -1286,6 +1562,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;
} }
...@@ -1357,6 +1635,14 @@ public: ...@@ -1357,6 +1635,14 @@ public:
return rtn; return rtn;
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual ConcreteCompilerType* getBoxType() { return BOXED_BOOL; } virtual ConcreteCompilerType* getBoxType() { return BOXED_BOOL; }
}; };
ConcreteCompilerType* BOOL = new BoolType(); ConcreteCompilerType* BOOL = new BoolType();
...@@ -1499,6 +1785,14 @@ public: ...@@ -1499,6 +1785,14 @@ public:
return BOXED_TUPLE->getattrType(attr, cls_only); return BOXED_TUPLE->getattrType(attr, cls_only);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->binexp(emitter, info, rhs, op_type, exp_type);
converted->decvref(emitter);
return rtn;
}
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, bool clsonly, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) { const std::vector<const std::string*>* keyword_names) {
...@@ -1575,6 +1869,11 @@ public: ...@@ -1575,6 +1869,11 @@ public:
return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true); return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
return undefVariable();
}
virtual ConcreteCompilerType* getBoxType() { return UNKNOWN; } virtual ConcreteCompilerType* getBoxType() { return UNKNOWN; }
virtual ConcreteCompilerType* getConcreteType() { return this; } virtual ConcreteCompilerType* getConcreteType() { return this; }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "core/ast.h"
#include "core/types.h" #include "core/types.h"
namespace pyston { namespace pyston {
...@@ -47,6 +48,12 @@ public: ...@@ -47,6 +48,12 @@ public:
typedef std::unordered_map<CompilerVariable*, CompilerVariable*> DupCache; typedef std::unordered_map<CompilerVariable*, CompilerVariable*> DupCache;
enum BinExpType {
AugBinOp,
BinOp,
Compare,
};
template <class V> class _ValuedCompilerType : public CompilerType { template <class V> class _ValuedCompilerType : public CompilerType {
public: public:
typedef ValuedCompilerVariable<V> VAR; typedef ValuedCompilerVariable<V> VAR;
...@@ -63,11 +70,11 @@ public: ...@@ -63,11 +70,11 @@ public:
printf("getBoxType not defined for %s\n", debugName().c_str()); printf("getBoxType not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual void drop(IREmitter& emmitter, VAR* value) { virtual void drop(IREmitter& emmitter, VAR* var) {
printf("drop not defined for %s\n", debugName().c_str()); printf("drop not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual void grab(IREmitter& emmitter, VAR* value) { virtual void grab(IREmitter& emmitter, VAR* var) {
printf("grab not defined for %s\n", debugName().c_str()); printf("grab not defined for %s\n", debugName().c_str());
abort(); abort();
} }
...@@ -75,53 +82,58 @@ public: ...@@ -75,53 +82,58 @@ public:
printf("canConvertTo not defined for %s\n", debugName().c_str()); printf("canConvertTo not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* value, ConcreteCompilerType* other_type) { virtual ConcreteCompilerVariable* makeConverted(IREmitter& emitter, VAR* var, ConcreteCompilerType* other_type) {
printf("makeConverted not defined for %s\n", debugName().c_str()); printf("makeConverted not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* value) { virtual ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("nonzero not defined for %s\n", debugName().c_str()); printf("nonzero not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr, virtual CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool cls_only) { bool cls_only) {
printf("getattr not defined for %s\n", debugName().c_str()); printf("getattr not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr, virtual void setattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
CompilerVariable* v) { CompilerVariable* v) {
printf("setattr not defined for %s\n", debugName().c_str()); printf("setattr not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* value, const std::string* attr, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
bool clsonly, struct ArgPassSpec argspec, bool clsonly, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) { const std::vector<const std::string*>* keyword_names) {
printf("callattr not defined for %s\n", debugName().c_str()); printf("callattr not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* value, struct ArgPassSpec argspec, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, VAR* var, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) { const std::vector<const std::string*>* keyword_names) {
printf("call not defined for %s\n", debugName().c_str()); printf("call not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual void print(IREmitter& emitter, const OpInfo& info, VAR* value) { virtual void print(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("print not defined for %s\n", debugName().c_str()); printf("print not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* value) { virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* var) {
printf("len not defined for %s\n", debugName().c_str()); printf("len not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* value, CompilerVariable* v) { virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* v) {
// Can almost do this, except for error messages + types: // Can almost do this, except for error messages + types:
// static const std::string attr("__getitem__"); // static const std::string attr("__getitem__");
// return callattr(emitter, info, value, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL); // return callattr(emitter, info, var, &attr, true, ArgPassSpec(1, 0, 0, 0), {v}, NULL);
printf("getitem not defined for %s\n", debugName().c_str()); printf("getitem not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* value, BoxedClass* c) { virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) {
printf("binexp not defined for %s\n", debugName().c_str());
abort();
}
virtual llvm::Value* makeClassCheck(IREmitter& emitter, VAR* var, BoxedClass* c) {
printf("makeClassCheck not defined for %s\n", debugName().c_str()); printf("makeClassCheck not defined for %s\n", debugName().c_str());
abort(); abort();
} }
...@@ -189,7 +201,7 @@ public: ...@@ -189,7 +201,7 @@ public:
} }
} }
void decvref(IREmitter& emitter) { void decvref(IREmitter& emitter) {
assert(vrefs > 0 && vrefs < (1 << 20)); ASSERT(vrefs > 0 && vrefs < (1 << 20), "%d", vrefs);
// ASSERT(vrefs, "%s", getType()->debugName().c_str()); // ASSERT(vrefs, "%s", getType()->debugName().c_str());
vrefs--; vrefs--;
if (vrefs == 0) { if (vrefs == 0) {
...@@ -229,6 +241,8 @@ public: ...@@ -229,6 +241,8 @@ public:
virtual void print(IREmitter& emitter, const OpInfo& info) = 0; virtual void print(IREmitter& emitter, const OpInfo& info) = 0;
virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) = 0; virtual ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0; virtual CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable*) = 0;
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) = 0;
}; };
template <class V> class ValuedCompilerVariable : public CompilerVariable { template <class V> class ValuedCompilerVariable : public CompilerVariable {
...@@ -299,6 +313,12 @@ public: ...@@ -299,6 +313,12 @@ public:
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable* slice) override { CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, CompilerVariable* slice) override {
return type->getitem(emitter, info, this, slice); return type->getitem(emitter, info, this, slice);
} }
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, AST_TYPE::AST_TYPE op_type,
BinExpType exp_type) override {
return type->binexp(emitter, info, this, rhs, op_type, exp_type);
}
llvm::Value* makeClassCheck(IREmitter& emitter, BoxedClass* cls) override { llvm::Value* makeClassCheck(IREmitter& emitter, BoxedClass* cls) override {
return type->makeClassCheck(emitter, this, cls); return type->makeClassCheck(emitter, this, cls);
} }
......
...@@ -337,13 +337,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua ...@@ -337,13 +337,18 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
arg_num++; arg_num++;
if (arg_num < 3) { if (arg_num < 3) {
from_arg = func_args[arg_num]; from_arg = func_args[arg_num];
assert(from_arg->getType() == p.second->llvmType());
} else { } else {
ASSERT(func_args.size() == 4, "%ld", func_args.size()); ASSERT(func_args.size() == 4, "%ld", func_args.size());
llvm::Value* ptr = entry_emitter->getBuilder()->CreateConstGEP1_32(func_args[3], arg_num - 3); llvm::Value* ptr = entry_emitter->getBuilder()->CreateConstGEP1_32(func_args[3], arg_num - 3);
if (p.second == INT) { if (p.second == INT) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.i64->getPointerTo()); ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.i64->getPointerTo());
} else if (p.second == BOOL) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.i1->getPointerTo());
} else if (p.second == FLOAT) { } else if (p.second == FLOAT) {
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo()); ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo());
} else {
assert(p.second->llvmType() == g.llvm_value_type_ptr);
} }
from_arg = entry_emitter->getBuilder()->CreateLoad(ptr); from_arg = entry_emitter->getBuilder()->CreateLoad(ptr);
assert(from_arg->getType() == p.second->llvmType()); assert(from_arg->getType() == p.second->llvmType());
...@@ -599,12 +604,8 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua ...@@ -599,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);
......
...@@ -33,13 +33,6 @@ ...@@ -33,13 +33,6 @@
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
extern "C" {
// Hack: we only need RTTI for a single type (Box*), which we know will get emmitted,
// so just use the mangled name directly instead of using typeid() since that requires
// turning on RTTI for *everything* (including llvm)
extern void* _ZTIPN6pyston3BoxE;
}
namespace pyston { namespace pyston {
llvm::Value* IRGenState::getScratchSpace(int min_bytes) { llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
...@@ -353,244 +346,66 @@ private: ...@@ -353,244 +346,66 @@ private:
} }
return new ConcreteCompilerVariable(UNKNOWN, exc_obj, true); return new ConcreteCompilerVariable(UNKNOWN, exc_obj, true);
} }
default: case AST_LangPrimitive::LOCALS: {
RELEASE_ASSERT(0, "%d", node->opcode); assert(node->args.size() == 0);
}
}
enum BinExpType { llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createDict);
AugBinOp, ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(DICT, v, true);
BinOp,
Compare,
};
CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type,
BinExpType exp_type, ExcInfo exc_info) {
assert(state != PARTIAL);
assert(left);
assert(right);
if (left->getType() == INT && right->getType() == INT) { for (auto& p : symbol_table) {
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, INT); if (p.first[0] == '!')
ConcreteCompilerVariable* converted_right = right->makeConverted(emitter, INT); continue;
llvm::Value* v;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_i64_i64, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::Add;
break;
case AST_TYPE::BitAnd:
binopcode = llvm::Instruction::And;
break;
case AST_TYPE::BitOr:
binopcode = llvm::Instruction::Or;
break;
case AST_TYPE::BitXor:
binopcode = llvm::Instruction::Xor;
break;
case AST_TYPE::LShift:
binopcode = llvm::Instruction::Shl;
break;
case AST_TYPE::RShift:
binopcode = llvm::Instruction::AShr;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::Mul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::Sub;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(),
converted_right->getValue());
} else {
assert(exp_type == Compare);
llvm::CmpInst::Predicate cmp_pred;
switch (type) {
case AST_TYPE::Eq:
case AST_TYPE::Is:
cmp_pred = llvm::CmpInst::ICMP_EQ;
break;
case AST_TYPE::Lt:
cmp_pred = llvm::CmpInst::ICMP_SLT;
break;
case AST_TYPE::LtE:
cmp_pred = llvm::CmpInst::ICMP_SLE;
break;
case AST_TYPE::Gt:
cmp_pred = llvm::CmpInst::ICMP_SGT;
break;
case AST_TYPE::GtE:
cmp_pred = llvm::CmpInst::ICMP_SGE;
break;
case AST_TYPE::NotEq:
case AST_TYPE::IsNot:
cmp_pred = llvm::CmpInst::ICMP_NE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
v = emitter.getBuilder()->CreateICmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
assert(v->getType() == g.i64 || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true);
}
if (left->getType() == FLOAT && (right->getType() == FLOAT || right->getType() == INT)) { ConcreteCompilerVariable* is_defined_var = static_cast<ConcreteCompilerVariable*>(
ConcreteCompilerVariable* converted_left = left->makeConverted(emitter, FLOAT); _getFake(_getFakeName("is_defined", p.first.c_str()), true));
ConcreteCompilerVariable* converted_right; static const std::string setitem_str("__setitem__");
if (right->getType() == FLOAT) { if (!is_defined_var) {
converted_right = right->makeConverted(emitter, FLOAT); ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
} else {
converted_right = right->makeConverted(emitter, INT);
llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_);
converted_right->decvref(emitter);
converted_right = new ConcreteCompilerVariable(FLOAT, conv, true);
}
llvm::Value* v;
bool succeeded = true;
if (type == AST_TYPE::Mod) {
v = emitter.createCall2(exc_info, g.funcs.mod_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(exc_info, g.funcs.div_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (type == AST_TYPE::Pow) {
v = emitter.createCall2(exc_info, g.funcs.pow_float_float, converted_left->getValue(),
converted_right->getValue()).getInstruction();
} else if (exp_type == BinOp || exp_type == AugBinOp) {
llvm::Instruction::BinaryOps binopcode;
switch (type) {
case AST_TYPE::Add:
binopcode = llvm::Instruction::FAdd;
break;
case AST_TYPE::Mult:
binopcode = llvm::Instruction::FMul;
break;
case AST_TYPE::Sub:
binopcode = llvm::Instruction::FSub;
break;
case AST_TYPE::BitAnd:
case AST_TYPE::BitOr:
case AST_TYPE::BitXor:
case AST_TYPE::LShift:
case AST_TYPE::RShift:
succeeded = false;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
}
if (succeeded) { // TODO super dumb that it reallocates the name again
v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(), CompilerVariable* _r
converted_right->getValue()); = rtn->callattr(emitter, getEmptyOpInfo(exc_info), &setitem_str, true, ArgPassSpec(2),
} { makeStr(new std::string(p.first)), converted }, NULL);
} else { converted->decvref(emitter);
assert(exp_type == Compare); _r->decvref(emitter);
llvm::CmpInst::Predicate cmp_pred; } else {
switch (type) { assert(is_defined_var->getType() == BOOL);
case AST_TYPE::Eq:
case AST_TYPE::Is: llvm::BasicBlock* was_defined
cmp_pred = llvm::CmpInst::FCMP_OEQ; = llvm::BasicBlock::Create(g.context, "was_defined", irstate->getLLVMFunction());
break; llvm::BasicBlock* join
case AST_TYPE::Lt: = llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction());
cmp_pred = llvm::CmpInst::FCMP_OLT; emitter.getBuilder()->CreateCondBr(is_defined_var->getValue(), was_defined, join);
break;
case AST_TYPE::LtE: emitter.getBuilder()->SetInsertPoint(was_defined);
cmp_pred = llvm::CmpInst::FCMP_OLE; ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
break; // TODO super dumb that it reallocates the name again
case AST_TYPE::Gt: CompilerVariable* _r
cmp_pred = llvm::CmpInst::FCMP_OGT; = rtn->callattr(emitter, getEmptyOpInfo(exc_info), &setitem_str, true, ArgPassSpec(2),
break; { makeStr(new std::string(p.first)), converted }, NULL);
case AST_TYPE::GtE: converted->decvref(emitter);
cmp_pred = llvm::CmpInst::FCMP_OGE; _r->decvref(emitter);
break; emitter.getBuilder()->CreateBr(join);
case AST_TYPE::NotEq: emitter.getBuilder()->SetInsertPoint(join);
case AST_TYPE::IsNot: }
cmp_pred = llvm::CmpInst::FCMP_UNE;
break;
default:
ASSERT(0, "%s", getOpName(type).c_str());
abort();
break;
} }
v = emitter.getBuilder()->CreateFCmp(cmp_pred, converted_left->getValue(), converted_right->getValue());
}
converted_left->decvref(emitter);
converted_right->decvref(emitter);
if (succeeded) { return rtn;
assert(v->getType() == g.double_ || v->getType() == g.i1);
return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true);
} }
default:
RELEASE_ASSERT(0, "%d", node->opcode);
} }
// ASSERT(left->getType() == left->getBoxType() || right->getType() == right->getBoxType(), "%s %s", }
// left->getType()->debugName().c_str(), right->getType()->debugName().c_str());
ConcreteCompilerVariable* boxed_left = left->makeConverted(emitter, left->getBoxType());
ConcreteCompilerVariable* boxed_right = right->makeConverted(emitter, right->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
llvm::Value* rt_func;
void* rt_func_addr;
if (exp_type == BinOp) {
rt_func = g.funcs.binop;
rt_func_addr = (void*)binop;
} 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;
}
if (do_patchpoint) {
PatchpointSetupInfo* pp = patchpoints::createBinexpPatchpoint(
emitter.currentFunction(), getOpInfoForNode(node, exc_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(boxed_left->getValue());
llvm_args.push_back(boxed_right->getValue());
llvm_args.push_back(getConstantInt(type, g.i32));
llvm::Value* uncasted = emitter.createPatchpoint(pp, rt_func_addr, llvm_args, exc_info).getInstruction();
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else {
rtn = emitter.createCall3(exc_info, rt_func, boxed_left->getValue(), boxed_right->getValue(),
getConstantInt(type, g.i32)).getInstruction();
}
boxed_left->decvref(emitter); CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type,
boxed_right->decvref(emitter); BinExpType exp_type, ExcInfo exc_info) {
assert(state != PARTIAL);
if (type == AST_TYPE::In || type == AST_TYPE::NotIn || type == AST_TYPE::Is || type == AST_TYPE::IsNot) { assert(left);
return unboxVar(BOXED_BOOL, rtn, true); assert(right);
}
return new ConcreteCompilerVariable(UNKNOWN, rtn, true); return left->binexp(emitter, getOpInfoForNode(node, exc_info), right, type, exp_type);
} }
CompilerVariable* evalBinOp(AST_BinOp* node, ExcInfo exc_info) { CompilerVariable* evalBinOp(AST_BinOp* node, ExcInfo exc_info) {
...@@ -734,7 +549,7 @@ private: ...@@ -734,7 +549,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);
...@@ -862,9 +677,10 @@ private: ...@@ -862,9 +677,10 @@ private:
} }
std::string defined_name = _getFakeName("is_defined", node->id.c_str()); std::string defined_name = _getFakeName("is_defined", node->id.c_str());
ConcreteCompilerVariable* is_defined = static_cast<ConcreteCompilerVariable*>(_popFake(defined_name, true)); ConcreteCompilerVariable* is_defined_var
= static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
if (is_defined) { if (is_defined_var) {
// classdefs have different scoping rules than functions: // classdefs have different scoping rules than functions:
if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) { if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) {
llvm::BasicBlock* from_local llvm::BasicBlock* from_local
...@@ -873,7 +689,7 @@ private: ...@@ -873,7 +689,7 @@ private:
= llvm::BasicBlock::Create(g.context, "from_global", irstate->getLLVMFunction()); = llvm::BasicBlock::Create(g.context, "from_global", irstate->getLLVMFunction());
llvm::BasicBlock* join = llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction()); llvm::BasicBlock* join = llvm::BasicBlock::Create(g.context, "join", irstate->getLLVMFunction());
emitter.getBuilder()->CreateCondBr(is_defined->getValue(), from_local, from_global); emitter.getBuilder()->CreateCondBr(is_defined_var->getValue(), from_local, from_global);
emitter.getBuilder()->SetInsertPoint(from_local); emitter.getBuilder()->SetInsertPoint(from_local);
CompilerVariable* local = symbol_table[node->id]; CompilerVariable* local = symbol_table[node->id];
...@@ -893,8 +709,11 @@ private: ...@@ -893,8 +709,11 @@ private:
return new ConcreteCompilerVariable(UNKNOWN, phi, true); return new ConcreteCompilerVariable(UNKNOWN, phi, true);
} }
emitter.createCall2(exc_info, g.funcs.assertNameDefined, is_defined->getValue(), emitter.createCall2(exc_info, g.funcs.assertNameDefined, is_defined_var->getValue(),
getStringConstantPtr(node->id + '\0')); getStringConstantPtr(node->id + '\0'));
// At this point we know the name must be defined (otherwise the assert would have fired):
_popFake(defined_name);
} }
CompilerVariable* rtn = symbol_table[node->id]; CompilerVariable* rtn = symbol_table[node->id];
...@@ -1271,30 +1090,29 @@ private: ...@@ -1271,30 +1090,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;
} }
...@@ -1454,6 +1272,16 @@ private: ...@@ -1454,6 +1272,16 @@ private:
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node); ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
assert(scope_info); assert(scope_info);
if (node->bases.size() == 0) {
printf("Warning: old-style class '%s' in file '%s' detected! Converting to a new-style class!\n",
node->name.c_str(), irstate->getSourceInfo()->parent_module->fn.c_str());
AST_Name* base = new AST_Name();
base->id = "object";
base->ctx_type = AST_TYPE::Load;
node->bases.push_back(base);
}
RELEASE_ASSERT(node->bases.size() == 1, ""); RELEASE_ASSERT(node->bases.size() == 1, "");
RELEASE_ASSERT(node->decorator_list.size() == 0, ""); RELEASE_ASSERT(node->decorator_list.size() == 0, "");
...@@ -1569,13 +1397,33 @@ private: ...@@ -1569,13 +1397,33 @@ private:
} }
CompilerVariable* created_closure = NULL; CompilerVariable* created_closure = NULL;
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
if (scope_info->takesClosure()) { bool takes_closure;
created_closure = _getFake(CREATED_CLOSURE_NAME, false); // Optimization: when compiling a module, it's nice to not have to run analyses into the
// entire module's source code.
// If we call getScopeInfoForNode, that will trigger an analysis of that function tree,
// but we're only using it here to figure out if that function takes a closure.
// Top level functions never take a closure, so we can skip the analysis.
if (irstate->getSourceInfo()->ast->type == AST_TYPE::Module)
takes_closure = false;
else {
takes_closure = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node)->takesClosure();
}
// TODO: this lines disables the optimization mentioned above...
bool is_generator = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node)->takesGenerator();
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
created_closure = _getFake(CREATED_CLOSURE_NAME, false);
} else {
assert(irstate->getScopeInfo()->passesThroughClosure());
created_closure = _getFake(PASSED_CLOSURE_NAME, false);
}
assert(created_closure); assert(created_closure);
} }
CompilerVariable* func = makeFunction(emitter, cl, created_closure, scope_info->takesGenerator(), defaults); CompilerVariable* func = makeFunction(emitter, cl, created_closure, is_generator, defaults);
for (auto d : defaults) { for (auto d : defaults) {
d->decvref(emitter); d->decvref(emitter);
...@@ -1631,7 +1479,11 @@ private: ...@@ -1631,7 +1479,11 @@ private:
const std::string& name = alias->name; const std::string& name = alias->name;
const std::string& asname = alias->asname.size() ? alias->asname : alias->name; const std::string& asname = alias->asname.size() ? alias->asname : alias->name;
CompilerVariable* v = module->getattr(emitter, getEmptyOpInfo(exc_info), &name, false); // TODO add patchpoints to this?
llvm::Value* r = emitter.createCall2(exc_info, g.funcs.importFrom, module->getValue(),
embedConstantPtr(&name, g.llvm_str_type_ptr)).getInstruction();
CompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, r, true);
_doSet(asname, v, exc_info); _doSet(asname, v, exc_info);
v->decvref(emitter); v->decvref(emitter);
} }
...@@ -1692,6 +1544,11 @@ private: ...@@ -1692,6 +1544,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());
...@@ -1769,18 +1626,6 @@ private: ...@@ -1769,18 +1626,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]
...@@ -1814,11 +1659,6 @@ private: ...@@ -1814,11 +1659,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:
...@@ -1845,11 +1685,17 @@ private: ...@@ -1845,11 +1685,17 @@ private:
} else { } else {
llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, arg_num - 3); llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, arg_num - 3);
if (var->getType() == INT) { if (var->getType() == INT || var->getType() == BOOL) {
val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr); val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr);
} 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);
} }
...@@ -1915,23 +1761,21 @@ private: ...@@ -1915,23 +1761,21 @@ private:
} }
void doRaise(AST_Raise* node, ExcInfo exc_info) { void doRaise(AST_Raise* node, ExcInfo exc_info) {
RELEASE_ASSERT(node->arg0 != NULL, ""); std::vector<llvm::Value*> args;
RELEASE_ASSERT(node->arg1 == NULL, ""); llvm::Value* raise_func = g.funcs.raise0;
RELEASE_ASSERT(node->arg2 == NULL, "");
CompilerVariable* arg0 = evalExpr(node->arg0, exc_info); if (node->arg0) {
ConcreteCompilerVariable* converted_arg0 = arg0->makeConverted(emitter, arg0->getBoxType()); raise_func = g.funcs.raise1;
arg0->decvref(emitter);
llvm::Value* exc_mem CompilerVariable* arg0 = evalExpr(node->arg0, exc_info);
= emitter.getBuilder()->CreateCall(g.funcs.__cxa_allocate_exception, getConstantInt(sizeof(void*), g.i64)); ConcreteCompilerVariable* converted_arg0 = arg0->makeConverted(emitter, arg0->getBoxType());
llvm::Value* bitcasted = emitter.getBuilder()->CreateBitCast(exc_mem, g.llvm_value_type_ptr->getPointerTo()); arg0->decvref(emitter);
emitter.getBuilder()->CreateStore(converted_arg0->getValue(), bitcasted); args.push_back(converted_arg0->getValue());
converted_arg0->decvref(emitter); }
RELEASE_ASSERT(node->arg1 == NULL, "");
RELEASE_ASSERT(node->arg2 == NULL, "");
void* type_id = &_ZTIPN6pyston3BoxE /* &typeid(Box*) */; emitter.createCall(exc_info, raise_func, args);
emitter.createCall(exc_info, g.funcs.__cxa_throw,
{ exc_mem, embedConstantPtr(type_id, g.i8_ptr), embedConstantPtr(nullptr, g.i8_ptr) });
emitter.getBuilder()->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
endBlock(DEAD); endBlock(DEAD);
...@@ -2064,11 +1908,14 @@ private: ...@@ -2064,11 +1908,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
ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock); // here, but this is just for debugging so I guess let it happen for now:
ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s", ConcreteCompilerType* ending_type = types->getTypeAtBlockEnd(it->first, myblock);
it->first.c_str(), ending_type->debugName().c_str(), it->second->getType()->debugName().c_str()); 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());
}
#endif #endif
++it; ++it;
...@@ -2123,20 +1970,13 @@ public: ...@@ -2123,20 +1970,13 @@ 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);
st->erase(PASSED_GENERATOR_NAME); }
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,
......
...@@ -102,6 +102,12 @@ Val fetch(llvm::Value* v, const llvm::DataLayout& dl, const SymMap& symbols) { ...@@ -102,6 +102,12 @@ Val fetch(llvm::Value* v, const llvm::DataLayout& dl, const SymMap& symbols) {
case llvm::Value::ConstantExprVal: { case llvm::Value::ConstantExprVal: {
llvm::ConstantExpr* ce = llvm::cast<llvm::ConstantExpr>(v); llvm::ConstantExpr* ce = llvm::cast<llvm::ConstantExpr>(v);
if (ce->isCast()) { if (ce->isCast()) {
if (ce->getOpcode() == llvm::Instruction::IntToPtr && ce->getOperand(0)->getType() == g.i1) {
// inttoptr is specified to zero-extend
Val o = fetch(ce->getOperand(0), dl, symbols);
return o.n & 0x1;
}
assert(width(ce->getOperand(0), dl) == 8 && width(ce, dl) == 8); assert(width(ce->getOperand(0), dl) == 8 && width(ce, dl) == 8);
Val o = fetch(ce->getOperand(0), dl, symbols); Val o = fetch(ce->getOperand(0), dl, symbols);
...@@ -283,7 +289,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -283,7 +289,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
int arg_num = -1; int arg_num = -1;
int closure_indicator = closure ? 1 : 0; int closure_indicator = closure ? 1 : 0;
int generator_indicator = generator ? 1 : 0; int generator_indicator = generator ? 1 : 0;
int argOffset = closure_indicator + generator_indicator; int arg_offset = closure_indicator + generator_indicator;
for (llvm::Argument& arg : f->args()) { for (llvm::Argument& arg : f->args()) {
arg_num++; arg_num++;
...@@ -291,15 +297,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -291,15 +297,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(closure))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(closure)));
else if ((arg_num == 0 || (arg_num == 1 && closure)) && generator) else if ((arg_num == 0 || (arg_num == 1 && closure)) && generator)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(generator))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(generator)));
else if (arg_num == 0 + argOffset) else if (arg_num == 0 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg1))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg1)));
else if (arg_num == 1 + argOffset) else if (arg_num == 1 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg2))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg2)));
else if (arg_num == 2 + argOffset) else if (arg_num == 2 + arg_offset)
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg3))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg3)));
else { else {
assert(arg_num == 3 + argOffset); assert(arg_num == 3 + arg_offset);
assert(f->getArgumentList().size() == 4 + argOffset); assert(f->getArgumentList().size() == 4 + arg_offset);
assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo()); assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo());
symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val((int64_t)args))); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val((int64_t)args)));
// printf("loading %%4 with %p\n", (void*)args); // printf("loading %%4 with %p\n", (void*)args);
...@@ -310,6 +316,14 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -310,6 +316,14 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
llvm::BasicBlock* prevblock = NULL; llvm::BasicBlock* prevblock = NULL;
llvm::BasicBlock* curblock = &f->getEntryBlock(); llvm::BasicBlock* curblock = &f->getEntryBlock();
// The symbol table at the end of the previous BB
// This is important for the following case:
// %a = phi [0, %l1], [1, %l2]
// %b = phi [0, %l1], [%a, %l2]
// The reference to %a in the definition of %b resolves to the *previous* value of %a,
// not the value of %a that we just set in the phi.
SymMap prev_symbols;
struct { struct {
Box* exc_obj; Box* exc_obj;
int64_t exc_selector; int64_t exc_selector;
...@@ -521,8 +535,12 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -521,8 +535,12 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
SET(fetch(bc->getOperand(0), dl, symbols)); SET(fetch(bc->getOperand(0), dl, symbols));
continue; continue;
} else if (llvm::IntToPtrInst* bc = llvm::dyn_cast<llvm::IntToPtrInst>(inst)) { } else if (llvm::IntToPtrInst* bc = llvm::dyn_cast<llvm::IntToPtrInst>(inst)) {
assert(width(bc->getOperand(0), dl) == 8); if (bc->getOperand(0)->getType() == g.i1) {
SET(fetch(bc->getOperand(0), dl, symbols)); SET(fetch(bc->getOperand(0), dl, symbols).n & 0xff);
} else {
assert(width(bc->getOperand(0), dl) == 8);
SET(fetch(bc->getOperand(0), dl, symbols));
}
continue; continue;
//} else if (llvm::CallInst* ci = llvm::dyn_cast<llvm::CallInst>(inst)) { //} else if (llvm::CallInst* ci = llvm::dyn_cast<llvm::CallInst>(inst)) {
} else if (llvm::isa<llvm::CallInst>(inst) || llvm::isa<llvm::InvokeInst>(inst)) { } else if (llvm::isa<llvm::CallInst>(inst) || llvm::isa<llvm::InvokeInst>(inst)) {
...@@ -615,14 +633,18 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -615,14 +633,18 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
r = reinterpret_cast<int64_t (*)(int64_t, double, double)>(f)(args[0].n, args[1].d, r = reinterpret_cast<int64_t (*)(int64_t, double, double)>(f)(args[0].n, args[1].d,
args[2].d); args[2].d);
break; break;
case 0b100000: case 0b100000: // 32
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n); args[0].n, args[1].n, args[2].n, args[3].n);
break; break;
case 0b100001: case 0b100001: // 33
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, double)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, double)>(f)(
args[0].n, args[1].n, args[2].n, args[3].d); args[0].n, args[1].n, args[2].n, args[3].d);
break; break;
case 0b100010: // 34
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, double, int64_t)>(f)(
args[0].n, args[1].n, args[2].d, args[3].n);
break;
case 0b100110: case 0b100110:
r = reinterpret_cast<int64_t (*)(int64_t, double, double, int64_t)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, double, double, int64_t)>(f)(
args[0].n, args[1].d, args[2].d, args[3].n); args[0].n, args[1].d, args[2].d, args[3].n);
...@@ -631,15 +653,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -631,15 +653,15 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n, r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n,
args[2].d, args[3].n); args[2].d, args[3].n);
break; break;
case 0b1000000: case 0b1000000: // 64
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n); args[0].n, args[1].n, args[2].n, args[3].n, args[4].n);
break; break;
case 0b10000000: case 0b10000000: // 128
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t)>(f)( r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n); args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n);
break; break;
case 0b100000000: case 0b100000000: // 256
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n, int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n); args[4].n, args[5].n, args[6].n);
...@@ -667,6 +689,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -667,6 +689,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
if (invoke != nullptr) { if (invoke != nullptr) {
prevblock = curblock; prevblock = curblock;
curblock = invoke->getNormalDest(); curblock = invoke->getNormalDest();
prev_symbols = symbols;
} }
} catch (Box* e) { } catch (Box* e) {
if (VERBOSITY("interpreter") >= 2) { if (VERBOSITY("interpreter") >= 2) {
...@@ -678,6 +701,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -678,6 +701,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
prevblock = curblock; prevblock = curblock;
curblock = invoke->getUnwindDest(); curblock = invoke->getUnwindDest();
prev_symbols = symbols;
landingpad_value.exc_obj = e; landingpad_value.exc_obj = e;
landingpad_value.exc_selector landingpad_value.exc_selector
...@@ -700,7 +724,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -700,7 +724,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
continue; continue;
} else if (llvm::PHINode* phi = llvm::dyn_cast<llvm::PHINode>(inst)) { } else if (llvm::PHINode* phi = llvm::dyn_cast<llvm::PHINode>(inst)) {
assert(prevblock); assert(prevblock);
SET(fetch(phi->getIncomingValueForBlock(prevblock), dl, symbols)); SET(fetch(phi->getIncomingValueForBlock(prevblock), dl, prev_symbols));
continue; continue;
} else if (llvm::BranchInst* br = llvm::dyn_cast<llvm::BranchInst>(inst)) { } else if (llvm::BranchInst* br = llvm::dyn_cast<llvm::BranchInst>(inst)) {
prevblock = curblock; prevblock = curblock;
...@@ -714,6 +738,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato ...@@ -714,6 +738,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generato
} else { } else {
curblock = br->getSuccessor(0); curblock = br->getSuccessor(0);
} }
prev_symbols = symbols;
// if (VERBOSITY()) { // if (VERBOSITY()) {
// printf("jumped to %s\n", curblock->getName().data()); // printf("jumped to %s\n", curblock->getName().data());
//} //}
......
...@@ -881,7 +881,7 @@ AST_Module* parse(const char* fn) { ...@@ -881,7 +881,7 @@ AST_Module* parse(const char* fn) {
#define MAGIC_STRING "a\nch" #define MAGIC_STRING "a\nch"
#define MAGIC_STRING_LENGTH 4 #define MAGIC_STRING_LENGTH 4
#define LENGTH_SUFFIX_LENGTH 4 #define CHECKSUM_LENGTH 4
static void _reparse(const char* fn, const std::string& cache_fn) { static void _reparse(const char* fn, const std::string& cache_fn) {
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r"); FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
...@@ -890,7 +890,14 @@ static void _reparse(const char* fn, const std::string& cache_fn) { ...@@ -890,7 +890,14 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp); fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp);
int bytes_written = 0; int checksum_start = ftell(cache_fp);
int bytes_written = -1;
// Currently just use the length as the checksum
static_assert(sizeof(bytes_written) >= CHECKSUM_LENGTH, "");
fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
bytes_written = 0;
char buf[80]; char buf[80];
while (true) { while (true) {
int nread = fread(buf, 1, 80, parser); int nread = fread(buf, 1, 80, parser);
...@@ -900,13 +907,12 @@ static void _reparse(const char* fn, const std::string& cache_fn) { ...@@ -900,13 +907,12 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(buf, 1, nread, cache_fp); fwrite(buf, 1, nread, cache_fp);
} }
// Ideally this should be a full checksum rather than just a length.
// And maybe it should be put at the beginning?
static_assert(sizeof(bytes_written) >= LENGTH_SUFFIX_LENGTH, "");
fwrite(&bytes_written, 1, LENGTH_SUFFIX_LENGTH, cache_fp);
int code = pclose(parser); int code = pclose(parser);
assert(code == 0); assert(code == 0);
fseek(cache_fp, checksum_start, SEEK_SET);
fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
fclose(cache_fp); fclose(cache_fp);
} }
...@@ -940,20 +946,25 @@ AST_Module* caching_parse(const char* fn) { ...@@ -940,20 +946,25 @@ AST_Module* caching_parse(const char* fn) {
char buf[MAGIC_STRING_LENGTH]; char buf[MAGIC_STRING_LENGTH];
int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp); int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp);
if (read != MAGIC_STRING_LENGTH || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) { if (read != MAGIC_STRING_LENGTH || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) {
if (VERBOSITY()) {
printf("Warning: corrupt or non-Pyston .pyc file found; ignoring\n");
}
good = false; good = false;
} }
} }
if (good) { if (good) {
int length = 0; int length = 0;
fseek(fp, -LENGTH_SUFFIX_LENGTH, SEEK_END);
static_assert(sizeof(length) >= LENGTH_SUFFIX_LENGTH, "");
int read = fread(&length, 1, LENGTH_SUFFIX_LENGTH, fp);
fseek(fp, MAGIC_STRING_LENGTH, SEEK_SET); fseek(fp, MAGIC_STRING_LENGTH, SEEK_SET);
static_assert(sizeof(length) >= CHECKSUM_LENGTH, "");
int read = fread(&length, 1, CHECKSUM_LENGTH, fp);
int expected_length = MAGIC_STRING_LENGTH + LENGTH_SUFFIX_LENGTH + length; int expected_total_length = MAGIC_STRING_LENGTH + CHECKSUM_LENGTH + length;
if (read != LENGTH_SUFFIX_LENGTH || expected_length != cache_stat.st_size) { if (read != CHECKSUM_LENGTH || expected_total_length != cache_stat.st_size) {
if (VERBOSITY()) {
printf("Warning: truncated .pyc file found; ignoring\n");
}
good = false; good = false;
} }
} }
...@@ -974,7 +985,7 @@ AST_Module* caching_parse(const char* fn) { ...@@ -974,7 +985,7 @@ AST_Module* caching_parse(const char* fn) {
BufferedReader* reader = new BufferedReader(fp); BufferedReader* reader = new BufferedReader(fp);
AST* rtn = readASTMisc(reader); AST* rtn = readASTMisc(reader);
reader->fill(); reader->fill();
assert(reader->bytesBuffered() == LENGTH_SUFFIX_LENGTH); assert(reader->bytesBuffered() == 0);
delete reader; delete reader;
assert(rtn->type == AST_TYPE::Module); assert(rtn->type == AST_TYPE::Module);
......
...@@ -42,8 +42,6 @@ ...@@ -42,8 +42,6 @@
extern "C" void* __cxa_begin_catch(void*); extern "C" void* __cxa_begin_catch(void*);
extern "C" void __cxa_end_catch(); extern "C" void __cxa_end_catch();
extern "C" void* __cxa_allocate_exception(size_t);
extern "C" void __cxa_throw(void*, void*, void (*)(void*));
namespace pyston { namespace pyston {
...@@ -135,9 +133,11 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -135,9 +133,11 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType(); g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType();
auto vector_type = g.stdlib_module->getTypeByName("class.std::vector"); // The LLVM vector type for the arguments that we pass to runtimeCall and related functions.
assert(vector_type); // It will be a pointer to a type named something like class.std::vector or
g.vector_ptr = vector_type->getPointerTo(); // class.std::vector.##. We can figure out exactly what it is by looking at the last
// argument of runtimeCall.
g.vector_ptr = (--lookupFunction("runtimeCall")->getArgumentList().end())->getType();
g.llvm_closure_type_ptr = g.stdlib_module->getTypeByName("class.pyston::BoxedClosure")->getPointerTo(); g.llvm_closure_type_ptr = g.stdlib_module->getTypeByName("class.pyston::BoxedClosure")->getPointerTo();
assert(g.llvm_closure_type_ptr); assert(g.llvm_closure_type_ptr);
...@@ -187,6 +187,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -187,6 +187,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(getclsattr); GET(getclsattr);
GET(unaryop); GET(unaryop);
GET(import); GET(import);
GET(importFrom);
GET(repr); GET(repr);
GET(isinstance); GET(isinstance);
GET(yield); GET(yield);
...@@ -225,8 +226,8 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -225,8 +226,8 @@ void initGlobalFuncs(GlobalState& g) {
GET(__cxa_begin_catch); GET(__cxa_begin_catch);
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_); g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
g.funcs.__cxa_allocate_exception = addFunc((void*)__cxa_allocate_exception, g.i8_ptr, g.i64); GET(raise0);
g.funcs.__cxa_throw = addFunc((void*)__cxa_throw, g.void_, g.i8_ptr, g.i8_ptr, g.i8_ptr); GET(raise1);
g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64"); g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64");
g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64"); g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64");
......
...@@ -34,7 +34,7 @@ struct GlobalFuncs { ...@@ -34,7 +34,7 @@ struct GlobalFuncs {
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure, *createGenerator, *insideGenerator; *createUserClass, *createClosure, *createGenerator, *insideGenerator;
llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr, llvm::Value* getattr, *setattr, *print, *nonzero, *binop, *compare, *augbinop, *unboxedLen, *getitem, *getclsattr,
*yield, *getGlobal, *setitem, *delitem, *unaryop, *import, *repr, *isinstance; *getGlobal, *setitem, *delitem, *unaryop, *import, *importFrom, *repr, *isinstance, *yield;
llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, llvm::Value* checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail; *assertNameDefined, *assertFail;
...@@ -43,7 +43,8 @@ struct GlobalFuncs { ...@@ -43,7 +43,8 @@ struct GlobalFuncs {
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr; llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr;
llvm::Value* reoptCompiledFunc, *compilePartialFunc; llvm::Value* reoptCompiledFunc, *compilePartialFunc;
llvm::Value* __cxa_begin_catch, *__cxa_end_catch, *__cxa_allocate_exception, *__cxa_throw; llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* raise0, *raise1;
llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64; llvm::Value* div_i64_i64, *mod_i64_i64, *pow_i64_i64;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float; llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
......
...@@ -1314,6 +1314,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) { ...@@ -1314,6 +1314,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case AST_LangPrimitive::LANDINGPAD: case AST_LangPrimitive::LANDINGPAD:
printf("landingpad"); printf("landingpad");
break; break;
case AST_LangPrimitive::LOCALS:
printf("locals");
break;
default: default:
RELEASE_ASSERT(0, "%d", node->opcode); RELEASE_ASSERT(0, "%d", node->opcode);
} }
......
...@@ -879,6 +879,7 @@ public: ...@@ -879,6 +879,7 @@ public:
enum Opcodes { enum Opcodes {
ISINSTANCE, ISINSTANCE,
LANDINGPAD, LANDINGPAD,
LOCALS,
} opcode; } opcode;
std::vector<AST_expr*> args; std::vector<AST_expr*> args;
......
...@@ -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;
...@@ -622,28 +626,20 @@ private: ...@@ -622,28 +626,20 @@ private:
} }
AST_expr* remapLambda(AST_Lambda* node) { AST_expr* remapLambda(AST_Lambda* node) {
if (node->args->defaults.empty()) { // Remap in place: see note in visit_functiondef for why.
return node;
}
AST_Lambda* rtn = new AST_Lambda(); for (int i = 0; i < node->args->defaults.size(); i++) {
rtn->lineno = node->lineno; node->args->defaults[i] = remapExpr(node->args->defaults[i]);
rtn->col_offset = node->col_offset;
rtn->args = new AST_arguments();
rtn->args->args = node->args->args;
rtn->args->vararg = node->args->vararg;
rtn->args->kwarg = node->args->kwarg;
for (auto d : node->args->defaults) {
rtn->args->defaults.push_back(remapExpr(d));
} }
rtn->body = node->body; return node;
return rtn;
} }
AST_expr* remapLangPrimitive(AST_LangPrimitive* node) { AST_expr* remapLangPrimitive(AST_LangPrimitive* node) {
AST_LangPrimitive* rtn = new AST_LangPrimitive(node->opcode); AST_LangPrimitive* rtn = new AST_LangPrimitive(node->opcode);
rtn->col_offset = node->col_offset;
rtn->lineno = node->lineno;
for (AST_expr* arg : node->args) { for (AST_expr* arg : node->args) {
rtn->args.push_back(remapExpr(arg)); rtn->args.push_back(remapExpr(arg));
} }
...@@ -859,6 +855,8 @@ public: ...@@ -859,6 +855,8 @@ public:
AST_Invoke* invoke = new AST_Invoke(node); AST_Invoke* invoke = new AST_Invoke(node);
invoke->normal_dest = normal_dest; invoke->normal_dest = normal_dest;
invoke->exc_dest = exc_dest; invoke->exc_dest = exc_dest;
invoke->col_offset = node->col_offset;
invoke->lineno = node->lineno;
curblock->push_back(invoke); curblock->push_back(invoke);
curblock->connectTo(normal_dest); curblock->connectTo(normal_dest);
...@@ -878,36 +876,42 @@ public: ...@@ -878,36 +876,42 @@ public:
} }
virtual bool visit_classdef(AST_ClassDef* node) { virtual bool visit_classdef(AST_ClassDef* node) {
// Remap in place: see note in visit_functiondef for why.
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) {
node->decorator_list[i] = remapExpr(node->decorator_list[i]);
}
for (int i = 0; i < node->bases.size(); i++) {
node->bases[i] = remapExpr(node->bases[i]);
}
push_back(node); push_back(node);
return true; return true;
} }
virtual bool visit_functiondef(AST_FunctionDef* node) { virtual bool visit_functiondef(AST_FunctionDef* node) {
if (node->args->defaults.size() == 0 && node->decorator_list.size() == 0) { // As much as I don't like it, for now we're remapping these in place.
push_back(node); // This is because we do certain analyses pre-remapping, and associate the
} else { // results with the node. We can either do some refactoring and have a way
AST_FunctionDef* remapped = new AST_FunctionDef(); // of associating the new node with the same results, or just do the remapping
// in-place.
// Doing it in-place seems ugly, but I can't think of anything it should break,
// so just do that for now.
// TODO If we remap these (functiondefs, lambdas, classdefs) in place, we should probably
// remap everything in place?
remapped->name = node->name; // Decorators are evaluated before the defaults:
remapped->lineno = node->lineno; for (int i = 0; i < node->decorator_list.size(); i++) {
remapped->col_offset = node->col_offset; node->decorator_list[i] = remapExpr(node->decorator_list[i]);
remapped->args = new AST_arguments(); }
remapped->body = node->body; // hmm shouldnt have to copy this
// Decorators are evaluated before the defaults:
for (auto d : node->decorator_list) {
remapped->decorator_list.push_back(remapExpr(d));
}
remapped->args->args = node->args->args;
remapped->args->vararg = node->args->vararg;
remapped->args->kwarg = node->args->kwarg;
for (auto d : node->args->defaults) {
remapped->args->defaults.push_back(remapExpr(d));
}
push_back(remapped); for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
} }
push_back(node);
return true; return true;
} }
...@@ -1027,11 +1031,15 @@ public: ...@@ -1027,11 +1031,15 @@ public:
s_target->value = remapExpr(s->value); s_target->value = remapExpr(s->value);
s_target->slice = remapExpr(s->slice); s_target->slice = remapExpr(s->slice);
s_target->ctx_type = AST_TYPE::Store; s_target->ctx_type = AST_TYPE::Store;
s_target->col_offset = s->col_offset;
s_target->lineno = s->lineno;
remapped_target = s_target; remapped_target = s_target;
AST_Subscript* s_lhs = new AST_Subscript(); AST_Subscript* s_lhs = new AST_Subscript();
s_lhs->value = s_target->value; s_lhs->value = s_target->value;
s_lhs->slice = s_target->slice; s_lhs->slice = s_target->slice;
s_lhs->col_offset = s->col_offset;
s_lhs->lineno = s->lineno;
s_lhs->ctx_type = AST_TYPE::Load; s_lhs->ctx_type = AST_TYPE::Load;
remapped_lhs = remapExpr(s_lhs); remapped_lhs = remapExpr(s_lhs);
...@@ -1045,12 +1053,16 @@ public: ...@@ -1045,12 +1053,16 @@ public:
a_target->value = remapExpr(a->value); a_target->value = remapExpr(a->value);
a_target->attr = a->attr; a_target->attr = a->attr;
a_target->ctx_type = AST_TYPE::Store; a_target->ctx_type = AST_TYPE::Store;
a_target->col_offset = a->col_offset;
a_target->lineno = a->lineno;
remapped_target = a_target; remapped_target = a_target;
AST_Attribute* a_lhs = new AST_Attribute(); AST_Attribute* a_lhs = new AST_Attribute();
a_lhs->value = a_target->value; a_lhs->value = a_target->value;
a_lhs->attr = a->attr; a_lhs->attr = a->attr;
a_lhs->ctx_type = AST_TYPE::Load; a_lhs->ctx_type = AST_TYPE::Load;
a_lhs->col_offset = a->col_offset;
a_lhs->lineno = a->lineno;
remapped_lhs = remapExpr(a_lhs); remapped_lhs = remapExpr(a_lhs);
break; break;
...@@ -1063,6 +1075,8 @@ public: ...@@ -1063,6 +1075,8 @@ public:
binop->op_type = node->op_type; binop->op_type = node->op_type;
binop->left = remapped_lhs; binop->left = remapped_lhs;
binop->right = remapExpr(node->value); binop->right = remapExpr(node->value);
binop->col_offset = node->col_offset;
binop->lineno = node->lineno;
AST_stmt* assign = makeAssign(remapped_target, binop); AST_stmt* assign = makeAssign(remapped_target, binop);
push_back(assign); push_back(assign);
return true; return true;
...@@ -1109,6 +1123,7 @@ public: ...@@ -1109,6 +1123,7 @@ public:
int i = 0; int i = 0;
for (auto v : node->values) { for (auto v : node->values) {
AST_Print* remapped = new AST_Print(); AST_Print* remapped = new AST_Print();
remapped->col_offset = node->col_offset;
remapped->lineno = node->lineno; remapped->lineno = node->lineno;
// TODO not good to reuse 'dest' like this // TODO not good to reuse 'dest' like this
remapped->dest = dest; remapped->dest = dest;
...@@ -1128,6 +1143,8 @@ public: ...@@ -1128,6 +1143,8 @@ public:
assert(node->nl); assert(node->nl);
AST_Print* final = new AST_Print(); AST_Print* final = new AST_Print();
final->col_offset = node->col_offset;
final->lineno = node->lineno;
// TODO not good to reuse 'dest' like this // TODO not good to reuse 'dest' like this
final->dest = dest; final->dest = dest;
final->nl = node->nl; final->nl = node->nl;
...@@ -1417,6 +1434,9 @@ public: ...@@ -1417,6 +1434,9 @@ public:
bool visit_raise(AST_Raise* node) override { bool visit_raise(AST_Raise* node) override {
AST_Raise* remapped = new AST_Raise(); AST_Raise* remapped = new AST_Raise();
remapped->col_offset = node->col_offset;
remapped->lineno = node->lineno;
if (node->arg0) if (node->arg0)
remapped->arg0 = remapExpr(node->arg0); remapped->arg0 = remapExpr(node->arg0);
if (node->arg1) if (node->arg1)
...@@ -1425,6 +1445,9 @@ public: ...@@ -1425,6 +1445,9 @@ public:
remapped->arg2 = remapExpr(node->arg2); remapped->arg2 = remapExpr(node->arg2);
push_back(remapped); push_back(remapped);
if (!curblock)
return true;
curblock->push_back(new AST_Unreachable()); curblock->push_back(new AST_Unreachable());
curblock = NULL; curblock = NULL;
...@@ -1518,7 +1541,6 @@ public: ...@@ -1518,7 +1541,6 @@ public:
if (!caught_all) { if (!caught_all) {
AST_Raise* raise = new AST_Raise(); AST_Raise* raise = new AST_Raise();
raise->arg0 = exc_obj;
push_back(raise); push_back(raise);
curblock->push_back(new AST_Unreachable()); curblock->push_back(new AST_Unreachable());
curblock = NULL; curblock = NULL;
...@@ -1709,20 +1731,10 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) { ...@@ -1709,20 +1731,10 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->ast->type == AST_TYPE::ClassDef) { if (source->ast->type == AST_TYPE::ClassDef) {
ScopeInfo* scope_info = source->scoping->getScopeInfoForNode(source->ast); ScopeInfo* scope_info = source->scoping->getScopeInfoForNode(source->ast);
auto written_names = scope_info->getClassDefLocalNames(); AST_LangPrimitive* locals = new AST_LangPrimitive(AST_LangPrimitive::LOCALS);
AST_Dict* rtn_dict = new AST_Dict();
// Even if the user never explicitly wrote to __module__, there was an
// implicit write:
assert(written_names.count("__module__"));
for (auto s : written_names) {
rtn_dict->keys.push_back(new AST_Str(s));
rtn_dict->values.push_back(makeName(s, AST_TYPE::Load));
}
AST_Return* rtn = new AST_Return(); AST_Return* rtn = new AST_Return();
rtn->value = rtn_dict; rtn->value = locals;
visitor.push_back(rtn); visitor.push_back(rtn);
} else { } else {
// Put a fake "return" statement at the end of every function just to make sure they all have one; // Put a fake "return" statement at the end of every function just to make sure they all have one;
......
...@@ -42,6 +42,18 @@ void registerStaticRootObj(void* obj) { ...@@ -42,6 +42,18 @@ void registerStaticRootObj(void* obj) {
roots.push(obj); roots.push(obj);
} }
static std::unordered_set<StaticRootHandle*>* getRootHandles() {
static std::unordered_set<StaticRootHandle*> root_handles;
return &root_handles;
}
StaticRootHandle::StaticRootHandle() {
getRootHandles()->insert(this);
}
StaticRootHandle::~StaticRootHandle() {
getRootHandles()->erase(this);
}
bool TraceStackGCVisitor::isValid(void* p) { bool TraceStackGCVisitor::isValid(void* p) {
return global_heap.getAllocationFromInteriorPointer(p); return global_heap.getAllocationFromInteriorPointer(p);
} }
...@@ -105,6 +117,10 @@ static void markPhase() { ...@@ -105,6 +117,10 @@ static void markPhase() {
TraceStackGCVisitor visitor(&stack); TraceStackGCVisitor visitor(&stack);
for (auto h : *getRootHandles()) {
visitor.visitPotential(h->value);
}
// if (VERBOSITY()) printf("Found %d roots\n", stack.size()); // if (VERBOSITY()) printf("Found %d roots\n", stack.size());
while (void* p = stack.pop()) { while (void* p = stack.pop()) {
assert(((intptr_t)p) % 8 == 0); assert(((intptr_t)p) % 8 == 0);
......
...@@ -83,6 +83,19 @@ public: ...@@ -83,6 +83,19 @@ public:
// (that should be registerStaticRootPtr) // (that should be registerStaticRootPtr)
void registerStaticRootObj(void* root_obj); void registerStaticRootObj(void* root_obj);
void runCollection(); void runCollection();
// If you want to have a static root "location" where multiple values could be stored, use this:
class StaticRootHandle {
public:
Box* value;
StaticRootHandle();
~StaticRootHandle();
void operator=(Box* b) { value = b; }
operator Box*() { return value; }
};
} }
} }
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
BoxedModule* errno_module;
void setupErrno() {
errno_module = createModule("errno", "__builtin__");
}
}
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/gc_runtime.h"
#include "runtime/inline/boxing.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
BoxedModule* posix_module;
void setupPosix() {
posix_module = createModule("posix", "__builtin__");
}
}
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <algorithm>
#include <cmath> #include <cmath>
#include "core/types.h" #include "core/types.h"
...@@ -87,4 +88,16 @@ void setupSys() { ...@@ -87,4 +88,16 @@ void setupSys() {
sys_module->giveAttr("stdin", new BoxedFile(stdin)); sys_module->giveAttr("stdin", new BoxedFile(stdin));
sys_module->giveAttr("stderr", new BoxedFile(stderr)); sys_module->giveAttr("stderr", new BoxedFile(stderr));
} }
void setupSysEnd() {
BoxedTuple::GCVector builtin_module_names;
for (auto& p : sys_modules_dict->d) {
builtin_module_names.push_back(p.first);
}
std::sort<decltype(builtin_module_names)::iterator, PyLt>(builtin_module_names.begin(), builtin_module_names.end(),
PyLt());
sys_module->giveAttr("builtin_module_names", new BoxedTuple(std::move(builtin_module_names)));
}
} }
...@@ -76,6 +76,7 @@ void force() { ...@@ -76,6 +76,7 @@ void force() {
FORCE(delitem); FORCE(delitem);
FORCE(unaryop); FORCE(unaryop);
FORCE(import); FORCE(import);
FORCE(importFrom);
FORCE(repr); FORCE(repr);
FORCE(isinstance); FORCE(isinstance);
FORCE(yield); FORCE(yield);
...@@ -93,6 +94,9 @@ void force() { ...@@ -93,6 +94,9 @@ void force() {
FORCE(runtimeCall); FORCE(runtimeCall);
FORCE(callattr); FORCE(callattr);
FORCE(raise0);
FORCE(raise1);
FORCE(div_i64_i64); FORCE(div_i64_i64);
FORCE(mod_i64_i64); FORCE(mod_i64_i64);
FORCE(pow_i64_i64); FORCE(pow_i64_i64);
......
...@@ -545,6 +545,7 @@ void setupList() { ...@@ -545,6 +545,7 @@ void setupList() {
list_cls->giveAttr("pop", new BoxedFunction(boxRTFunction((void*)listPop, UNKNOWN, 2, 1, false, false), { None })); list_cls->giveAttr("pop", new BoxedFunction(boxRTFunction((void*)listPop, UNKNOWN, 2, 1, false, false), { None }));
list_cls->giveAttr("append", new BoxedFunction(boxRTFunction((void*)listAppend, NONE, 2))); list_cls->giveAttr("append", new BoxedFunction(boxRTFunction((void*)listAppend, NONE, 2)));
list_cls->giveAttr("extend", new BoxedFunction(boxRTFunction((void*)listIAdd, NONE, 2)));
CLFunction* setitem = createRTFunction(3, 0, false, false); CLFunction* setitem = createRTFunction(3, 0, false, false);
addRTFunction(setitem, (void*)listSetitemInt, NONE, std::vector<ConcreteCompilerType*>{ LIST, BOXED_INT, UNKNOWN }); addRTFunction(setitem, (void*)listSetitemInt, NONE, std::vector<ConcreteCompilerType*>{ LIST, BOXED_INT, UNKNOWN });
......
...@@ -1772,7 +1772,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1772,7 +1772,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
rewrite_args->rewriter->loadConst(0, (intptr_t)closure); rewrite_args->rewriter->loadConst(0, (intptr_t)closure);
if (func->isGenerator) if (func->isGenerator)
rewrite_args->rewriter->loadConst(0, (intptr_t)0 /*generator*/); rewrite_args->rewriter->loadConst(0, (intptr_t)func->isGenerator);
// We might have trouble if we have more output args than input args, // We might have trouble if we have more output args than input args,
// such as if we need more space to pass defaults. // such as if we need more space to pass defaults.
...@@ -1963,7 +1963,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1963,7 +1963,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
return createGenerator(func, oarg1, oarg2, oarg3, oargs); return createGenerator(func, oarg1, oarg2, oarg3, oargs);
} }
return callCLFunc(f, rewrite_args, num_output_args, closure, NULL, oarg1, oarg2, oarg3, oargs); return callCLFunc(f, rewrite_args, num_output_args, closure, (BoxedGenerator*)func->isGenerator, oarg1, oarg2, oarg3, oargs);
} }
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure, Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
...@@ -2981,4 +2981,16 @@ extern "C" Box* import(const std::string* name) { ...@@ -2981,4 +2981,16 @@ extern "C" Box* import(const std::string* name) {
raiseExcHelper(ImportError, "No module named %s", name->c_str()); raiseExcHelper(ImportError, "No module named %s", name->c_str());
} }
extern "C" Box* importFrom(Box* _m, const std::string* name) {
assert(_m->cls == module_cls);
BoxedModule* m = static_cast<BoxedModule*>(_m);
Box* r = m->getattr(*name, NULL, NULL);
if (r)
return r;
raiseExcHelper(ImportError, "cannot import name %s", name->c_str());
}
} }
...@@ -29,7 +29,14 @@ class BoxedList; ...@@ -29,7 +29,14 @@ class BoxedList;
class BoxedString; class BoxedString;
class BoxedGenerator; class BoxedGenerator;
void raiseExc(Box*) __attribute__((__noreturn__)); // user-level raise functions that implement python-level semantics
extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise1(Box*) __attribute__((__noreturn__));
extern "C" void raise2(Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
// helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__)); void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
extern "C" const std::string* getTypeName(Box* o); extern "C" const std::string* getTypeName(Box* o);
...@@ -37,6 +44,7 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls); ...@@ -37,6 +44,7 @@ extern "C" const std::string* getNameOfClass(BoxedClass* cls);
// TODO sort this // TODO sort this
extern "C" void my_assert(bool b); extern "C" void my_assert(bool b);
extern "C" Box* importFrom(Box* obj, const std::string* attr);
extern "C" Box* getattr(Box* obj, const char* attr); extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val); extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" bool nonzero(Box* obj); extern "C" bool nonzero(Box* obj);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "codegen/llvm_interpreter.h" #include "codegen/llvm_interpreter.h"
#include "core/options.h" #include "core/options.h"
#include "gc/collector.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -99,17 +100,27 @@ void unwindExc(Box* exc_obj) { ...@@ -99,17 +100,27 @@ void unwindExc(Box* exc_obj) {
abort(); abort();
} }
void raiseExc(Box* exc_obj) { static std::vector<const LineInfo*> getTracebackEntries();
static gc::StaticRootHandle last_exc;
static std::vector<const LineInfo*> last_tb;
void raiseRaw(Box* exc_obj) __attribute__((__noreturn__));
void raiseRaw(Box* exc_obj) {
// Using libgcc: // Using libgcc:
throw exc_obj; throw exc_obj;
// Using libunwind // Using libunwind
// unwindExc(exc_obj); // unwindExc(exc_obj);
}
abort(); void raiseExc(Box* exc_obj) {
auto entries = getTracebackEntries();
last_tb = std::move(entries);
last_exc = exc_obj;
raiseRaw(exc_obj);
} }
static std::vector<const LineInfo*> last_tb;
void printLastTraceback() { void printLastTraceback() {
fprintf(stderr, "Traceback (most recent call last):\n"); fprintf(stderr, "Traceback (most recent call last):\n");
...@@ -183,10 +194,28 @@ static std::vector<const LineInfo*> getTracebackEntries() { ...@@ -183,10 +194,28 @@ static std::vector<const LineInfo*> getTracebackEntries() {
return entries; return entries;
} }
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) { void raise0() {
auto entries = getTracebackEntries(); raiseRaw(last_exc);
last_tb = std::move(entries); }
void raise1(Box* b) {
if (b->cls == type_cls) {
BoxedClass* c = static_cast<BoxedClass*>(b);
if (isSubclass(c, Exception)) {
auto exc_obj = exceptionNew1(c);
raiseExc(exc_obj);
} else {
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not %s",
getTypeName(b)->c_str());
}
}
// TODO: should only allow throwing of old-style classes or things derived
// from BaseException:
raiseExc(b);
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
if (msg != NULL) { if (msg != NULL) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
...@@ -223,6 +252,8 @@ std::string formatException(Box* b) { ...@@ -223,6 +252,8 @@ std::string formatException(Box* b) {
assert(r->cls == str_cls); assert(r->cls == str_cls);
const std::string* msg = &r->s; const std::string* msg = &r->s;
return *name + ": " + *msg; if (msg->size())
return *name + ": " + *msg;
return *name;
} }
} }
...@@ -191,6 +191,46 @@ extern "C" BoxedString* strMul(BoxedString* lhs, BoxedInt* rhs) { ...@@ -191,6 +191,46 @@ extern "C" BoxedString* strMul(BoxedString* lhs, BoxedInt* rhs) {
return new BoxedString(buf); return new BoxedString(buf);
} }
extern "C" Box* strLt(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s < srhs->s);
}
extern "C" Box* strLe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s <= srhs->s);
}
extern "C" Box* strGt(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s > srhs->s);
}
extern "C" Box* strGe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s >= srhs->s);
}
extern "C" Box* strEq(BoxedString* lhs, Box* rhs) { extern "C" Box* strEq(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls); assert(lhs->cls == str_cls);
...@@ -201,6 +241,16 @@ extern "C" Box* strEq(BoxedString* lhs, Box* rhs) { ...@@ -201,6 +241,16 @@ extern "C" Box* strEq(BoxedString* lhs, Box* rhs) {
return boxBool(lhs->s == srhs->s); return boxBool(lhs->s == srhs->s);
} }
extern "C" Box* strNe(BoxedString* lhs, Box* rhs) {
assert(lhs->cls == str_cls);
if (rhs->cls != str_cls)
return boxBool(true);
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s != srhs->s);
}
extern "C" Box* strLen(BoxedString* self) { extern "C" Box* strLen(BoxedString* self) {
assert(self->cls == str_cls); assert(self->cls == str_cls);
...@@ -572,7 +622,14 @@ void setupStr() { ...@@ -572,7 +622,14 @@ void setupStr() {
str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2))); str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2)));
str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2))); str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2)));
str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2))); str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
str_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)strLt, UNKNOWN, 2)));
str_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)strLe, UNKNOWN, 2)));
str_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)strGt, UNKNOWN, 2)));
str_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)strGe, UNKNOWN, 2)));
str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, UNKNOWN, 2))); str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, UNKNOWN, 2)));
str_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)strNe, UNKNOWN, 2)));
str_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)strGetitem, STR, 2))); str_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)strGetitem, STR, 2)));
str_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)strIter, typeFromClass(str_iterator_cls), 1))); str_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)strIter, typeFromClass(str_iterator_cls), 1)));
......
...@@ -652,9 +652,13 @@ void setupRuntime() { ...@@ -652,9 +652,13 @@ void setupRuntime() {
setupMath(); setupMath();
setupTime(); setupTime();
setupThread(); setupThread();
setupErrno();
setupPosix();
setupCAPI(); setupCAPI();
setupSysEnd();
TRACK_ALLOCATIONS = true; TRACK_ALLOCATIONS = true;
} }
......
...@@ -61,6 +61,9 @@ void setupBuiltins(); ...@@ -61,6 +61,9 @@ void setupBuiltins();
void setupMath(); void setupMath();
void setupTime(); void setupTime();
void setupThread(); void setupThread();
void setupErrno();
void setupPosix();
void setupSysEnd();
BoxedDict* getSysModulesDict(); BoxedDict* getSysModulesDict();
BoxedList* getSysPath(); BoxedList* getSysPath();
......
# expected: fail
# - WIP
X = 0 X = 0
Y = 0 Y = 0
Z = 0 Z = 0
...@@ -37,10 +34,10 @@ def wrapper(): ...@@ -37,10 +34,10 @@ def wrapper():
# The defaults for a and b should resolve to the classdef definitions, and the default # The defaults for a and b should resolve to the classdef definitions, and the default
# for c should resolve to the wrapper() definition # for c should resolve to the wrapper() definition
def f(self, a=X, b=Y, c=Z, d=W): def f(self, a=X, b=Y, c=Z, d=W):
print a, b, c, W # "2 2 0 1" print a, b, c, d # "2 2 0 1"
# These references should skip all of the classdef directives, # These references should skip all of the classdef directives,
# and hit the definitions in the wrapper() function # and hit the definitions in the wrapper() function
print X, Y # "1 1" print X, Y, Z, W # "1 1 1 1"
print "done with classdef" print "done with classdef"
print hasattr(C, 'X') print hasattr(C, 'X')
......
# expected: fail
# - decorators
def f(o, msg):
print msg
return o
@f(lambda c: f(c, "calling decorator"), "evaluating decorator object")
class C(f(object, "evaluating base")):
print "in classdef"
x3 = 0
def bad_addr3(_x):
if 0:
x3 = _
def g(y3):
return x3 + y3
return g
print bad_addr3(1)(2)
...@@ -43,11 +43,29 @@ def make_addr3(x3): ...@@ -43,11 +43,29 @@ def make_addr3(x3):
return g return g
print make_addr3(10)(2) print make_addr3(10)(2)
def bad_addr3(_x): def f4(args):
if 0: def inner():
x3 = _ for a in args:
print a
return inner
print f4([1, 2, 3])()
def g(y3): def f5():
return x3 + y3 x = 12039
return g def i1():
print bad_addr3(1)(2) def i2():
print x
i2()
i1()
f5()
def f6():
x = 131
# Regression test:
# default args shouldn't mess with closure analysis
def inner(a=1):
print x
inner()
print (lambda a=1: x)()
f6()
# expected: fail
# - deletes on names
x = 1
def f():
if 0:
# the del marks 'x' as a name written to in this scope
del x
print x
f()
...@@ -15,3 +15,12 @@ del a[:] ...@@ -15,3 +15,12 @@ del a[:]
print a print a
a.append(1) a.append(1)
print a print a
# Make sure that del's work correctly in sub-scopes:
x = 1
def f1():
x = range(5)
def f2():
del x[1]
return f2
f1()()
try:
import non_existent_module
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from non_existent_module import a
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from sys import non_existent_attribute
assert 0, "shouldn't get here"
except ImportError:
pass
...@@ -67,3 +67,7 @@ for i in xrange(100): ...@@ -67,3 +67,7 @@ for i in xrange(100):
l.append(i) l.append(i)
while l: while l:
del l[0] del l[0]
l = range(5)
l.extend(range(5))
print l
...@@ -39,3 +39,17 @@ for c in "hello world": ...@@ -39,3 +39,17 @@ for c in "hello world":
for i in xrange(1, 10): for i in xrange(1, 10):
for j in xrange(1, 4): for j in xrange(1, 4):
print ("a"*i).count("a"*j) print ("a"*i).count("a"*j)
def test_comparisons(a, b):
print "%s < %s = " % (a, b), a < b
print "%s <= %s = " % (a, b), a <= b
print "%s > %s = " % (a, b), a > b
print "%s >= %s = " % (a, b), a >= b
print "%s == %s = " % (a, b), a == b
print "%s != %s = " % (a, b), a != b
test_comparisons("a", "a")
test_comparisons("a", "A")
test_comparisons("a", "aa")
test_comparisons("ab", "aa")
print sorted([str(i) for i in xrange(25)])
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