Commit e16e0775 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #318 from undingen/getiter2

Add compvars and rewriting support for GET_ITER nodes 
parents f7ed69df 07978243
...@@ -365,8 +365,9 @@ private: ...@@ -365,8 +365,9 @@ private:
return BOOL; return BOOL;
case AST_LangPrimitive::LOCALS: case AST_LangPrimitive::LOCALS:
return DICT; return DICT;
case AST_LangPrimitive::LANDINGPAD:
case AST_LangPrimitive::GET_ITER: case AST_LangPrimitive::GET_ITER:
return getType(node->args[0])->getPystonIterType();
case AST_LangPrimitive::LANDINGPAD:
case AST_LangPrimitive::IMPORT_FROM: case AST_LangPrimitive::IMPORT_FROM:
case AST_LangPrimitive::IMPORT_STAR: case AST_LangPrimitive::IMPORT_STAR:
case AST_LangPrimitive::IMPORT_NAME: case AST_LangPrimitive::IMPORT_NAME:
......
...@@ -34,6 +34,29 @@ ...@@ -34,6 +34,29 @@
namespace pyston { namespace pyston {
static const std::string& iter_str = "__iter__";
static const std::string& hasnext_str = "__hasnext__";
CompilerType* CompilerType::getPystonIterType() {
if (hasattr(&iter_str) == Yes) {
CompilerType* iter_type = getattrType(&iter_str, true)->callType(ArgPassSpec(0), {}, NULL);
if (iter_type->hasattr(&hasnext_str) == Yes)
return iter_type;
// if iter_type->hasattr(&hasnext_str) == No we know this is going to be a BoxedIterWrapper
// we could optimize this case but it looks like this is very uncommon
}
return UNKNOWN;
}
CompilerType::Result CompilerType::hasattr(const std::string* attr) {
CompilerType* type = getattrType(attr, true);
if (type == UNKNOWN)
return Result::Maybe;
else if (type == UNDEF)
return Result::No;
return Result::Yes;
}
void ConcreteCompilerType::serializeToFrame(VAR* var, std::vector<llvm::Value*>& stackmap_args) { void ConcreteCompilerType::serializeToFrame(VAR* var, std::vector<llvm::Value*>& stackmap_args) {
#ifndef NDEBUG #ifndef NDEBUG
if (llvmType() == g.i1) { if (llvmType() == g.i1) {
...@@ -210,7 +233,7 @@ public: ...@@ -210,7 +233,7 @@ public:
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override; const std::vector<const std::string*>* keyword_names) override;
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override; const std::vector<const std::string*>* keyword_names) override;
ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override; ConcreteCompilerVariable* nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override;
...@@ -330,6 +353,57 @@ public: ...@@ -330,6 +353,57 @@ public:
return new ConcreteCompilerVariable(UNKNOWN, rtn, true); return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
} }
CompilerVariable* getPystonIter(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override {
CallattrFlags flags = {.cls_only = true, .null_on_nonexistent = true };
CompilerVariable* iter_call = var->callattr(emitter, info, &iter_str, flags, ArgPassSpec(0), {}, 0);
ConcreteCompilerVariable* converted_iter_call = iter_call->makeConverted(emitter, iter_call->getBoxType());
// If the type analysis could determine the iter type is a valid pyston iter (has 'hasnext') we are finished.
CompilerType* iter_type = var->getType()->getPystonIterType();
if (iter_type != UNKNOWN) {
iter_call->decvref(emitter);
return converted_iter_call;
}
// We don't know the type so we have to check at runtime if __iter__ is implemented
llvm::Value* cmp = emitter.getBuilder()->CreateICmpNE(converted_iter_call->getValue(),
embedConstantPtr(0, g.llvm_value_type_ptr));
llvm::BasicBlock* bb_has_iter = emitter.createBasicBlock("has_iter");
bb_has_iter->moveAfter(emitter.currentBasicBlock());
llvm::BasicBlock* bb_no_iter = emitter.createBasicBlock("no_iter");
bb_no_iter->moveAfter(bb_has_iter);
llvm::BasicBlock* bb_join = emitter.createBasicBlock("join_after_getiter");
emitter.getBuilder()->CreateCondBr(cmp, bb_has_iter, bb_no_iter);
// var has __iter__()
emitter.setCurrentBasicBlock(bb_has_iter);
ICSetupInfo* pp = createGenericIC(info.getTypeRecorder(), true, 128);
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::createBoxedIterWrapperIfNeeded,
{ converted_iter_call->getValue() }, info.unw_info);
llvm::Value* value_has_iter = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
llvm::BasicBlock* value_has_iter_bb = emitter.currentBasicBlock();
emitter.getBuilder()->CreateBr(bb_join);
// var has no __iter__()
// TODO: we could create a patchpoint if this turns out to be hot
emitter.setCurrentBasicBlock(bb_no_iter);
llvm::Value* value_no_iter = emitter.createCall(info.unw_info, g.funcs.getiterHelper, var->getValue());
llvm::BasicBlock* value_no_iter_bb = emitter.currentBasicBlock();
emitter.getBuilder()->CreateBr(bb_join);
// join
emitter.setCurrentBasicBlock(bb_join);
auto phi = emitter.getBuilder()->CreatePHI(g.llvm_value_type_ptr, 2, "iter");
phi->addIncoming(value_has_iter, value_has_iter_bb);
phi->addIncoming(value_no_iter, value_no_iter_bb);
converted_iter_call->decvref(emitter);
iter_call->decvref(emitter);
return new ConcreteCompilerVariable(UNKNOWN, phi, true);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs, CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override { AST_TYPE::AST_TYPE op_type, BinExpType exp_type) override {
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType()); ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
...@@ -579,7 +653,7 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc ...@@ -579,7 +653,7 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc
} }
CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, 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) {
bool pass_keywords = (argspec.num_keywords != 0); bool pass_keywords = (argspec.num_keywords != 0);
...@@ -599,10 +673,17 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ...@@ -599,10 +673,17 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
else else
func = g.funcs.callattrN; func = g.funcs.callattrN;
union {
CallattrFlags flags;
char value;
} flags_to_int;
static_assert(sizeof(CallattrFlags) == sizeof(char), "");
flags_to_int.flags = flags;
std::vector<llvm::Value*> other_args; std::vector<llvm::Value*> other_args;
other_args.push_back(var->getValue()); other_args.push_back(var->getValue());
other_args.push_back(embedConstantPtr(attr, g.llvm_str_type_ptr)); other_args.push_back(embedConstantPtr(attr, g.llvm_str_type_ptr));
other_args.push_back(getConstantInt(clsonly, g.i1)); other_args.push_back(getConstantInt(flags_to_int.value, g.i8));
llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false); llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false);
other_args.push_back(llvm_argspec); other_args.push_back(llvm_argspec);
...@@ -819,11 +900,11 @@ public: ...@@ -819,11 +900,11 @@ public:
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); CompilerVariable* rtn = converted->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1057,11 +1138,11 @@ public: ...@@ -1057,11 +1138,11 @@ public:
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT); ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_FLOAT);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); CompilerVariable* rtn = converted->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1523,16 +1604,16 @@ public: ...@@ -1523,16 +1604,16 @@ public:
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
ConcreteCompilerVariable* called_constant ConcreteCompilerVariable* called_constant
= tryCallattrConstant(emitter, info, var, attr, clsonly, argspec, args, keyword_names); = tryCallattrConstant(emitter, info, var, attr, flags.cls_only, argspec, args, keyword_names);
if (called_constant) if (called_constant)
return called_constant; return called_constant;
ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN); ConcreteCompilerVariable* converted = var->makeConverted(emitter, UNKNOWN);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); CompilerVariable* rtn = converted->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1551,6 +1632,7 @@ public: ...@@ -1551,6 +1632,7 @@ public:
const std::string& left_side_name = getOpName(op_type); const std::string& left_side_name = getOpName(op_type);
bool no_attribute = false; bool no_attribute = false;
ConcreteCompilerVariable* called_constant ConcreteCompilerVariable* called_constant
= tryCallattrConstant(emitter, info, var, &left_side_name, true, ArgPassSpec(1, 0, 0, 0), = tryCallattrConstant(emitter, info, var, &left_side_name, true, ArgPassSpec(1, 0, 0, 0),
{ converted_rhs }, NULL, &no_attribute); { converted_rhs }, NULL, &no_attribute);
...@@ -1599,6 +1681,10 @@ public: ...@@ -1599,6 +1681,10 @@ public:
return UNKNOWN->getitem(emitter, info, var, slice); return UNKNOWN->getitem(emitter, info, var, slice);
} }
CompilerVariable* getPystonIter(IREmitter& emitter, const OpInfo& info, VAR* var) override {
return UNKNOWN->getPystonIter(emitter, info, var);
}
ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* var) override { ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, VAR* var) override {
static const std::string attr("__len__"); static const std::string attr("__len__");
ConcreteCompilerVariable* called_constant ConcreteCompilerVariable* called_constant
...@@ -1741,11 +1827,11 @@ public: ...@@ -1741,11 +1827,11 @@ public:
return rtn; return rtn;
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, bool clsonly, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, CallattrFlags flags, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, STR); ConcreteCompilerVariable* converted = var->makeConverted(emitter, STR);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); CompilerVariable* rtn = converted->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -1870,11 +1956,11 @@ public: ...@@ -1870,11 +1956,11 @@ public:
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool clsonly, ArgPassSpec argspec, const std::string* attr, CallattrFlags flags, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_BOOL); ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_BOOL);
CompilerVariable* rtn = converted->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); CompilerVariable* rtn = converted->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
converted->decvref(emitter); converted->decvref(emitter);
return rtn; return rtn;
} }
...@@ -2043,11 +2129,11 @@ public: ...@@ -2043,11 +2129,11 @@ public:
return rtn; return rtn;
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, bool clsonly, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, CallattrFlags flags, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
return makeConverted(emitter, var, getConcreteType()) return makeConverted(emitter, var, getConcreteType())
->callattr(emitter, info, attr, clsonly, argspec, args, keyword_names); ->callattr(emitter, info, attr, flags, argspec, args, keyword_names);
} }
void serializeToFrame(VAR* var, std::vector<llvm::Value*>& stackmap_args) override { void serializeToFrame(VAR* var, std::vector<llvm::Value*>& stackmap_args) override {
...@@ -2147,8 +2233,8 @@ public: ...@@ -2147,8 +2233,8 @@ public:
return undefVariable(); return undefVariable();
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr, bool clsonly, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, VAR* var, const std::string* attr,
ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, CallattrFlags flags, ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
return undefVariable(); return undefVariable();
} }
......
...@@ -36,14 +36,19 @@ typedef llvm::SmallVector<uint64_t, 1> FrameVals; ...@@ -36,14 +36,19 @@ typedef llvm::SmallVector<uint64_t, 1> FrameVals;
class CompilerType { class CompilerType {
public: public:
enum Result { Yes, No, Maybe };
virtual ~CompilerType() {} virtual ~CompilerType() {}
virtual std::string debugName() = 0; virtual std::string debugName() = 0;
virtual ConcreteCompilerType* getConcreteType() = 0; virtual ConcreteCompilerType* getConcreteType() = 0;
virtual ConcreteCompilerType* getBoxType() = 0; virtual ConcreteCompilerType* getBoxType() = 0;
virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0; virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0;
virtual CompilerType* getattrType(const std::string* attr, bool cls_only) = 0; virtual CompilerType* getattrType(const std::string* attr, bool cls_only) = 0;
virtual CompilerType* getPystonIterType();
virtual Result hasattr(const std::string* attr);
virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types, virtual CompilerType* callType(ArgPassSpec argspec, const std::vector<CompilerType*>& arg_types,
const std::vector<const std::string*>* keyword_names) = 0; const std::vector<const std::string*>* keyword_names) = 0;
virtual BoxedClass* guaranteedClass() = 0; virtual BoxedClass* guaranteedClass() = 0;
virtual Box* deserializeFromFrame(const FrameVals& vals) = 0; virtual Box* deserializeFromFrame(const FrameVals& vals) = 0;
virtual int numFrameArgs() = 0; virtual int numFrameArgs() = 0;
...@@ -112,7 +117,7 @@ public: ...@@ -112,7 +117,7 @@ public:
} }
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, struct ArgPassSpec argspec, CallattrFlags flags, 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());
...@@ -135,6 +140,7 @@ public: ...@@ -135,6 +140,7 @@ public:
printf("getitem not defined for %s\n", debugName().c_str()); printf("getitem not defined for %s\n", debugName().c_str());
abort(); abort();
} }
virtual CompilerVariable* getPystonIter(IREmitter& emitter, const OpInfo& info, VAR* var);
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs, virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) { AST_TYPE::AST_TYPE op_type, BinExpType exp_type) {
printf("binexp not defined for %s\n", debugName().c_str()); printf("binexp not defined for %s\n", debugName().c_str());
...@@ -254,14 +260,16 @@ public: ...@@ -254,14 +260,16 @@ public:
= 0; = 0;
virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0; virtual void setattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CompilerVariable* v) = 0;
virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) = 0; virtual void delattr(IREmitter& emitter, const OpInfo& info, const std::string* attr) = 0;
virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly, virtual CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, CallattrFlags flags, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) = 0; const std::vector<const std::string*>* keyword_names) = 0;
virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec, virtual CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) = 0; const std::vector<const std::string*>* keyword_names) = 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* getPystonIter(IREmitter& emitter, const OpInfo& info) = 0;
virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, virtual CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs,
AST_TYPE::AST_TYPE op_type, BinExpType exp_type) = 0; AST_TYPE::AST_TYPE op_type, BinExpType exp_type) = 0;
...@@ -330,10 +338,10 @@ public: ...@@ -330,10 +338,10 @@ public:
type->delattr(emitter, info, this, attr); type->delattr(emitter, info, this, attr);
} }
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, bool clsonly, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, const std::string* attr, CallattrFlags flags,
struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args, struct ArgPassSpec argspec, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names) override { const std::vector<const std::string*>* keyword_names) override {
return type->callattr(emitter, info, this, attr, clsonly, argspec, args, keyword_names); return type->callattr(emitter, info, this, attr, flags, argspec, args, keyword_names);
} }
CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec, CompilerVariable* call(IREmitter& emitter, const OpInfo& info, struct ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
...@@ -346,7 +354,9 @@ public: ...@@ -346,7 +354,9 @@ 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* getPystonIter(IREmitter& emitter, const OpInfo& info) override {
return type->getPystonIter(emitter, info, this);
}
CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, AST_TYPE::AST_TYPE op_type, CompilerVariable* binexp(IREmitter& emitter, const OpInfo& info, CompilerVariable* rhs, AST_TYPE::AST_TYPE op_type,
BinExpType exp_type) override { BinExpType exp_type) override {
return type->binexp(emitter, info, this, rhs, op_type, exp_type); return type->binexp(emitter, info, this, rhs, op_type, exp_type);
...@@ -392,6 +402,14 @@ CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<Con ...@@ -392,6 +402,14 @@ CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<Con
ConcreteCompilerVariable* boolFromI1(IREmitter&, llvm::Value*); ConcreteCompilerVariable* boolFromI1(IREmitter&, llvm::Value*);
llvm::Value* i1FromBool(IREmitter&, ConcreteCompilerVariable*); llvm::Value* i1FromBool(IREmitter&, ConcreteCompilerVariable*);
template <typename V>
CompilerVariable* _ValuedCompilerType<V>::getPystonIter(IREmitter& emitter, const OpInfo& info, VAR* var) {
ConcreteCompilerVariable* converted = makeConverted(emitter, var, getBoxType());
auto r = UNKNOWN->getPystonIter(emitter, info, converted);
converted->decvref(emitter);
return r;
}
template <typename V> template <typename V>
std::vector<CompilerVariable*> _ValuedCompilerType<V>::unpack(IREmitter& emitter, const OpInfo& info, VAR* var, std::vector<CompilerVariable*> _ValuedCompilerType<V>::unpack(IREmitter& emitter, const OpInfo& info, VAR* var,
int num_into) { int num_into) {
......
...@@ -68,8 +68,11 @@ public: ...@@ -68,8 +68,11 @@ public:
virtual IRBuilder* getBuilder() = 0; virtual IRBuilder* getBuilder() = 0;
virtual GCBuilder* getGC() = 0; virtual GCBuilder* getGC() = 0;
virtual CompiledFunction* currentFunction() = 0; virtual CompiledFunction* currentFunction() = 0;
virtual llvm::BasicBlock* currentBasicBlock() = 0;
virtual llvm::BasicBlock* createBasicBlock(const char* name = "") = 0; virtual llvm::BasicBlock* createBasicBlock(const char* name = "") = 0;
virtual void setCurrentBasicBlock(llvm::BasicBlock*) = 0;
virtual llvm::Value* getScratch(int num_bytes) = 0; virtual llvm::Value* getScratch(int num_bytes) = 0;
virtual void releaseScratch(llvm::Value*) = 0; virtual void releaseScratch(llvm::Value*) = 0;
......
...@@ -127,9 +127,6 @@ private: ...@@ -127,9 +127,6 @@ private:
} }
} }
llvm::BasicBlock* createBasicBlock(const char* name) override {
return llvm::BasicBlock::Create(g.context, name, irstate->getLLVMFunction());
}
llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func, llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func,
const std::vector<llvm::Value*>& args, const std::vector<llvm::Value*>& args,
...@@ -194,6 +191,16 @@ public: ...@@ -194,6 +191,16 @@ public:
void releaseScratch(llvm::Value* scratch) override { assert(0); } void releaseScratch(llvm::Value* scratch) override { assert(0); }
CompiledFunction* currentFunction() override { return irstate->getCurFunction(); } CompiledFunction* currentFunction() override { return irstate->getCurFunction(); }
llvm::BasicBlock* currentBasicBlock() override { return curblock; }
void setCurrentBasicBlock(llvm::BasicBlock* bb) override {
curblock = bb;
getBuilder()->SetInsertPoint(curblock);
}
llvm::BasicBlock* createBasicBlock(const char* name) override {
return llvm::BasicBlock::Create(g.context, name, irstate->getLLVMFunction());
}
llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) override { llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) override {
if (ENABLE_FRAME_INTROSPECTION) { if (ENABLE_FRAME_INTROSPECTION) {
...@@ -457,8 +464,9 @@ private: ...@@ -457,8 +464,9 @@ private:
ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType()); ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
// TODO super dumb that it reallocates the name again // TODO super dumb that it reallocates the name again
CallattrFlags flags = {.cls_only = true, .null_on_nonexistent = false };
CompilerVariable* _r CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, true, ArgPassSpec(2), = rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, flags, ArgPassSpec(2),
{ makeStr(new std::string(p.first.str())), converted }, NULL); { makeStr(new std::string(p.first.str())), converted }, NULL);
converted->decvref(emitter); converted->decvref(emitter);
_r->decvref(emitter); _r->decvref(emitter);
...@@ -474,8 +482,9 @@ private: ...@@ -474,8 +482,9 @@ private:
emitter.getBuilder()->SetInsertPoint(was_defined); emitter.getBuilder()->SetInsertPoint(was_defined);
ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType()); ConcreteCompilerVariable* converted = p.second->makeConverted(emitter, p.second->getBoxType());
// TODO super dumb that it reallocates the name again // TODO super dumb that it reallocates the name again
CallattrFlags flags = {.cls_only = true, .null_on_nonexistent = false };
CompilerVariable* _r CompilerVariable* _r
= rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, true, ArgPassSpec(2), = rtn->callattr(emitter, getEmptyOpInfo(unw_info), &setitem_str, flags, ArgPassSpec(2),
{ makeStr(new std::string(p.first.str())), converted }, NULL); { makeStr(new std::string(p.first.str())), converted }, NULL);
converted->decvref(emitter); converted->decvref(emitter);
_r->decvref(emitter); _r->decvref(emitter);
...@@ -487,24 +496,11 @@ private: ...@@ -487,24 +496,11 @@ private:
return rtn; return rtn;
} }
case AST_LangPrimitive::GET_ITER: { case AST_LangPrimitive::GET_ITER: {
// TODO if this is a type that has an __iter__, we could do way better than this, both in terms of
// function call overhead and resulting type information, if we went with that instead of the generic
// version.
// (ie we can inline getPystonIter here, whether mechanically with LLVM [would require adding more
// optimization passes to make it fast] or by-hand)
//
// TODO Move this behavior into to the type-specific section (compvars.cpp)?
emitter.getBuilder();
assert(node->args.size() == 1); assert(node->args.size() == 1);
CompilerVariable* obj = evalExpr(node->args[0], unw_info); CompilerVariable* obj = evalExpr(node->args[0], unw_info);
auto rtn = obj->getPystonIter(emitter, getOpInfoForNode(node, unw_info));
ConcreteCompilerVariable* converted_obj = obj->makeConverted(emitter, obj->getBoxType());
obj->decvref(emitter); obj->decvref(emitter);
return rtn;
llvm::Value* v = emitter.createCall(unw_info, g.funcs.getPystonIter, converted_obj->getValue());
assert(v->getType() == g.llvm_value_type_ptr);
return new ConcreteCompilerVariable(UNKNOWN, v, true);
} }
case AST_LangPrimitive::IMPORT_FROM: { case AST_LangPrimitive::IMPORT_FROM: {
assert(node->args.size() == 2); assert(node->args.size() == 2);
...@@ -748,8 +744,8 @@ private: ...@@ -748,8 +744,8 @@ private:
CompilerVariable* rtn; CompilerVariable* rtn;
if (is_callattr) { if (is_callattr) {
rtn = func->callattr(emitter, getOpInfoForNode(node, unw_info), attr, callattr_clsonly, argspec, args, CallattrFlags flags = {.cls_only = callattr_clsonly, .null_on_nonexistent = false };
keyword_names); rtn = func->callattr(emitter, getOpInfoForNode(node, unw_info), attr, flags, argspec, args, keyword_names);
} else { } else {
rtn = func->call(emitter, getOpInfoForNode(node, unw_info), argspec, args, keyword_names); rtn = func->call(emitter, getOpInfoForNode(node, unw_info), argspec, args, keyword_names);
} }
...@@ -976,8 +972,8 @@ private: ...@@ -976,8 +972,8 @@ private:
for (int i = 0; i < node->elts.size(); i++) { for (int i = 0; i < node->elts.size(); i++) {
CompilerVariable* elt = elts[i]; CompilerVariable* elt = elts[i];
CallattrFlags flags = {.cls_only = true, .null_on_nonexistent = false };
CompilerVariable* r = rtn->callattr(emitter, getOpInfoForNode(node, unw_info), &add_str, true, CompilerVariable* r = rtn->callattr(emitter, getOpInfoForNode(node, unw_info), &add_str, flags,
ArgPassSpec(1), { elt }, NULL); ArgPassSpec(1), { elt }, NULL);
r->decvref(emitter); r->decvref(emitter);
elt->decvref(emitter); elt->decvref(emitter);
...@@ -1648,8 +1644,8 @@ private: ...@@ -1648,8 +1644,8 @@ private:
curblock = ss_block; curblock = ss_block;
emitter.getBuilder()->SetInsertPoint(ss_block); emitter.getBuilder()->SetInsertPoint(ss_block);
CallattrFlags flags = {.cls_only = false, .null_on_nonexistent = false };
auto r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, false, ArgPassSpec(1), auto r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, flags, ArgPassSpec(1),
{ makeStr(&space_str) }, NULL); { makeStr(&space_str) }, NULL);
r->decvref(emitter); r->decvref(emitter);
...@@ -1662,7 +1658,7 @@ private: ...@@ -1662,7 +1658,7 @@ private:
llvm::Value* v = emitter.createCall(unw_info, g.funcs.str, converted->getValue()); llvm::Value* v = emitter.createCall(unw_info, g.funcs.str, converted->getValue());
v = emitter.getBuilder()->CreateBitCast(v, g.llvm_value_type_ptr); v = emitter.getBuilder()->CreateBitCast(v, g.llvm_value_type_ptr);
auto s = new ConcreteCompilerVariable(STR, v, true); auto s = new ConcreteCompilerVariable(STR, v, true);
r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, false, ArgPassSpec(1), { s }, r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, flags, ArgPassSpec(1), { s },
NULL); NULL);
s->decvref(emitter); s->decvref(emitter);
r->decvref(emitter); r->decvref(emitter);
...@@ -1670,7 +1666,8 @@ private: ...@@ -1670,7 +1666,8 @@ private:
} }
if (node->nl) { if (node->nl) {
auto r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, false, ArgPassSpec(1), CallattrFlags flags = {.cls_only = false, .null_on_nonexistent = false };
auto r = dest->callattr(emitter, getOpInfoForNode(node, unw_info), &write_str, flags, ArgPassSpec(1),
{ makeStr(&newline_str) }, NULL); { makeStr(&newline_str) }, NULL);
r->decvref(emitter); r->decvref(emitter);
......
...@@ -208,7 +208,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -208,7 +208,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(str); GET(str);
GET(isinstance); GET(isinstance);
GET(yield); GET(yield);
GET(getPystonIter); GET(getiterHelper);
GET(unpackIntoArray); GET(unpackIntoArray);
GET(raiseAttributeError); GET(raiseAttributeError);
......
...@@ -38,7 +38,7 @@ struct GlobalFuncs { ...@@ -38,7 +38,7 @@ struct GlobalFuncs {
*decodeUTF8StringPtr; *decodeUTF8StringPtr;
llvm::Value* getattr, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, *augbinop, *unboxedLen, llvm::Value* getattr, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, *augbinop, *unboxedLen,
*getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *importStar, *repr, *str, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *importStar, *repr, *str,
*isinstance, *yield, *getPystonIter; *isinstance, *yield, *getiterHelper;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError,
*assertNameDefined, *assertFail; *assertNameDefined, *assertFail;
......
...@@ -557,6 +557,11 @@ struct FrameInfo { ...@@ -557,6 +557,11 @@ struct FrameInfo {
FrameInfo(ExcInfo exc) : exc(exc) {} FrameInfo(ExcInfo exc) : exc(exc) {}
}; };
struct CallattrFlags {
bool cls_only : 1;
bool null_on_nonexistent : 1;
};
} }
#endif #endif
...@@ -89,7 +89,7 @@ void force() { ...@@ -89,7 +89,7 @@ void force() {
FORCE(str); FORCE(str);
FORCE(isinstance); FORCE(isinstance);
FORCE(yield); FORCE(yield);
FORCE(getPystonIter); FORCE(getiterHelper);
FORCE(unpackIntoArray); FORCE(unpackIntoArray);
FORCE(raiseAttributeError); FORCE(raiseAttributeError);
......
...@@ -3471,6 +3471,41 @@ extern "C" void delattr(Box* obj, const char* attr) { ...@@ -3471,6 +3471,41 @@ extern "C" void delattr(Box* obj, const char* attr) {
delattr_internal(obj, attr, true, NULL); delattr_internal(obj, attr, true, NULL);
} }
extern "C" Box* createBoxedIterWrapper(Box* o) {
return new BoxedIterWrapper(o);
}
extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) {
std::unique_ptr<Rewriter> rewriter(Rewriter::createRewriter(
__builtin_extract_return_addr(__builtin_return_address(0)), 1, "createBoxedIterWrapperIfNeeded"));
if (rewriter.get()) {
RewriterVar* r_o = rewriter->getArg(0);
RewriterVar* r_cls = r_o->getAttr(BOX_CLS_OFFSET);
GetattrRewriteArgs rewrite_args(rewriter.get(), r_cls, rewriter->getReturnDestination());
Box* r = typeLookup(o->cls, hasnext_str, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else if (r) {
rewrite_args.out_rtn->addGuard((uint64_t)r);
if (rewrite_args.out_success) {
rewriter->commitReturning(r_o);
return o;
}
} else if (!r) {
RewriterVar* var = rewriter.get()->call(true, (void*)createBoxedIterWrapper, rewriter->getArg(0));
if (rewrite_args.out_success) {
rewriter->commitReturning(var);
return createBoxedIterWrapper(o);
}
}
}
if (typeLookup(o->cls, hasnext_str, NULL) == NULL)
return new BoxedIterWrapper(o);
return o;
}
extern "C" Box* getPystonIter(Box* o) { extern "C" Box* getPystonIter(Box* o) {
Box* r = getiter(o); Box* r = getiter(o);
if (typeLookup(r->cls, hasnext_str, NULL) == NULL) if (typeLookup(r->cls, hasnext_str, NULL) == NULL)
...@@ -3478,17 +3513,18 @@ extern "C" Box* getPystonIter(Box* o) { ...@@ -3478,17 +3513,18 @@ extern "C" Box* getPystonIter(Box* o) {
return r; return r;
} }
extern "C" Box* getiterHelper(Box* o) {
if (typeLookup(o->cls, getitem_str, NULL))
return new BoxedSeqIter(o, 0);
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
}
Box* getiter(Box* o) { Box* getiter(Box* o) {
// TODO add rewriting to this? probably want to try to avoid this path though // TODO add rewriting to this? probably want to try to avoid this path though
Box* r = callattrInternal0(o, &iter_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(0)); Box* r = callattrInternal0(o, &iter_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(0));
if (r) if (r)
return r; return r;
return getiterHelper(o);
if (typeLookup(o->cls, getitem_str, NULL)) {
return new BoxedSeqIter(o, 0);
}
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
} }
llvm::iterator_range<BoxIterator> Box::pyElements() { llvm::iterator_range<BoxIterator> Box::pyElements() {
......
...@@ -53,10 +53,6 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val); ...@@ -53,10 +53,6 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" void delattr(Box* obj, const char* attr); extern "C" void delattr(Box* obj, const char* attr);
extern "C" bool nonzero(Box* obj); extern "C" bool nonzero(Box* obj);
extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*); extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*);
struct CallattrFlags {
bool cls_only : 1;
bool null_on_nonexistent : 1;
};
extern "C" Box* callattr(Box*, const std::string*, CallattrFlags, ArgPassSpec, Box*, Box*, Box*, Box**, extern "C" Box* callattr(Box*, const std::string*, CallattrFlags, ArgPassSpec, Box*, Box*, Box*, Box**,
const std::vector<const std::string*>*); const std::vector<const std::string*>*);
extern "C" BoxedString* str(Box* obj); extern "C" BoxedString* str(Box* obj);
...@@ -92,6 +88,8 @@ extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure); ...@@ -92,6 +88,8 @@ extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
Box* getiter(Box* o); Box* getiter(Box* o);
extern "C" Box* getPystonIter(Box* o); extern "C" Box* getPystonIter(Box* o);
extern "C" Box* getiterHelper(Box* o);
extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o);
extern "C" void dump(void* p); extern "C" void dump(void* p);
......
...@@ -228,7 +228,7 @@ public: ...@@ -228,7 +228,7 @@ public:
// that we can't rely on for extension classes. // that we can't rely on for extension classes.
bool is_pyston_class; bool is_pyston_class;
bool hasGenericGetattr() { return tp_getattr != NULL; } bool hasGenericGetattr() { return tp_getattr == NULL; }
void freeze(); void freeze();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# statcheck: "-O" in EXTRA_JIT_ARGS or 'slowpath_getclsattr' in stats or 'slowpath_callattr' in stats # statcheck: "-O" in EXTRA_JIT_ARGS or 'slowpath_getclsattr' in stats or 'slowpath_callattr' in stats
# statcheck: stats.get('slowpath_getclsattr', 0) <= 20 # statcheck: stats.get('slowpath_getclsattr', 0) <= 20
# statcheck: stats.get('slowpath_callattr', 0) <= 20 # statcheck: stats.get('slowpath_callattr', 0) <= 22
for i in xrange(1000): for i in xrange(1000):
print i print i
......
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