Jit/hir/parser.cpp (786 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) #include "Jit/hir/parser.h" #include "classloader.h" #include "pycore_tupleobject.h" #include "Jit/hir/hir.h" #include "Jit/log.h" #include "Jit/ref.h" #include <algorithm> #include <cctype> #include <cstdlib> #include <cstring> #include <functional> #include <memory> #include <string> #include <unordered_map> #include <utility> namespace jit { namespace hir { #define NEW_INSTR(type, ...) \ auto instr = type::create(__VA_ARGS__); \ instruction = instr; void HIRParser::expect(const char* expected) { const char* actual = GetNextToken(); if (strcmp(expected, actual) != 0) { JIT_LOG("Expected \"%s\", but got \"%s\"", expected, actual); std::abort(); } } Register* HIRParser::allocateRegister(const char* name) { JIT_CHECK( name[0] == 'v', "invalid register name (must be v[0-9]+): %s", name); int id = atoi(name + 1); auto reg = env_->getRegister(id); if (reg == nullptr) { reg = env_->addRegister(std::make_unique<Register>(id)); } max_reg_id_ = std::max(max_reg_id_, id); return reg; } Register* HIRParser::ParseRegister() { const char* name = GetNextToken(); return allocateRegister(name); } HIRParser::ListOrTuple HIRParser::parseListOrTuple() { const char* kind = GetNextToken(); if (strcmp(kind, "list") == 0) { return ListOrTuple::List; } if (strcmp(kind, "tuple") == 0) { return ListOrTuple::Tuple; } JIT_CHECK(false, "Invalid kind %s, expected list or tuple", kind); } Instr* HIRParser::parseInstr(const char* opcode, Register* dst, int bb_index) { Instr* instruction = nullptr; if (strcmp(opcode, "Branch") == 0) { NEW_INSTR(Branch, nullptr); expect("<"); branches_.emplace(instr, GetNextInteger()); expect(">"); } else if ( strcmp(opcode, "VectorCall") == 0 || strcmp(opcode, "VectorCallStatic") == 0 || strcmp(opcode, "VectorCallKW") == 0) { expect("<"); int num_args = GetNextInteger(); bool is_awaited = false; if (strcmp(peekNextToken(), ",") == 0) { expect(","); expect("awaited"); is_awaited = true; } expect(">"); auto func = ParseRegister(); std::vector<Register*> args(num_args); std::generate( args.begin(), args.end(), std::bind(std::mem_fun(&HIRParser::ParseRegister), this)); if (strcmp(opcode, "VectorCall") == 0) { instruction = newInstr<VectorCall>(num_args + 1, dst, is_awaited); } else if (strcmp(opcode, "VectorCallStatic") == 0) { instruction = newInstr<VectorCallStatic>(num_args + 1, dst, is_awaited); } else if (strcmp(opcode, "VectorCallKW") == 0) { instruction = newInstr<VectorCallKW>(num_args + 1, dst, is_awaited); } else { JIT_CHECK(false, "Unhandled opcode {}", opcode); } instruction->SetOperand(0, func); for (int i = 0; i < num_args; i++) { instruction->SetOperand(i + 1, args[i]); } } else if (strcmp(opcode, "FormatValue") == 0) { expect("<"); auto tok = GetNextToken(); auto conversion = [&] { if (strcmp(tok, "None") == 0) { return FVC_NONE; } else if (strcmp(tok, "Str") == 0) { return FVC_STR; } else if (strcmp(tok, "Repr") == 0) { return FVC_REPR; } else if (strcmp(tok, "ASCII") == 0) { return FVC_ASCII; } JIT_CHECK(false, "Bad FormatValue conversion type: %s", tok); }(); expect(">"); Register* fmt_spec = ParseRegister(); Register* val = ParseRegister(); instruction = newInstr<FormatValue>(dst, fmt_spec, val, conversion); } else if (strcmp(opcode, "CallEx") == 0) { bool is_awaited = false; if (strcmp(peekNextToken(), "<") == 0) { expect("<"); expect("awaited"); expect(">"); is_awaited = true; } Register* func = ParseRegister(); Register* pargs = ParseRegister(); instruction = newInstr<CallEx>(dst, func, pargs, is_awaited); } else if (strcmp(opcode, "CallExKw") == 0) { bool is_awaited = false; if (strcmp(peekNextToken(), "<") == 0) { expect("<"); expect("awaited"); expect(">"); is_awaited = true; } Register* func = ParseRegister(); Register* pargs = ParseRegister(); Register* kwargs = ParseRegister(); instruction = newInstr<CallExKw>(dst, func, pargs, kwargs, is_awaited); } else if (strcmp(opcode, "ImportFrom") == 0) { expect("<"); int name_idx = GetNextInteger(); expect(">"); Register* module = ParseRegister(); instruction = newInstr<ImportFrom>(dst, module, name_idx); } else if (strcmp(opcode, "ImportName") == 0) { expect("<"); int name_idx = GetNextInteger(); expect(">"); Register* fromlist = ParseRegister(); Register* level = ParseRegister(); instruction = newInstr<ImportName>(dst, name_idx, fromlist, level); } else if (strcmp(opcode, "InitListTuple") == 0) { expect("<"); auto kind = parseListOrTuple(); expect(","); int num_args = GetNextInteger(); expect(">"); auto target = ParseRegister(); std::vector<Register*> args(num_args); std::generate( args.begin(), args.end(), std::bind(std::mem_fun(&HIRParser::ParseRegister), this)); NEW_INSTR(InitListTuple, num_args + 1, kind == ListOrTuple::Tuple); instr->SetOperand(0, target); for (int i = 0; i < num_args; i++) { instr->SetOperand(i + 1, args[i]); } } else if (strcmp(opcode, "MakeListTuple") == 0) { expect("<"); auto kind = parseListOrTuple(); expect(","); int nvalues = GetNextInteger(); expect(">"); instruction = newInstr<MakeListTuple>(kind == ListOrTuple::Tuple, dst, nvalues); } else if (strcmp(opcode, "LoadArg") == 0) { expect("<"); int idx = GetNextNameIdx(); Type ty = TObject; if (strcmp(peekNextToken(), ",") == 0) { expect(","); ty = Type::parse(env_, GetNextToken()); } expect(">"); NEW_INSTR(LoadArg, dst, idx, ty); } else if (strcmp(opcode, "LoadMethod") == 0) { expect("<"); int idx = GetNextNameIdx(); expect(">"); auto receiver = ParseRegister(); instruction = newInstr<LoadMethod>(dst, receiver, idx); } else if (strcmp(opcode, "LoadTupleItem") == 0) { expect("<"); int idx = GetNextNameIdx(); expect(">"); auto receiver = ParseRegister(); NEW_INSTR(LoadTupleItem, dst, receiver, idx); } else if (strcmp(opcode, "CallMethod") == 0) { expect("<"); int num_args = GetNextInteger(); bool is_awaited = false; if (strcmp(peekNextToken(), ",") == 0) { expect(","); expect("awaited"); is_awaited = true; } expect(">"); std::vector<Register*> args(num_args); std::generate( args.begin(), args.end(), std::bind(std::mem_fun(&HIRParser::ParseRegister), this)); instruction = newInstr<CallMethod>(args.size(), dst, is_awaited); for (std::size_t i = 0; i < args.size(); i++) { instruction->SetOperand(i, args[i]); } } else if (strcmp(opcode, "CondBranch") == 0) { expect("<"); auto true_bb = GetNextInteger(); expect(","); auto false_bb = GetNextInteger(); expect(">"); auto var = ParseRegister(); NEW_INSTR(CondBranch, var, nullptr, nullptr); cond_branches_.emplace( std::piecewise_construct, std::forward_as_tuple(instr), std::forward_as_tuple(true_bb, false_bb)); } else if (strcmp(opcode, "CondBranchCheckType") == 0) { expect("<"); auto true_bb = GetNextInteger(); expect(","); auto false_bb = GetNextInteger(); expect(","); Type ty = Type::parse(env_, GetNextToken()); expect(">"); auto var = ParseRegister(); NEW_INSTR(CondBranchCheckType, var, ty, nullptr, nullptr); cond_branches_.emplace( std::piecewise_construct, std::forward_as_tuple(instr), std::forward_as_tuple(true_bb, false_bb)); } else if (strcmp(opcode, "Decref") == 0) { auto var = ParseRegister(); NEW_INSTR(Decref, var); } else if (strcmp(opcode, "Incref") == 0) { auto var = ParseRegister(); NEW_INSTR(Incref, var); } else if (strcmp(opcode, "LoadAttr") == 0) { expect("<"); int idx = GetNextNameIdx(); expect(">"); auto receiver = ParseRegister(); instruction = newInstr<LoadAttr>(dst, receiver, idx); } else if (strcmp(opcode, "LoadConst") == 0) { expect("<"); Type ty = Type::parse(env_, GetNextToken()); expect(">"); NEW_INSTR(LoadConst, dst, ty); } else if (strcmp(opcode, "LoadGlobal") == 0) { expect("<"); int name_idx = GetNextNameIdx(); expect(">"); instruction = newInstr<LoadGlobal>(dst, name_idx); } else if (strcmp(opcode, "LoadGlobalCached") == 0) { expect("<"); int name_idx = GetNextNameIdx(); expect(">"); instruction = LoadGlobalCached::create( dst, /*code=*/nullptr, /*globals=*/nullptr, name_idx); } else if (strcmp(opcode, "StoreAttr") == 0) { expect("<"); int idx = GetNextNameIdx(); expect(">"); auto receiver = ParseRegister(); auto value = ParseRegister(); instruction = newInstr<StoreAttr>(dst, receiver, value, idx); } else if (strcmp(opcode, "DeleteSubscr") == 0) { auto container = ParseRegister(); auto sub = ParseRegister(); newInstr<DeleteSubscr>(container, sub); } else if (strcmp(opcode, "StoreSubscr") == 0) { auto receiver = ParseRegister(); auto index = ParseRegister(); auto value = ParseRegister(); NEW_INSTR(StoreSubscr, dst, receiver, index, value); } else if (strcmp(opcode, "Assign") == 0) { auto src = ParseRegister(); NEW_INSTR(Assign, dst, src); } else if (strcmp(opcode, "BinaryOp") == 0) { expect("<"); BinaryOpKind op = ParseBinaryOpName(GetNextToken()); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); instruction = newInstr<BinaryOp>(dst, op, left, right); } else if (strcmp(opcode, "LongBinaryOp") == 0) { expect("<"); BinaryOpKind op = ParseBinaryOpName(GetNextToken()); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); instruction = newInstr<LongBinaryOp>(dst, op, left, right); } else if (strcmp(opcode, "IntBinaryOp") == 0) { expect("<"); BinaryOpKind op = ParseBinaryOpName(GetNextToken()); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); NEW_INSTR(IntBinaryOp, dst, op, left, right); } else if (strcmp(opcode, "Compare") == 0) { expect("<"); std::optional<CompareOp> op = ParseCompareOpName(GetNextToken()); JIT_CHECK(op.has_value(), "Invalid CompareOp"); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); instruction = newInstr<Compare>(dst, *op, left, right); } else if (strcmp(opcode, "LongCompare") == 0) { expect("<"); std::optional<CompareOp> op = ParseCompareOpName(GetNextToken()); JIT_CHECK(op.has_value(), "Invalid CompareOp"); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); NEW_INSTR(LongCompare, dst, *op, left, right); } else if (strcmp(opcode, "PrimitiveCompareOp") == 0) { expect("<"); PrimitiveCompareOp op = ParsePrimitiveCompareOpName(GetNextToken()); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); NEW_INSTR(PrimitiveCompare, dst, op, left, right); } else if (strcmp(opcode, "PrimitiveUnaryOp") == 0) { expect("<"); PrimitiveUnaryOpKind op = ParsePrimitiveUnaryOpName(GetNextToken()); expect(">"); auto operand = ParseRegister(); NEW_INSTR(PrimitiveUnaryOp, dst, op, operand); } else if (strcmp(opcode, "PrimitiveUnbox") == 0) { expect("<"); Type type = Type::parse(env_, GetNextToken()); expect(">"); auto operand = ParseRegister(); NEW_INSTR(PrimitiveUnbox, dst, operand, type); } else if (strcmp(opcode, "PrimitiveBox") == 0) { expect("<"); Type type = Type::parse(env_, GetNextToken()); expect(">"); auto operand = ParseRegister(); NEW_INSTR(PrimitiveBox, dst, operand, type); } else if (strcmp(opcode, "InPlaceOp") == 0) { expect("<"); InPlaceOpKind op = ParseInPlaceOpName(GetNextToken()); expect(">"); auto left = ParseRegister(); auto right = ParseRegister(); instruction = newInstr<InPlaceOp>(dst, op, left, right); } else if (strcmp(opcode, "UnaryOp") == 0) { expect("<"); UnaryOpKind op = ParseUnaryOpName(GetNextToken()); expect(">"); auto operand = ParseRegister(); instruction = newInstr<UnaryOp>(dst, op, operand); } else if (strcmp(opcode, "RaiseAwaitableError") == 0) { expect("<"); auto tok = GetNextToken(); auto opcode = [&] { if (strcmp(tok, "BEFORE_ASYNC_WITH") == 0) { return BEFORE_ASYNC_WITH; } if (strcmp(tok, "WITH_CLEANUP_START") != 0) { return WITH_CLEANUP_START; } JIT_CHECK(false, "Bad RaiseAwaitableError opcode: %s", tok); }(); expect(">"); auto type_reg = ParseRegister(); NEW_INSTR(RaiseAwaitableError, type_reg, opcode, FrameState{}); } else if (strcmp(opcode, "Return") == 0) { Type type = TObject; if (strcmp(peekNextToken(), "<") == 0) { GetNextToken(); type = Type::parse(env_, GetNextToken()); expect(">"); } auto var = ParseRegister(); NEW_INSTR(Return, var); } else if ( strcmp(opcode, "YieldValue") == 0 || strcmp(opcode, "InitialYield") == 0) { std::vector<Register*> live_owned_registers; if (strcmp(peekNextToken(), "<") == 0) { GetNextToken(); while (true) { live_owned_registers.push_back(ParseRegister()); auto token = peekNextToken(); if (strcmp(token, ">") == 0) { GetNextToken(); break; } expect(","); } } if (strcmp(opcode, "InitialYield") == 0) { instruction = InitialYield::create(dst, FrameState{}); } else { auto reg = ParseRegister(); instruction = YieldValue::create(dst, reg, FrameState{}); } YieldBase* yield_base = dynamic_cast<YieldBase*>(instruction); JIT_CHECK(yield_base, "Not a yield opcode"); for (auto reg : live_owned_registers) { yield_base->emplaceLiveOwnedReg(reg); } } else if (strcmp(opcode, "GetIter") == 0) { auto iterable = ParseRegister(); instruction = newInstr<GetIter>(dst, iterable); } else if (strcmp(opcode, "LoadTypeAttrCacheItem") == 0) { expect("<"); int cache_id = GetNextInteger(); int item_idx = GetNextInteger(); expect(">"); NEW_INSTR(LoadTypeAttrCacheItem, dst, cache_id, item_idx); } else if (strcmp(opcode, "FillTypeAttrCache") == 0) { expect("<"); int cache_id = GetNextInteger(); int name_idx = GetNextInteger(); expect(">"); auto receiver = ParseRegister(); instruction = newInstr<FillTypeAttrCache>(dst, receiver, name_idx, cache_id); } else if (strcmp(opcode, "LoadArrayItem") == 0) { auto ob_item = ParseRegister(); auto idx = ParseRegister(); auto array_unused = ParseRegister(); NEW_INSTR(LoadArrayItem, dst, ob_item, idx, array_unused, 0, TObject); } else if (strcmp(opcode, "Phi") == 0) { expect("<"); PhiInfo info{dst}; while (true) { info.inputs.emplace_back(PhiInput{GetNextInteger(), nullptr}); auto token = peekNextToken(); if (strcmp(token, ">") == 0) { GetNextToken(); break; } expect(","); } for (auto& input : info.inputs) { input.value = ParseRegister(); } phis_[bb_index].emplace_back(std::move(info)); } else if (strcmp(opcode, "Guard") == 0) { auto operand = ParseRegister(); instruction = newInstr<Guard>(operand); } else if (strcmp(opcode, "GuardType") == 0) { expect("<"); Type ty = Type::parse(env_, GetNextToken()); expect(">"); auto operand = ParseRegister(); instruction = newInstr<GuardType>(dst, ty, operand); } else if (strcmp(opcode, "IsTruthy") == 0) { auto src = ParseRegister(); instruction = newInstr<IsTruthy>(dst, src); } else if (strcmp(opcode, "UseType") == 0) { expect("<"); Type ty = Type::parse(env_, GetNextToken()); expect(">"); auto operand = ParseRegister(); NEW_INSTR(UseType, operand, ty); } else if (strcmp(opcode, "HintType") == 0) { ProfiledTypes types; expect("<"); int num_args = GetNextInteger(); expect(","); while (true) { std::vector<Type> single_profile; expect("<"); while (true) { Type ty = Type::parse(env_, GetNextToken()); single_profile.emplace_back(ty); auto token = peekNextToken(); if (strcmp(token, ">") == 0) { GetNextToken(); break; } expect(","); } types.emplace_back(single_profile); auto token = peekNextToken(); if (strcmp(token, ">") == 0) { GetNextToken(); break; } expect(","); } std::vector<Register*> args(num_args); std::generate( args.begin(), args.end(), std::bind(std::mem_fun(&HIRParser::ParseRegister), this)); NEW_INSTR(HintType, num_args, types, args); } else if (strcmp(opcode, "RefineType") == 0) { expect("<"); Type ty = Type::parse(env_, GetNextToken()); expect(">"); auto operand = ParseRegister(); NEW_INSTR(RefineType, dst, ty, operand); } else if (strcmp(opcode, "CheckExc") == 0) { auto operand = ParseRegister(); instruction = newInstr<CheckExc>(dst, operand); } else if (strcmp(opcode, "CheckVar") == 0) { expect("<"); BorrowedRef<> name = GetNextUnicode(); expect(">"); auto operand = ParseRegister(); instruction = newInstr<CheckVar>(dst, operand, name); } else if (strcmp(opcode, "Snapshot") == 0) { auto snapshot = Snapshot::create(); if (strcmp(peekNextToken(), "{") == 0) { snapshot->setFrameState(parseFrameState()); } instruction = snapshot; } else if (strcmp(opcode, "Deopt") == 0) { instruction = newInstr<Deopt>(); } else if (strcmp(opcode, "MakeDict") == 0) { expect("<"); auto capacity = GetNextInteger(); expect(">"); instruction = newInstr<MakeDict>(dst, capacity); } else if (strcmp(opcode, "InvokeStaticFunction") == 0) { expect("<"); auto name = GetNextToken(); auto mod_name = Ref<>::steal(PyUnicode_FromString(name)); JIT_CHECK(mod_name != nullptr, "failed to allocate mod name"); auto dot = Ref<>::steal(PyUnicode_FromString(".")); JIT_CHECK(dot != nullptr, "failed to allocate mod name"); auto names = Ref<PyListObject>::steal(PyUnicode_Split(mod_name, dot, -1)); JIT_CHECK(names != nullptr, "unknown func"); auto type_descr = Ref<>::steal(_PyTuple_FromArray(names->ob_item, Py_SIZE(names.get()))); JIT_CHECK(type_descr != nullptr, "unknown func"); PyObject* container = nullptr; auto func = Ref<PyFunctionObject>::steal( _PyClassLoader_ResolveFunction(type_descr, &container)); JIT_CHECK(func != nullptr, "unknown func"); Py_XDECREF(container); expect(","); auto argcount = GetNextInteger(); expect(","); Type ty = Type::parse(env_, GetNextToken()); expect(">"); instruction = newInstr<InvokeStaticFunction>(argcount, dst, func, ty); } else if (strcmp(opcode, "IsErrStopAsyncIteration") == 0) { NEW_INSTR(IsErrStopAsyncIteration, dst); } else if (strcmp(opcode, "ClearError") == 0) { NEW_INSTR(ClearError); } else if (strcmp(opcode, "LoadCurrentFunc") == 0) { NEW_INSTR(LoadCurrentFunc, dst); } else if (strcmp(opcode, "RepeatList") == 0) { Register* list = ParseRegister(); Register* count = ParseRegister(); instruction = newInstr<RepeatList>(dst, list, count); } else { JIT_CHECK(0, "Unknown opcode: %s", opcode); } return instruction; } std::vector<Register*> HIRParser::parseRegisterVector() { expect("<"); int num_items = GetNextInteger(); expect(">"); std::vector<Register*> registers; for (int i = 0; i < num_items; i++) { auto name = GetNextToken(); if (strcmp(name, "<null>") == 0) { registers.emplace_back(nullptr); } else { registers.emplace_back(allocateRegister(name)); } } return registers; } std::vector<RegState> HIRParser::parseRegStates() { expect("<"); int num_vals = GetNextInteger(); expect(">"); std::vector<RegState> reg_states; for (int i = 0; i < num_vals; i++) { auto rs = GetNextRegState(); reg_states.emplace_back(rs); } return reg_states; } FrameState HIRParser::parseFrameState() { FrameState fs; expect("{"); auto token = GetNextToken(); while (strcmp(token, "}") != 0) { if (strcmp(token, "NextInstrOffset") == 0) { fs.next_instr_offset = GetNextInteger(); } else if (strcmp(token, "Locals") == 0) { fs.locals = parseRegisterVector(); } else if (strcmp(token, "Cells") == 0) { fs.cells = parseRegisterVector(); } else if (strcmp(token, "Stack") == 0) { for (Register* r : parseRegisterVector()) { fs.stack.push(r); } } else if (strcmp(token, "BlockStack") == 0) { expect("{"); while (strcmp(peekNextToken(), "}") != 0) { ExecutionBlock block; expect("Opcode"); block.opcode = GetNextInteger(); expect("HandlerOff"); block.handler_off = GetNextInteger(); expect("StackLevel"); block.stack_level = GetNextInteger(); fs.block_stack.push(block); } expect("}"); } else { JIT_CHECK(false, "unexpected token in FrameState: %s", token); } token = GetNextToken(); } return fs; } BasicBlock* HIRParser::ParseBasicBlock(CFG& cfg) { if (strcmp(peekNextToken(), "bb") != 0) { return nullptr; } expect("bb"); int id = GetNextInteger(); auto bb = cfg.AllocateBlock(); bb->id = id; if (strcmp(peekNextToken(), "(") == 0) { // Skip over optional "(preds 1, 2, 3)". while (strcmp(GetNextToken(), ")") != 0) { } } expect("{"); while (strcmp(peekNextToken(), "}") != 0) { Register* dst = nullptr; if (strcmp(peekNextToken(1), "=") == 0) { dst = ParseRegister(); expect("="); } const char* token = GetNextToken(); auto* instr = parseInstr(token, dst, id); if (instr != nullptr) { bb->Append(instr); } } expect("}"); index_to_bb_.emplace(id, bb); return bb; } static bool is_whitespace(char c) { return c == ' ' || c == '\t' || c == '\n'; } static bool is_single_char_token(char c) { return c == '=' || c == '<' || c == '>' || c == ',' || c == '{' || c == '}' || c == '(' || c == ')' || c == ';'; } std::unique_ptr<Function> HIRParser::ParseHIR(const char* hir) { tokens_.clear(); phis_.clear(); branches_.clear(); cond_branches_.clear(); index_to_bb_.clear(); const char* p = hir; while (true) { while (is_whitespace(*p)) { p++; } if (*p == '\0') { break; } if (*p == '"') { std::string token; for (p++; *p != '"'; p++) { JIT_CHECK(*p != '\0', "End of input during string literal"); if (*p != '\\') { token += *p; continue; } p++; switch (*p) { case 'n': token += '\n'; break; case '"': case '\\': token += *p; break; default: JIT_CHECK(false, "Bad escape sequence \\%c", *p); } } p++; tokens_.emplace_back(std::move(token)); } if (is_single_char_token(*p)) { tokens_.emplace_back(p, 1); p++; continue; } auto q = p; while (!is_whitespace(*q) && !is_single_char_token(*q) && *q != '\0') { q++; } tokens_.emplace_back(p, q - p); p = q; } token_iter_ = tokens_.begin(); expect("fun"); auto hir_func = std::make_unique<Function>(); env_ = &hir_func->env; hir_func->fullname = GetNextToken(); expect("{"); while (auto bb = ParseBasicBlock(hir_func->cfg)) { if (hir_func->cfg.entry_block == nullptr) { hir_func->cfg.entry_block = bb; } } realizePhis(); for (auto& it : branches_) { it.first->set_target(index_to_bb_[it.second]); } for (auto& it : cond_branches_) { it.first->set_true_bb(index_to_bb_[it.second.first]); it.first->set_false_bb(index_to_bb_[it.second.second]); } expect("}"); hir_func->env.setNextRegisterId(max_reg_id_ + 1); return hir_func; } void HIRParser::realizePhis() { for (auto& pair : phis_) { auto block = index_to_bb_[pair.first]; auto& front = block->front(); for (auto& phi : pair.second) { std::unordered_map<BasicBlock*, Register*> inputs; for (auto& info : phi.inputs) { inputs.emplace(index_to_bb_[info.bb], info.value); } (Phi::create(phi.dst, inputs))->InsertBefore(front); } } } // Parse an integer, followed by an optional ; and string name (which are // ignored). int HIRParser::GetNextNameIdx() { auto idx = GetNextInteger(); if (strcmp(peekNextToken(), ";") == 0) { // Ignore ; and name. GetNextToken(); GetNextToken(); } return idx; } BorrowedRef<> HIRParser::GetNextUnicode() { const char* str = GetNextToken(); auto obj = Ref<>::steal(PyUnicode_InternFromString(str)); JIT_CHECK(str != nullptr, "Failed to intern string %s", str); return env_->addReference(std::move(obj)); } RegState HIRParser::GetNextRegState() { auto token = GetNextToken(); auto end = strchr(token, ':'); JIT_CHECK(end != NULL, "invalid reg state: %s", token); RegState rs; rs.reg = allocateRegister(end + 1); switch (token[0]) { case 'b': rs.ref_kind = RefKind::kBorrowed; break; case 'o': rs.ref_kind = RefKind::kOwned; break; case 'u': rs.ref_kind = RefKind::kUncounted; break; default: JIT_CHECK(false, "unknown ref kind: %c", token[0]); break; } return rs; } } // namespace hir } // namespace jit