in Jit/hir/printer.cpp [231:664]
static std::string format_immediates(const Instr& instr) {
switch (instr.opcode()) {
case Opcode::kAssign:
case Opcode::kBatchDecref:
case Opcode::kBuildString:
case Opcode::kCheckExc:
case Opcode::kCheckNeg:
case Opcode::kCheckSequenceBounds:
case Opcode::kClearError:
case Opcode::kDecref:
case Opcode::kDeleteSubscr:
case Opcode::kDeopt:
case Opcode::kEndInlinedFunction:
case Opcode::kGetIter:
case Opcode::kGetTuple:
case Opcode::kGuard:
case Opcode::kIncref:
case Opcode::kInitFunction:
case Opcode::kInvokeIterNext:
case Opcode::kIsErrStopAsyncIteration:
case Opcode::kIsInstance:
case Opcode::kIsNegativeAndErrOccurred:
case Opcode::kIsSubtype:
case Opcode::kIsTruthy:
case Opcode::kListAppend:
case Opcode::kListExtend:
case Opcode::kLoadCellItem:
case Opcode::kLoadCurrentFunc:
case Opcode::kLoadEvalBreaker:
case Opcode::kLoadFieldAddress:
case Opcode::kLoadVarObjectSize:
case Opcode::kMakeCell:
case Opcode::kMakeFunction:
case Opcode::kMakeSet:
case Opcode::kMakeTupleFromList:
case Opcode::kMergeDictUnpack:
case Opcode::kMergeSetUnpack:
case Opcode::kRaise:
case Opcode::kRepeatList:
case Opcode::kRepeatTuple:
case Opcode::kRunPeriodicTasks:
case Opcode::kSetCurrentAwaiter:
case Opcode::kSetCellItem:
case Opcode::kSetDictItem:
case Opcode::kSetSetItem:
case Opcode::kSnapshot:
case Opcode::kStealCellItem:
case Opcode::kStoreArrayItem:
case Opcode::kStoreSubscr:
case Opcode::kWaitHandleLoadCoroOrResult:
case Opcode::kWaitHandleLoadWaiter:
case Opcode::kWaitHandleRelease:
case Opcode::kXDecref:
case Opcode::kXIncref: {
return "";
}
case Opcode::kBeginInlinedFunction:
return static_cast<const BeginInlinedFunction&>(instr).fullname();
case Opcode::kLoadArrayItem: {
const auto& load = static_cast<const LoadArrayItem&>(instr);
return load.offset() == 0 ? "" : fmt::format("Offset[{}]", load.offset());
}
case Opcode::kReturn: {
const auto& ret = static_cast<const Return&>(instr);
return ret.type() != TObject ? ret.type().toString() : "";
}
case Opcode::kCallEx: {
const auto& call = static_cast<const CallEx&>(instr);
return call.isAwaited() ? "awaited" : "";
}
case Opcode::kCallExKw: {
const auto& call = static_cast<const CallExKw&>(instr);
return call.isAwaited() ? "awaited" : "";
}
case Opcode::kBinaryOp: {
const auto& bin_op = static_cast<const BinaryOp&>(instr);
return GetBinaryOpName(bin_op.op());
}
case Opcode::kUnaryOp: {
const auto& unary_op = static_cast<const UnaryOp&>(instr);
return GetUnaryOpName(unary_op.op());
}
case Opcode::kBranch: {
const auto& branch = static_cast<const Branch&>(instr);
return fmt::format("{}", branch.target()->id);
}
case Opcode::kVectorCall:
case Opcode::kVectorCallStatic:
case Opcode::kVectorCallKW: {
const auto& call = static_cast<const VectorCallBase&>(instr);
return fmt::format(
"{}{}", call.numArgs(), call.isAwaited() ? ", awaited" : "");
}
case Opcode::kCallCFunc: {
const auto& call = static_cast<const CallCFunc&>(instr);
return call.funcName();
}
case Opcode::kCallMethod: {
const auto& call = static_cast<const CallMethod&>(instr);
return fmt::format(
"{}{}", call.NumOperands(), call.isAwaited() ? ", awaited" : "");
}
case Opcode::kCallStatic: {
const auto& call = static_cast<const CallStatic&>(instr);
return fmt::format("{}", call.NumOperands());
}
case Opcode::kCallStaticRetVoid: {
const auto& call = static_cast<const CallStatic&>(instr);
return fmt::format("{}", call.NumOperands());
}
case Opcode::kInvokeStaticFunction: {
const auto& call = static_cast<const InvokeStaticFunction&>(instr);
return fmt::format(
"{}.{}, {}, {}",
PyUnicode_AsUTF8(call.func()->func_module),
PyUnicode_AsUTF8(call.func()->func_qualname),
call.NumOperands(),
call.ret_type());
}
case Opcode::kInvokeMethod: {
const auto& call = static_cast<const InvokeMethod&>(instr);
return fmt::format(
"{}{}", call.NumOperands(), call.isAwaited() ? ", awaited" : "");
}
case Opcode::kLoadField: {
const auto& lf = static_cast<const LoadField&>(instr);
std::size_t offset = lf.offset();
#ifdef Py_TRACE_REFS
// Keep these stable from the offset of ob_refcnt, in trace refs
// we have 2 extra next/prev pointers linking all objects together
offset -= (sizeof(PyObject*) * 2);
#endif
return fmt::format(
"{}@{}, {}, {}",
lf.name(),
offset,
lf.type(),
lf.borrowed() ? "borrowed" : "owned");
}
case Opcode::kStoreField: {
const auto& sf = static_cast<const StoreField&>(instr);
return fmt::format("{}@{}", sf.name(), sf.offset());
}
case Opcode::kCast: {
const auto& cast = static_cast<const Cast&>(instr);
if (cast.optional()) {
return fmt::format("Optional[{}]", cast.pytype()->tp_name);
} else {
return fmt::format("{}", cast.pytype()->tp_name);
}
}
case Opcode::kTpAlloc: {
const auto& tp_alloc = static_cast<const TpAlloc&>(instr);
return fmt::format("{}", tp_alloc.pytype()->tp_name);
}
case Opcode::kCompare: {
const auto& cmp = static_cast<const Compare&>(instr);
return GetCompareOpName(cmp.op());
}
case Opcode::kLongCompare: {
const auto& cmp = static_cast<const LongCompare&>(instr);
return GetCompareOpName(cmp.op());
}
case Opcode::kLongBinaryOp: {
const auto& bin = static_cast<const LongBinaryOp&>(instr);
return GetBinaryOpName(bin.op());
}
case Opcode::kCompareBool: {
const auto& cmp = static_cast<const Compare&>(instr);
return GetCompareOpName(cmp.op());
}
case Opcode::kIntConvert: {
const auto& conv = static_cast<const IntConvert&>(instr);
return conv.type().toString();
}
case Opcode::kPrimitiveUnaryOp: {
const auto& unary = static_cast<const PrimitiveUnaryOp&>(instr);
return GetPrimitiveUnaryOpName(unary.op());
}
case Opcode::kCondBranch:
case Opcode::kCondBranchIterNotDone:
case Opcode::kCondBranchCheckType: {
const auto& cond = static_cast<const CondBranchBase&>(instr);
auto targets =
fmt::format("{}, {}", cond.true_bb()->id, cond.false_bb()->id);
if (cond.IsCondBranchCheckType()) {
Type type = static_cast<const CondBranchCheckType&>(cond).type();
return fmt::format("{}, {}", targets, type);
}
return targets;
}
case Opcode::kDoubleBinaryOp: {
const auto& bin_op = static_cast<const DoubleBinaryOp&>(instr);
return GetBinaryOpName(bin_op.op());
}
case Opcode::kLoadArg: {
const auto& load = static_cast<const LoadArg&>(instr);
auto varname = format_varname(load, load.arg_idx());
if (load.type() == TObject) {
return varname;
}
return fmt::format("{}, {}", varname, load.type());
}
case Opcode::kLoadAttrSpecial: {
const auto& load = static_cast<const LoadAttrSpecial&>(instr);
_Py_Identifier* id = load.id();
return fmt::format("\"{}\"", id->string);
}
case Opcode::kLoadMethod: {
const auto& load = static_cast<const LoadMethod&>(instr);
return format_name(load, load.name_idx());
}
case Opcode::kLoadMethodSuper: {
return format_load_super(static_cast<const LoadSuperBase&>(instr));
}
case Opcode::kLoadAttrSuper: {
return format_load_super(static_cast<const LoadSuperBase&>(instr));
}
case Opcode::kLoadConst: {
const auto& load = static_cast<const LoadConst&>(instr);
return fmt::format("{}", load.type());
}
case Opcode::kLoadFunctionIndirect: {
const auto& load = static_cast<const LoadFunctionIndirect&>(instr);
PyObject* func = *load.funcptr();
const char* name;
if (PyFunction_Check(func)) {
name = PyUnicode_AsUTF8(((PyFunctionObject*)func)->func_name);
} else {
name = Py_TYPE(func)->tp_name;
}
return fmt::format("{}", name);
}
case Opcode::kIntBinaryOp: {
const auto& bin_op = static_cast<const IntBinaryOp&>(instr);
return GetBinaryOpName(bin_op.op());
}
case Opcode::kPrimitiveCompare: {
const auto& cmp = static_cast<const PrimitiveCompare&>(instr);
return GetPrimitiveCompareOpName(cmp.op());
}
case Opcode::kPrimitiveBox: {
const auto& box = static_cast<const PrimitiveBox&>(instr);
return fmt::format("{}", box.type());
}
case Opcode::kPrimitiveUnbox: {
const auto& unbox = static_cast<const PrimitiveUnbox&>(instr);
return fmt::format("{}", unbox.type());
}
case Opcode::kLoadGlobalCached: {
const auto& load = static_cast<const LoadGlobalCached&>(instr);
return format_name(load, load.name_idx());
}
case Opcode::kLoadGlobal: {
const auto& load = static_cast<const LoadGlobal&>(instr);
return format_name(load, load.name_idx());
}
case Opcode::kMakeListTuple: {
const auto& makelt = static_cast<const MakeListTuple&>(instr);
return fmt::format(
"{}, {}", makelt.is_tuple() ? "tuple" : "list", makelt.nvalues());
}
case Opcode::kInitListTuple: {
const auto& initlt = static_cast<const InitListTuple&>(instr);
return fmt::format(
"{}, {}", initlt.is_tuple() ? "tuple" : "list", initlt.num_args());
}
case Opcode::kLoadTupleItem: {
const auto& loaditem = static_cast<const LoadTupleItem&>(instr);
return fmt::format("{}", loaditem.idx());
}
case Opcode::kMakeCheckedDict: {
const auto& makedict = static_cast<const MakeCheckedDict&>(instr);
return fmt::format("{} {}", makedict.type(), makedict.GetCapacity());
}
case Opcode::kMakeCheckedList: {
const auto& makelist = static_cast<const MakeCheckedList&>(instr);
return fmt::format("{} {}", makelist.type(), makelist.GetCapacity());
}
case Opcode::kMakeDict: {
const auto& makedict = static_cast<const MakeDict&>(instr);
return fmt::format("{}", makedict.GetCapacity());
}
case Opcode::kPhi: {
const auto& phi = static_cast<const Phi&>(instr);
std::stringstream ss;
bool first = true;
for (auto& bb : phi.basic_blocks()) {
if (first) {
first = false;
} else {
ss << ", ";
}
ss << bb->id;
}
return ss.str();
}
case Opcode::kDeleteAttr:
case Opcode::kLoadAttr:
case Opcode::kStoreAttr: {
const auto& named = static_cast<const DeoptBaseWithNameIdx&>(instr);
return format_name(named, named.name_idx());
}
case Opcode::kInPlaceOp: {
const auto& inplace_op = static_cast<const InPlaceOp&>(instr);
return GetInPlaceOpName(inplace_op.op());
}
case Opcode::kBuildSlice: {
const auto& build_slice = static_cast<const BuildSlice&>(instr);
return fmt::format("{}", build_slice.NumOperands());
}
case Opcode::kLoadTypeAttrCacheItem: {
const auto& i = static_cast<const LoadTypeAttrCacheItem&>(instr);
return fmt::format("{}, {}", i.cache_id(), i.item_idx());
}
case Opcode::kFillTypeAttrCache: {
const auto& ftac = static_cast<const FillTypeAttrCache&>(instr);
return fmt::format("{}, {}", ftac.cache_id(), ftac.name_idx());
}
case Opcode::kSetFunctionAttr: {
const auto& set_fn_attr = static_cast<const SetFunctionAttr&>(instr);
return fmt::format("{}", functionFieldName(set_fn_attr.field()));
}
case Opcode::kCheckField:
case Opcode::kCheckFreevar:
case Opcode::kCheckVar: {
const auto& check = static_cast<const CheckBaseWithName&>(instr);
return escape_unicode(check.name());
}
case Opcode::kGuardIs: {
const auto& gs = static_cast<const GuardIs&>(instr);
return fmt::format("{}", getStablePointer(gs.target()));
}
case Opcode::kGuardType: {
const auto& gs = static_cast<const GuardType&>(instr);
return fmt::format("{}", gs.target().toString());
}
case Opcode::kHintType: {
std::ostringstream os;
auto profile_sep = "";
const auto& hint = static_cast<const HintType&>(instr);
os << fmt::format("{}, ", hint.NumOperands());
for (auto types_seen : hint.seenTypes()) {
os << fmt::format("{}<", profile_sep);
auto type_sep = "";
for (auto type : types_seen) {
os << fmt::format("{}{}", type_sep, type.toString());
type_sep = ", ";
}
os << ">";
profile_sep = ", ";
}
return os.str();
}
case Opcode::kUseType: {
const auto& gs = static_cast<const UseType&>(instr);
return fmt::format("{}", gs.type().toString());
}
case Opcode::kRaiseAwaitableError: {
const auto& ra = static_cast<const RaiseAwaitableError&>(instr);
if (ra.with_opcode() == BEFORE_ASYNC_WITH) {
return "BEFORE_ASYNC_WITH";
}
if (ra.with_opcode() == WITH_CLEANUP_START) {
return "WITH_CLEANUP_START";
}
return fmt::format("invalid:{}", ra.with_opcode());
}
case Opcode::kRaiseStatic: {
const auto& pyerr = static_cast<const RaiseStatic&>(instr);
std::ostringstream os;
print_reg_states(os, pyerr.live_regs());
return fmt::format(
"{}, \"{}\", <{}>",
PyExceptionClass_Name(pyerr.excType()),
pyerr.fmt(),
os.str());
}
case Opcode::kInitialYield:
case Opcode::kYieldValue:
case Opcode::kYieldAndYieldFrom:
case Opcode::kYieldFrom: {
std::ostringstream os;
auto sep = "";
for (auto reg : dynamic_cast<const YieldBase*>(&instr)->liveOwnedRegs()) {
os << fmt::format("{}o:{}", sep, reg->name());
sep = ", ";
}
for (auto reg :
dynamic_cast<const YieldBase*>(&instr)->liveUnownedRegs()) {
os << fmt::format("{}u:{}", sep, reg->name());
sep = ", ";
}
return os.str();
}
case Opcode::kImportFrom: {
const auto& import_from = static_cast<const ImportFrom&>(instr);
return format_name(import_from, import_from.nameIdx());
}
case Opcode::kImportName: {
const auto& import_name = static_cast<const ImportName&>(instr);
return format_name(import_name, import_name.name_idx());
}
case Opcode::kRefineType: {
const auto& rt = static_cast<const RefineType&>(instr);
return rt.type().toString();
}
case Opcode::kFormatValue: {
int conversion = static_cast<const FormatValue&>(instr).conversion();
switch (conversion) {
case FVC_NONE:
return "None";
case FVC_STR:
return "Str";
case FVC_REPR:
return "Repr";
case FVC_ASCII:
return "ASCII";
}
JIT_CHECK(false, "Unknown conversion type.");
}
case Opcode::kUnpackExToTuple: {
const auto& i = static_cast<const UnpackExToTuple&>(instr);
return fmt::format("{}, {}", i.before(), i.after());
}
case Opcode::kDeoptPatchpoint: {
const auto& dp = static_cast<const DeoptPatchpoint&>(instr);
return fmt::format("{}", getStablePointer(dp.patcher()));
}
}
JIT_CHECK(false, "invalid opcode %d", static_cast<int>(instr.opcode()));
}