void BasicBlockBuilder::AppendCodeLine()

in Jit/lir/block_builder.cpp [105:448]


void BasicBlockBuilder::AppendCodeLine(const std::string& s) {
  // this function assumes that input is syntactically correct.
  // there is very limited syntax checking in the following parsing process.
  std::vector<std::string> tokens = Tokenize(s);

  const std::string& instr_str = tokens[0];
  if (instr_str == "Load") {
    auto instr = createInstr(Instruction::kMove);

    if (tokens.size() == 3) {
      instr->allocateAddressInput(reinterpret_cast<void*>(stoull(tokens[2])));
    } else {
      CreateInstrIndirect(instr, tokens[2], stoull(tokens[3]));
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "LoadArg") {
    JIT_CHECK(tokens.size() == 3, "expected 3 args");
    auto instr = createInstr(Instruction::kLoadArg);

    CreateInstrImmediateInput(instr, tokens[2]);
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "Store") {
    auto instr = createInstr(Instruction::kMove);

    JIT_CHECK(
        tokens.size() == 3 || tokens.size() == 4, "Syntax error for Store");

    if (IsConstant(tokens[1])) {
      CreateInstrImmediateInput(instr, tokens[1]);
    } else {
      CreateInstrInput(instr, tokens[1]);
    }
    if (tokens.size() == 3) {
      instr->output()->setMemoryAddress(
          reinterpret_cast<void*>(stoull(tokens[2])));
    } else {
      CreateInstrIndirectOutput(instr, tokens[2], stoull(tokens[3]));
    }
    instr->output()->setDataType(instr->getInput(0)->dataType());
  } else if (instr_str == "Move") {
    JIT_CHECK(tokens.size() == 3, "Syntax error for Move.");
    JIT_CHECK(
        !IsConstant(tokens[1]), "Syntax error for Move: %s", tokens[1].c_str());
    auto instr = createInstr(Instruction::kMove);

    if (IsConstant(tokens[2])) {
      CreateInstrImmediateInput(instr, tokens[2]);
    } else {
      CreateInstrInput(instr, tokens[2]);
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "Lea") {
    JIT_CHECK(tokens.size() == 4, "Syntax error for LoadAddress.");
    JIT_CHECK(
        !IsConstant(tokens[1]),
        "Syntax error for LoadAddress: %s",
        tokens[1].c_str());
    auto instr = createInstr(Instruction::kLea);

    CreateInstrIndirect(instr, tokens[2], stoull(tokens[3]));
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "Return") {
    auto instr = createInstr(Instruction::kReturn);

    CreateInstrInput(instr, tokens[1]);
  } else if (instr_str == "Convert") {
    auto instr = createInstr(Instruction::kSext);

    if (IsConstant(tokens[2])) {
      CreateInstrImmediateInput(instr, tokens[2]);
    } else {
      CreateInstrInput(instr, tokens[2]);
    }

    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "ConvertUnsigned") {
    auto instr = createInstr(Instruction::kZext);

    if (IsConstant(tokens[2])) {
      CreateInstrImmediateInput(instr, tokens[2]);
    } else {
      CreateInstrInput(instr, tokens[2]);
    }

    CreateInstrOutput(instr, tokens[1]);
  } else if (
      instr_str == "Add" || instr_str == "Sub" || instr_str == "And" ||
      instr_str == "Xor" || instr_str == "Or" || instr_str == "LShift" ||
      instr_str == "RShift" || instr_str == "RShiftUn" || instr_str == "Mul" ||
      instr_str == "Div" || instr_str == "DivUn" || instr_str == "Equal" ||
      instr_str == "NotEqual" || instr_str == "GreaterThanSigned" ||
      instr_str == "LessThanSigned" || instr_str == "GreaterThanEqualSigned" ||
      instr_str == "LessThanEqualSigned" ||
      instr_str == "GreaterThanUnsigned" || instr_str == "LessThanUnsigned" ||
      instr_str == "GreaterThanEqualUnsigned" ||
      instr_str == "LessThanEqualUnsigned" || instr_str == "Fadd" ||
      instr_str == "Fsub" || instr_str == "Fmul" || instr_str == "Fdiv") {
    Instruction* instr = nullptr;
    if (instr_str == "Add") {
      instr = createInstr(Instruction::kAdd);
    } else if (instr_str == "Sub") {
      instr = createInstr(Instruction::kSub);
    } else if (instr_str == "And") {
      instr = createInstr(Instruction::kAnd);
    } else if (instr_str == "Xor") {
      instr = createInstr(Instruction::kXor);
    } else if (instr_str == "Or") {
      instr = createInstr(Instruction::kOr);
    } else if (instr_str == "LShift") {
      instr = createInstr(Instruction::kLShift);
    } else if (instr_str == "RShift") {
      instr = createInstr(Instruction::kRShift);
    } else if (instr_str == "RShiftUn") {
      instr = createInstr(Instruction::kRShiftUn);
    } else if (instr_str == "Mul") {
      instr = createInstr(Instruction::kMul);
    } else if (instr_str == "Equal") {
      instr = createInstr(Instruction::kEqual);
    } else if (instr_str == "NotEqual") {
      instr = createInstr(Instruction::kNotEqual);
    } else if (instr_str == "GreaterThanSigned") {
      instr = createInstr(Instruction::kGreaterThanSigned);
    } else if (instr_str == "LessThanSigned") {
      instr = createInstr(Instruction::kLessThanSigned);
    } else if (instr_str == "GreaterThanEqualSigned") {
      instr = createInstr(Instruction::kGreaterThanEqualSigned);
    } else if (instr_str == "LessThanEqualSigned") {
      instr = createInstr(Instruction::kLessThanEqualSigned);
    } else if (instr_str == "GreaterThanUnsigned") {
      instr = createInstr(Instruction::kGreaterThanUnsigned);
    } else if (instr_str == "LessThanUnsigned") {
      instr = createInstr(Instruction::kLessThanUnsigned);
    } else if (instr_str == "GreaterThanEqualUnsigned") {
      instr = createInstr(Instruction::kGreaterThanEqualUnsigned);
    } else if (instr_str == "LessThanEqualUnsigned") {
      instr = createInstr(Instruction::kLessThanEqualUnsigned);
    } else if (instr_str == "Fadd") {
      instr = createInstr(Instruction::kFadd);
    } else if (instr_str == "Fsub") {
      instr = createInstr(Instruction::kFsub);
    } else if (instr_str == "Fmul") {
      instr = createInstr(Instruction::kFmul);
    } else if (instr_str == "Fdiv") {
      instr = createInstr(Instruction::kFdiv);
    } else if (instr_str == "Div") {
      instr = createInstr(Instruction::kDiv);
    } else if (instr_str == "DivUn") {
      instr = createInstr(Instruction::kDivUn);
    } else {
      JIT_CHECK(false, "Unknown LIR instruction: %s", instr_str);
    }

    for (size_t i = 2; i < tokens.size(); i++) {
      if (IsConstant(tokens[i])) {
        CreateInstrImmediateInput(instr, tokens[i]);
      } else {
        CreateInstrInput(instr, tokens[i]);
      }
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "Negate") {
    auto instr = createInstr(Instruction::kNegate);
    if (IsConstant(tokens[2])) {
      CreateInstrImmediateInput(instr, tokens[2]);
    } else {
      CreateInstrInput(instr, tokens[2]);
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (instr_str == "Invert") {
    auto instr = createInstr(Instruction::kInvert);
    if (IsConstant(tokens[2])) {
      CreateInstrImmediateInput(instr, tokens[2]);
    } else {
      CreateInstrInput(instr, tokens[2]);
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (
      instr_str == "Call" || instr_str == "Vectorcall" ||
      instr_str == "Invoke") {
    bool is_invoke = (instr_str == "Invoke");
    bool is_vector_call = (instr_str == "Vectorcall");

    if (g_dump_c_helper) {
      size_t dest_idx = is_invoke ? 1 : 2;
      if (dest_idx < tokens.size() && IsConstant(tokens[dest_idx])) {
        std::string helper_id = GetId(tokens[dest_idx]);
        uint64_t helper_addr = stoull(helper_id);
        Dl_info helper_info;
        if (dladdr(reinterpret_cast<void*>(helper_addr), &helper_info) != 0 &&
            helper_info.dli_sname != NULL) {
          JIT_LOG("Call to function %s.", helper_info.dli_sname);
        } else {
          JIT_LOG("Call to function at %s.", tokens[dest_idx]);
        }
      }
    }

    auto instr = createInstr(
        is_vector_call ? Instruction::kVectorCall : Instruction::kCall);

    for (size_t i = is_invoke ? 1 : 2; i < tokens.size(); i++) {
      if (IsConstant(tokens[i])) {
        CreateInstrImmediateInput(instr, tokens[i]);
      } else {
        CreateInstrInput(instr, tokens[i]);
      }
    }

    if (!is_invoke) {
      CreateInstrOutput(instr, tokens[1]);
    }
  } else if (instr_str == "CondBranch") {
    auto instr = createInstr(Instruction::kCondBranch);

    auto cond = tokens[1];
    if (IsConstant(cond)) {
      CreateInstrImmediateInput(instr, cond);
    } else {
      CreateInstrInput(instr, cond);
    }
  } else if (instr_str == "JumpIf") {
    // the difference between CondBranch and JumpIf is that the
    // arguments of CondBranch is HIR basic block ids, while those
    // of JumpIf are label names.
    // TODO: we can merge CondBranch and JumpIf by translating
    // HIR basic block ids into label names.
    auto instr = createInstr(Instruction::kCondBranch);
    auto cond = tokens[1];
    if (IsConstant(cond)) {
      CreateInstrImmediateInput(instr, cond);
    } else {
      CreateInstrInput(instr, cond);
    }
    auto true_bb = GetBasicBlockByLabel(tokens[2]);
    auto false_bb = GetBasicBlockByLabel(tokens[3]);

    cur_bb_->addSuccessor(true_bb);
    cur_bb_->addSuccessor(false_bb);
  } else if (instr_str == "Branch") {
    createInstr(Instruction::kBranch);
  } else if (instr_str == "BranchB" || instr_str == "BranchC") {
    createInstr(Instruction::kBranchB);
    auto succ_bb = GetBasicBlockByLabel(tokens[1]);
    cur_bb_->addSuccessor(succ_bb);
  } else if (instr_str == "BranchNZ") {
    createInstr(Instruction::kBranchNZ);
    auto succ_bb = GetBasicBlockByLabel(tokens[1]);
    cur_bb_->addSuccessor(succ_bb);
  } else if (instr_str == "BranchC") {
    createInstr(Instruction::kBranchC);
    auto succ_bb = GetBasicBlockByLabel(tokens[1]);
    cur_bb_->addSuccessor(succ_bb);
  } else if (instr_str == "BranchNC") {
    createInstr(Instruction::kBranchNC);
    auto succ_bb = GetBasicBlockByLabel(tokens[1]);
    cur_bb_->addSuccessor(succ_bb);
  } else if (instr_str == "BitTest") {
    auto instr = createInstr(Instruction::kBitTest);
    CreateInstrInput(instr, tokens[1]);
    CreateInstrImmediateInput(instr, tokens[2]);
  } else if (instr_str == "Inc" || instr_str == "Dec") {
    auto instr =
        createInstr(instr_str == "Inc" ? Instruction::kInc : Instruction::kDec);
    CreateInstrInput(instr, tokens[1]);
  } else if (instr_str == "Guard") {
    auto instr = createInstr(Instruction::kGuard);

    enum InstrGuardKind guard_kind;
    const std::string& kind = tokens[1];
    if (kind == "NotZero") {
      guard_kind = InstrGuardKind::kNotZero;
    } else if (kind == "NotNegative") {
      guard_kind = InstrGuardKind::kNotNegative;
    } else if (kind == "AlwaysFail") {
      guard_kind = InstrGuardKind::kAlwaysFail;
    } else if (kind == "Is") {
      guard_kind = InstrGuardKind::kIs;
    } else if (kind == "HasType") {
      guard_kind = InstrGuardKind::kHasType;
    } else {
      JIT_CHECK(false, "unknown check kind: {}", kind);
    }
    instr->allocateImmediateInput(guard_kind);
    CreateInstrImmediateInput(instr, tokens[2]);

    for (size_t i = 3; i < tokens.size(); i++) {
      if (tokens[i] == "reg:edx") {
        Operand* opnd = instr->allocatePhyRegisterInput(PhyLocation::RDX);
        opnd->setDataType(OperandBase::k32bit);
      } else if (tokens[i] == "reg:xmm1") {
        Operand* opnd = instr->allocatePhyRegisterInput(PhyLocation::XMM1);
        opnd->setDataType(OperandBase::kDouble);
      } else if (IsConstant(tokens[i])) {
        CreateInstrImmediateInput(instr, tokens[i]);
      } else {
        CreateInstrInput(instr, tokens[i]);
      }
    }
  } else if (instr_str == "DeoptPatchpoint") {
    auto instr = createInstr(Instruction::kDeoptPatchpoint);
    for (size_t i = 1; i < tokens.size(); i++) {
      if (IsConstant(tokens[i])) {
        CreateInstrImmediateInput(instr, tokens[i]);
      } else {
        CreateInstrInput(instr, tokens[i]);
      }
    }
  } else if (instr_str == "Phi") {
    auto instr = createInstr(Instruction::kPhi);

    JIT_CHECK((tokens.size() & 1) == 0, "Expected even number of tokens");
    for (size_t i = 2; i < tokens.size() - 1; i += 2) {
      instr->allocateLabelInput(
          reinterpret_cast<BasicBlock*>(stoull(tokens[i])));
      CreateInstrInput(instr, tokens[i + 1]);
    }
    CreateInstrOutput(instr, tokens[1]);
  } else if (
      instr_str == "YieldInitial" || instr_str == "YieldValue" ||
      instr_str == "YieldFrom" || instr_str == "YieldFromSkipInitialSend") {
    Instruction* instr;
    if (instr_str == "YieldInitial") {
      instr = createInstr(Instruction::kYieldInitial);
    } else if (instr_str == "YieldValue") {
      instr = createInstr(Instruction::kYieldValue);
    } else if (instr_str == "YieldFromSkipInitialSend") {
      instr = createInstr(Instruction::kYieldFromSkipInitialSend);
    } else {
      instr = createInstr(Instruction::kYieldFrom);
    }
    CreateInstrOutput(instr, tokens[1]);
    for (size_t tok_n = 2; tok_n < tokens.size() - 1; tok_n++) {
      CreateInstrInput(instr, tokens[tok_n]);
    }
    CreateInstrImmediateInput(instr, tokens[tokens.size() - 1]);
  } else if (instr_str == "BatchDecref") {
    auto instr = createInstr(Instruction::kBatchDecref);
    for (size_t i = 1; i < tokens.size(); i++) {
      CreateInstrInput(instr, tokens[i]);
    }
  } else {
    JIT_CHECK(false, "Unknown LIR instruction: %s", instr_str);
  }
}