github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp (about) 1 //===- LLVMIRConversionGen.cpp - MLIR LLVM IR builder generator -----------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 // 18 // This file uses tablegen definitions of the LLVM IR Dialect operations to 19 // generate the code building the LLVM IR from it. 20 // 21 //===----------------------------------------------------------------------===// 22 23 #include "mlir/TableGen/GenInfo.h" 24 #include "mlir/TableGen/Operator.h" 25 26 #include "llvm/ADT/StringExtras.h" 27 #include "llvm/ADT/Twine.h" 28 #include "llvm/Support/FormatVariadic.h" 29 #include "llvm/Support/raw_ostream.h" 30 #include "llvm/TableGen/Record.h" 31 #include "llvm/TableGen/TableGenBackend.h" 32 33 using namespace llvm; 34 using namespace mlir; 35 36 static bool emitError(const Twine &message) { 37 llvm::errs() << message << "\n"; 38 return false; 39 } 40 41 namespace { 42 // Helper structure to return a position of the substring in a string. 43 struct StringLoc { 44 size_t pos; 45 size_t length; 46 47 // Take a substring identified by this location in the given string. 48 StringRef in(StringRef str) const { return str.substr(pos, length); } 49 50 // A location is invalid if its position is outside the string. 51 explicit operator bool() { return pos != std::string::npos; } 52 }; 53 } // namespace 54 55 // Find the next TableGen variable in the given pattern. These variables start 56 // with a `$` character and can contain alphannumeric characters or underscores. 57 // Return the position of the variable in the pattern and its length, including 58 // the `$` character. The escape syntax `$$` is also detected and returned. 59 static StringLoc findNextVariable(StringRef str) { 60 size_t startPos = str.find('$'); 61 if (startPos == std::string::npos) 62 return {startPos, 0}; 63 64 // If we see "$$", return immediately. 65 if (startPos != str.size() - 1 && str[startPos + 1] == '$') 66 return {startPos, 2}; 67 68 // Otherwise, the symbol spans until the first character that is not 69 // alphanumeric or '_'. 70 size_t endPos = str.find_if_not([](char c) { return isAlnum(c) || c == '_'; }, 71 startPos + 1); 72 if (endPos == std::string::npos) 73 endPos = str.size(); 74 75 return {startPos, endPos - startPos}; 76 } 77 78 // Check if `name` is the name of the variadic operand of `op`. The variadic 79 // operand can only appear at the last position in the list of operands. 80 static bool isVariadicOperandName(const tblgen::Operator &op, StringRef name) { 81 unsigned numOperands = op.getNumOperands(); 82 if (numOperands == 0) 83 return false; 84 const auto &operand = op.getOperand(numOperands - 1); 85 return operand.isVariadic() && operand.name == name; 86 } 87 88 // Check if `result` is a known name of a result of `op`. 89 static bool isResultName(const tblgen::Operator &op, StringRef name) { 90 for (int i = 0, e = op.getNumResults(); i < e; ++i) 91 if (op.getResultName(i) == name) 92 return true; 93 return false; 94 } 95 96 // Check if `name` is a known name of an attribute of `op`. 97 static bool isAttributeName(const tblgen::Operator &op, StringRef name) { 98 return llvm::any_of( 99 op.getAttributes(), 100 [name](const tblgen::NamedAttribute &attr) { return attr.name == name; }); 101 } 102 103 // Check if `name` is a known name of an operand of `op`. 104 static bool isOperandName(const tblgen::Operator &op, StringRef name) { 105 for (int i = 0, e = op.getNumOperands(); i < e; ++i) 106 if (op.getOperand(i).name == name) 107 return true; 108 return false; 109 } 110 111 // Emit to `os` the operator-name driven check and the call to LLVM IRBuilder 112 // for one definition of a LLVM IR Dialect operation. Return true on success. 113 static bool emitOneBuilder(const Record &record, raw_ostream &os) { 114 auto op = tblgen::Operator(record); 115 116 if (!record.getValue("llvmBuilder")) 117 return emitError("no 'llvmBuilder' field for op " + op.getOperationName()); 118 119 // Return early if there is no builder specified. 120 auto builderStrRef = record.getValueAsString("llvmBuilder"); 121 if (builderStrRef.empty()) 122 return true; 123 124 // Progressively create the builder string by replacing $-variables with 125 // value lookups. Keep only the not-yet-traversed part of the builder pattern 126 // to avoid re-traversing the string multiple times. 127 std::string builder; 128 llvm::raw_string_ostream bs(builder); 129 while (auto loc = findNextVariable(builderStrRef)) { 130 auto name = loc.in(builderStrRef).drop_front(); 131 // First, insert the non-matched part as is. 132 bs << builderStrRef.substr(0, loc.pos); 133 // Then, rewrite the name based on its kind. 134 bool isVariadicOperand = isVariadicOperandName(op, name); 135 if (isOperandName(op, name)) { 136 auto result = isVariadicOperand 137 ? formatv("lookupValues(op.{0}())", name) 138 : formatv("valueMapping.lookup(op.{0}())", name); 139 bs << result; 140 } else if (isAttributeName(op, name)) { 141 bs << formatv("op.{0}()", name); 142 } else if (isResultName(op, name)) { 143 bs << formatv("valueMapping[op.{0}()]", name); 144 } else if (name == "_resultType") { 145 bs << "op.getResult()->getType().cast<LLVM::LLVMType>()." 146 "getUnderlyingType()"; 147 } else if (name == "_hasResult") { 148 bs << "opInst.getNumResults() == 1"; 149 } else if (name == "_location") { 150 bs << "opInst.getLoc()"; 151 } else if (name == "_numOperands") { 152 bs << "opInst.getNumOperands()"; 153 } else if (name == "$") { 154 bs << '$'; 155 } else { 156 return emitError(name + " is neither an argument nor a result of " + 157 op.getOperationName()); 158 } 159 // Finally, only keep the untraversed part of the string. 160 builderStrRef = builderStrRef.substr(loc.pos + loc.length); 161 } 162 163 // Output the check and the rewritten builder string. 164 os << "if (auto op = dyn_cast<" << op.getQualCppClassName() 165 << ">(opInst)) {\n"; 166 os << bs.str() << builderStrRef << "\n"; 167 os << " return success();\n"; 168 os << "}\n"; 169 170 return true; 171 } 172 173 // Emit all builders. Returns false on success because of the generator 174 // registration requirements. 175 static bool emitBuilders(const RecordKeeper &recordKeeper, raw_ostream &os) { 176 for (const auto *def : recordKeeper.getAllDerivedDefinitions("LLVM_OpBase")) { 177 if (!emitOneBuilder(*def, os)) 178 return true; 179 } 180 return false; 181 } 182 183 static mlir::GenRegistration 184 genLLVMIRConversions("gen-llvmir-conversions", 185 "Generate LLVM IR conversions", emitBuilders);