#include "irtools.h" #include namespace codon { namespace ir { namespace util { bool hasAttribute(const Func *func, const std::string &attribute) { if (auto *attr = func->getAttribute()) { return attr->has(attribute); } return false; } bool isStdlibFunc(const Func *func, const std::string &submodule) { if (auto *attr = func->getAttribute()) { std::string module = attr->get(".module"); return module.rfind("std::" + submodule, 0) == 0; } return false; } CallInstr *call(Func *func, const std::vector &args) { auto *M = func->getModule(); return M->Nr(M->Nr(func), args); } bool isCallOf(const Value *value, const std::string &name, const std::vector &inputs, types::Type *output, bool method) { if (auto *call = cast(value)) { auto *fn = getFunc(call->getCallee()); if (!fn || fn->getUnmangledName() != name || call->numArgs() != inputs.size()) return false; unsigned i = 0; for (auto *arg : *call) { if (!arg->getType()->is(inputs[i++])) return false; } if (output && !value->getType()->is(output)) return false; if (method && (inputs.empty() || !fn->getParentType() || !fn->getParentType()->is(inputs[0]))) return false; return true; } return false; } bool isCallOf(const Value *value, const std::string &name, int numArgs, types::Type *output, bool method) { if (auto *call = cast(value)) { auto *fn = getFunc(call->getCallee()); if (!fn || fn->getUnmangledName() != name || (numArgs >= 0 && call->numArgs() != numArgs)) return false; if (output && !value->getType()->is(output)) return false; if (method && (!fn->getParentType() || call->numArgs() == 0 || !call->front()->getType()->is(fn->getParentType()))) return false; return true; } return false; } bool isMagicMethodCall(const Value *value) { if (auto *call = cast(value)) { auto *fn = getFunc(call->getCallee()); if (!fn || !fn->getParentType() || call->numArgs() == 0 || !call->front()->getType()->is(fn->getParentType())) return false; auto name = fn->getUnmangledName(); auto size = name.size(); if (size < 5 || !(name[0] == '_' && name[1] == '_' && name[size - 1] == '_' && name[size - 2] == '_')) return false; return true; } return false; } Value *makeTuple(const std::vector &args, Module *M) { if (!M) { seqassert(!args.empty(), "unknown module for empty tuple construction"); M = args[0]->getModule(); } std::vector types; for (auto *arg : args) { types.push_back(arg->getType()); } auto *tupleType = M->getTupleType(types); auto *newFunc = M->getOrRealizeMethod(tupleType, "__new__", types); seqassert(newFunc, "could not realize {} new function", *tupleType); return M->Nr(M->Nr(newFunc), args); } VarValue *makeVar(Value *x, SeriesFlow *flow, BodiedFunc *parent, bool prepend) { const bool global = (parent == nullptr); auto *M = x->getModule(); auto *v = M->Nr(x->getType(), global); if (global) v->setName("_anon_global"); auto *a = M->Nr(v, x); if (prepend) { flow->insert(flow->begin(), a); } else { flow->push_back(a); } if (!global) { parent->push_back(v); } return M->Nr(v); } Value *alloc(types::Type *type, Value *count) { auto *M = type->getModule(); auto *ptrType = M->getPointerType(type); return (*ptrType)(*count); } Value *alloc(types::Type *type, int64_t count) { auto *M = type->getModule(); return alloc(type, M->getInt(count)); } Var *getVar(Value *x) { if (auto *v = cast(x)) { if (auto *var = cast(v->getVar())) { if (!isA(var)) { return var; } } } return nullptr; } const Var *getVar(const Value *x) { if (auto *v = cast(x)) { if (auto *var = cast(v->getVar())) { if (!isA(var)) { return var; } } } return nullptr; } Func *getFunc(Value *x) { if (auto *v = cast(x)) { if (auto *func = cast(v->getVar())) { return func; } } return nullptr; } const Func *getFunc(const Value *x) { if (auto *v = cast(x)) { if (auto *func = cast(v->getVar())) { return func; } } return nullptr; } Value *ptrLoad(Value *ptr) { auto *M = ptr->getModule(); auto *deref = (*ptr)[*M->getInt(0)]; seqassert(deref, "pointer getitem not found"); return deref; } Value *ptrStore(Value *ptr, Value *val) { auto *M = ptr->getModule(); auto *setitem = M->getOrRealizeMethod(ptr->getType(), Module::SETITEM_MAGIC_NAME, {ptr->getType(), M->getIntType(), val->getType()}); seqassert(setitem, "pointer setitem not found"); return call(setitem, {ptr, M->getInt(0), val}); } Value *tupleGet(Value *tuple, unsigned index) { auto *M = tuple->getModule(); return M->Nr(tuple, "item" + std::to_string(index + 1)); } Value *tupleStore(Value *tuple, unsigned index, Value *val) { auto *M = tuple->getModule(); auto *type = cast(tuple->getType()); seqassert(type, "argument is not a tuple"); std::vector newElements; for (unsigned i = 0; i < std::distance(type->begin(), type->end()); i++) { newElements.push_back(i == index ? val : tupleGet(tuple, i)); } return makeTuple(newElements, M); } BodiedFunc *getStdlibFunc(Value *x, const std::string &name, const std::string &submodule) { if (auto *f = getFunc(x)) { if (auto *g = cast(f)) { if (isStdlibFunc(g, submodule) && g->getUnmangledName() == name) { return g; } } } return nullptr; } const BodiedFunc *getStdlibFunc(const Value *x, const std::string &name, const std::string &submodule) { if (auto *f = getFunc(x)) { if (auto *g = cast(f)) { if (isStdlibFunc(g, submodule) && g->getUnmangledName() == name) { return g; } } } return nullptr; } types::Type *getReturnType(const Func *func) { return cast(func->getType())->getReturnType(); } void setReturnType(Func *func, types::Type *rType) { auto *M = func->getModule(); auto *t = cast(func->getType()); seqassert(t, "{} is not a function type", *func->getType()); std::vector argTypes(t->begin(), t->end()); func->setType(M->getFuncType(rType, argTypes)); } } // namespace util } // namespace ir } // namespace codon