1 /** 2 * Copyright 2023 Huawei Technologies Co., Ltd 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef MINDSPORE_PI_JIT_BYTECODE_PARSER_H_ 18 #define MINDSPORE_PI_JIT_BYTECODE_PARSER_H_ 19 20 #include <map> 21 #include <memory> 22 #include <string> 23 #include <vector> 24 #include "pybind11/pybind11.h" 25 #include "pipeline/jit/pi/graph_compiler/pi_ir/ctrl_flow.h" 26 #include "pipeline/jit/pi/graph_compiler/pi_ir/custom_nodes.h" 27 #include "pipeline/jit/pi/graph_compiler/pi_ir/debug_info.h" 28 #include "pipeline/jit/pi/graph_compiler/pi_ir/value.h" 29 #include "utils/convert_utils_base.h" 30 31 namespace mindspore { 32 namespace pijit { 33 namespace py = pybind11; 34 35 // ByteCodeParser to parse python byte code 36 class ByteCodeParser { 37 public: 38 explicit ByteCodeParser(const py::object &func); 39 explicit ByteCodeParser(const PyFunctionObject &func); 40 ir::FunctionNodePtr Parse(); SetEnableTupleBroaden(bool enable)41 void SetEnableTupleBroaden(bool enable) { func_->SetAttr("enable_tuple_broaden", enable); } 42 43 private: 44 class Instr { 45 public: Instr(const py::object & instr)46 explicit Instr(const py::object &instr) 47 : op_code_(CastToInt(instr.attr("opcode"))), 48 op_name_(instr.attr("opname").cast<std::string>()), 49 arg_(CastToInt(instr.attr("arg"))), 50 arg_repr_(instr.attr("argrepr").cast<std::string>()), 51 offset_(CastToInt(instr.attr("offset"))), 52 starts_line_(CastToInt(instr.attr("starts_line"))), 53 is_jump_target_(instr.attr("is_jump_target").cast<bool>()) {} 54 GetOpCode()55 int GetOpCode() const { return op_code_; } GetOpName()56 const std::string &GetOpName() const { return op_name_; } GetArg()57 int GetArg() const { return arg_; } SetArg(int arg)58 void SetArg(int arg) { arg_ = arg; } GetArgRepr()59 const std::string &GetArgRepr() const { return arg_repr_; } GetOffset()60 int GetOffset() const { return offset_; } GetStartsLine()61 int GetStartsLine() const { return starts_line_; } IsJumpTarget()62 bool IsJumpTarget() const { return is_jump_target_; } ToString()63 std::string ToString() const { 64 return op_name_ + " " + std::to_string(arg_) + (arg_repr_.empty() ? "" : (" (" + arg_repr_) + ")"); 65 } 66 67 private: CastToInt(const py::object & obj)68 int CastToInt(const py::object &obj) const { return py::isinstance<py::none>(obj) ? 0 : obj.cast<int>(); } 69 70 int op_code_; 71 std::string op_name_; 72 int arg_; 73 std::string arg_repr_; 74 int offset_; 75 int starts_line_; 76 bool is_jump_target_; 77 }; 78 using InstrPtr = std::unique_ptr<Instr>; 79 80 // Bind op code to it's handle function 81 void BuildMethodMap(); 82 void BuildStackMethodMap(); 83 void BuildLoadStoreMethodMap(); 84 void BuildMathMethodMap(); 85 void BuildBitwiseMethodMap(); 86 void BuildContainerMethodMap(); 87 void BuildContrlFlowMethodMap(); 88 void BuildOtherMethodMap(); 89 void CallInstrMethod(const InstrPtr &instr); Register(ir::NodePtrList * list)90 void Register(ir::NodePtrList *list) { nodes_.push_back(list); } Restore()91 void Restore() { nodes_.pop_back(); } 92 void SaveNode(const ir::NodePtr &node); 93 bool IsConditionJump(ir::OpCode op); 94 void ParseInstructions(const py::list &instrs); 95 void ParseIf(const InstrPtr &cond, const py::list &then, const py::list &els); 96 void ParseWhile(const InstrPtr &cond, const py::list &body); 97 ir::NodePtr PopStack(); 98 void PushStack(const ir::NodePtr &node); 99 // Process parameters, create place holder and set abstract(type info) 100 void GeneratePostionalParameters(); 101 void GenerateVariableParameter(); 102 void GenerateKeywordOnlyParameters(); 103 void GenerateKeywordParameter(); 104 void GenerateFunctionParameters(); 105 void ParsePopTop(const InstrPtr &instr); 106 void DoRot(const int &cnt); 107 void ParseRotTwo(const InstrPtr &instr); 108 void ParseRotThree(const InstrPtr &instr); 109 void ParseRotFour(const InstrPtr &instr); 110 void ParseNop(const InstrPtr &instr); 111 void ParseDupTop(const InstrPtr &instr); 112 void ParseDupTwo(const InstrPtr &instr); 113 void ParseUnaryOpertion(const InstrPtr &instr); 114 void ParseUnaryNegative(const InstrPtr &instr); 115 void ParseUnaryNot(const InstrPtr &instr); 116 void ParseUnaryInvert(const InstrPtr &instr); 117 void ParseBinaryOpertion(const InstrPtr &instr); 118 void ParseBitwise(const InstrPtr &instr); 119 void ParseAdd(const InstrPtr &instr); 120 void ParseSub(const InstrPtr &instr); 121 void ParseMul(const InstrPtr &instr); 122 void ParseDiv(const InstrPtr &instr); 123 void ParseBinarySubscr(const InstrPtr &instr); 124 void ParseCompareOp(const InstrPtr &instr); 125 void ParseJump(const InstrPtr &instr); 126 void ParseListToTuple(const InstrPtr &instr); 127 void ParseReturnValue(const InstrPtr &instr); 128 // Process Load Constant as value node 129 void ParseLoadConst(const InstrPtr &instr); 130 void ParseLoadName(const InstrPtr &instr); 131 void ParseMakeFunction(const InstrPtr &instr); 132 void ParseBuild(const InstrPtr &instr); 133 void ParseLoadAttr(const InstrPtr &instr); 134 void ParseImport(const InstrPtr &instr); 135 // Process Load a global module/class/function/method/variable etc. 136 void ParseLoadGlobal(const InstrPtr &instr); 137 // Whether two objects are the same 138 // Fold Python objects into constant values, relying on Gurad 139 void ParseIsOp(const InstrPtr &instr); 140 void ParseContainsOp(const InstrPtr &instr); 141 // Process Load a parameter or a local variable 142 void ParseLoadFast(const InstrPtr &instr); 143 void ParseStoreName(const InstrPtr &instr); 144 void ParseStoreSubscr(const InstrPtr &instr); 145 void ParseStoreAttr(const InstrPtr &instr); 146 void ParseCallFunction(const InstrPtr &instr); 147 void ParseLoadClosure(const InstrPtr &instr); 148 void ParseSetupWith(const InstrPtr &instr); 149 // Fold Python objects into constant values, relying on Gurad 150 void ParseFormatValue(const InstrPtr &instr); 151 void ParseLoadMethod(const InstrPtr &instr); 152 void ParseContainerUpdate(const InstrPtr &instr); 153 void ParseNoArgOperation(const InstrPtr &instr); 154 void ParseWithExceptStart(const InstrPtr &instr); 155 void ParseGet(const InstrPtr &instr); 156 void ParseLoadAssertError(const InstrPtr &instr); 157 void ParseDeleteSubscr(const InstrPtr &instr); 158 void ParseDeleteName(const InstrPtr &instr); 159 void ParseDeleteAttr(const InstrPtr &instr); 160 void ParseUnpack(const InstrPtr &instr); 161 void ParseRaiseVarargs(const InstrPtr &instr); 162 ir::DebugInfoPtr GetNodeDebugInfo(const InstrPtr &instr); 163 164 ir::FunctionNodePtr func_; 165 const PyCodeObject &code_; 166 const py::dict globals_; 167 const py::dict builtins_; 168 const py::tuple clousre_; 169 const py::dict kwdefaults_; 170 const py::tuple defaults_; 171 172 using InstrFunc = void (ByteCodeParser::*)(const InstrPtr &instr); 173 // Define the function map to parse ast expression 174 std::map<int, InstrFunc> instr_method_map_; 175 // variable's buffer used to analysis logic and build graph 176 ir::NodePtrList stack_; 177 std::map<int, std::vector<ir::JumpNodePtr>> jump_nodes_map_; 178 std::map<int, ir::NodePtr> targets_map_; 179 std::vector<ir::NodePtrList *> nodes_; 180 ir::NodePtr latest_gen_node_{nullptr}; 181 }; 182 } // namespace pijit 183 } // namespace mindspore 184 185 #endif // MINDSPORE_PI_JIT_BYTECODE_PARSER_H_ 186