brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.3 KiB · a514ea9 Raw
442 lines · cpp
1//===- WasmSSAOps.cpp - WasmSSA dialect operations ----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===---------------------------------------------------------------------===//8 9#include "mlir/Dialect/WasmSSA/IR/WasmSSA.h"10#include "mlir/Dialect/WasmSSA/IR/WasmSSAInterfaces.h"11 12#include "mlir/IR/Attributes.h"13#include "mlir/IR/Builders.h"14#include "mlir/IR/BuiltinAttributes.h"15#include "mlir/IR/Diagnostics.h"16#include "mlir/IR/Dialect.h"17#include "mlir/IR/Region.h"18#include "mlir/IR/SymbolTable.h"19#include "mlir/Interfaces/FunctionImplementation.h"20#include "llvm/Support/Casting.h"21 22//===----------------------------------------------------------------------===//23// TableGen'd op method definitions24//===----------------------------------------------------------------------===//25 26using namespace mlir;27namespace {28ParseResult parseElseRegion(OpAsmParser &opParser, Region &elseRegion) {29  std::string keyword;30  std::ignore = opParser.parseOptionalKeywordOrString(&keyword);31  if (keyword == "else")32    return opParser.parseRegion(elseRegion);33  return ParseResult::success();34}35 36void printElseRegion(OpAsmPrinter &opPrinter, Operation *op,37                     Region &elseRegion) {38  if (elseRegion.empty())39    return;40  opPrinter.printKeywordOrString("else ");41  opPrinter.printRegion(elseRegion);42}43} // namespace44 45#define GET_OP_CLASSES46#include "mlir/Dialect/WasmSSA/IR/WasmSSAOps.cpp.inc"47 48#include "mlir/IR/OpImplementation.h"49#include "mlir/IR/Types.h"50#include "llvm/Support/LogicalResult.h"51 52using namespace wasmssa;53 54namespace {55inline LogicalResult56inferTeeGetResType(ValueRange operands,57                   SmallVectorImpl<Type> &inferredReturnTypes) {58  if (operands.empty())59    return failure();60  auto opType = dyn_cast<LocalRefType>(operands.front().getType());61  if (!opType)62    return failure();63  inferredReturnTypes.push_back(opType.getElementType());64  return success();65}66 67ParseResult parseImportOp(OpAsmParser &parser, OperationState &result) {68  std::string importName;69  auto *ctx = parser.getContext();70  ParseResult res = parser.parseString(&importName);71  result.addAttribute("importName", StringAttr::get(ctx, importName));72 73  std::string fromStr;74  res = parser.parseKeywordOrString(&fromStr);75  if (failed(res) || fromStr != "from")76    return failure();77 78  std::string moduleName;79  res = parser.parseString(&moduleName);80  if (failed(res))81    return failure();82  result.addAttribute("moduleName", StringAttr::get(ctx, moduleName));83 84  std::string asStr;85  res = parser.parseKeywordOrString(&asStr);86  if (failed(res) || asStr != "as")87    return failure();88 89  StringAttr symbolName;90  res = parser.parseSymbolName(symbolName, SymbolTable::getSymbolAttrName(),91                               result.attributes);92  return res;93}94} // namespace95 96//===----------------------------------------------------------------------===//97// BlockOp98//===----------------------------------------------------------------------===//99 100Block *BlockOp::getLabelTarget() { return getTarget(); }101 102//===----------------------------------------------------------------------===//103// BlockReturnOp104//===----------------------------------------------------------------------===//105 106std::size_t BlockReturnOp::getExitLevel() { return 0; }107 108Block *BlockReturnOp::getTarget() {109  return cast<LabelBranchingOpInterface>(getOperation())110      .getTargetOp()111      .getOperation()112      ->getSuccessor(0);113}114 115//===----------------------------------------------------------------------===//116// ExtendLowBitsSOp117//===----------------------------------------------------------------------===//118 119LogicalResult ExtendLowBitsSOp::verify() {120  auto bitsToTake = getBitsToTake().getValue().getLimitedValue();121  if (bitsToTake != 32 && bitsToTake != 16 && bitsToTake != 8)122    return emitError("extend op can only take 8, 16 or 32 bits. Got ")123           << bitsToTake;124 125  if (bitsToTake >= getInput().getType().getIntOrFloatBitWidth())126    return emitError("trying to extend the ")127           << bitsToTake << " low bits from a " << getInput().getType()128           << " value is illegal";129  return success();130}131 132//===----------------------------------------------------------------------===//133// FuncOp134//===----------------------------------------------------------------------===//135 136Block *FuncOp::addEntryBlock() {137  if (!getBody().empty()) {138    emitError("adding entry block to a FuncOp which already has one");139    return &getBody().front();140  }141  Block &block = getBody().emplaceBlock();142  for (auto argType : getFunctionType().getInputs())143    block.addArgument(LocalRefType::get(argType), getLoc());144  return &block;145}146 147void FuncOp::build(OpBuilder &odsBuilder, OperationState &odsState,148                   StringRef symbol, FunctionType funcType) {149  FuncOp::build(odsBuilder, odsState, symbol, funcType, {}, {});150}151 152ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {153  auto *ctx = parser.getContext();154  std::string visibilityString;155  auto loc = parser.getNameLoc();156  ParseResult res = parser.parseOptionalKeywordOrString(&visibilityString);157  bool exported{false};158  if (res.succeeded()) {159    if (visibilityString != "exported")160      return parser.emitError(161                 loc, "expecting either `exported` or symbol name. got ")162             << visibilityString;163    exported = true;164  }165 166  auto buildFuncType = [&parser](Builder &builder, ArrayRef<Type> argTypes,167                                 ArrayRef<Type> results,168                                 function_interface_impl::VariadicFlag,169                                 std::string &) {170    SmallVector<Type> argTypesWithoutLocal{};171    argTypesWithoutLocal.reserve(argTypes.size());172    llvm::for_each(argTypes, [&parser, &argTypesWithoutLocal](Type argType) {173      auto refType = dyn_cast<LocalRefType>(argType);174      auto loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());175      if (!refType) {176        mlir::emitError(loc, "invalid type for wasm.func argument. Expecting "177                             "!wasm<local T>, got ")178            << argType;179        return;180      }181      argTypesWithoutLocal.push_back(refType.getElementType());182    });183 184    return builder.getFunctionType(argTypesWithoutLocal, results);185  };186  auto funcParseRes = function_interface_impl::parseFunctionOp(187      parser, result, /*allowVariadic=*/false,188      getFunctionTypeAttrName(result.name), buildFuncType,189      getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));190  if (exported)191    result.addAttribute(getExportedAttrName(result.name), UnitAttr::get(ctx));192  return funcParseRes;193}194 195LogicalResult FuncOp::verifyBody() {196  if (getBody().empty())197    return success();198  Block &entry = getBody().front();199  if (entry.getNumArguments() != getFunctionType().getNumInputs())200    return emitError("entry block should have same number of arguments as "201                     "function type. Function type has ")202           << getFunctionType().getNumInputs() << ", entry block has "203           << entry.getNumArguments();204 205  for (auto [argNo, funcSignatureType, blockType] : llvm::enumerate(206           getFunctionType().getInputs(), entry.getArgumentTypes())) {207    auto blockLocalRefType = dyn_cast<LocalRefType>(blockType);208    if (!blockLocalRefType)209      return emitError("entry block argument type should be LocalRefType, got ")210             << blockType << " for block argument " << argNo;211    if (blockLocalRefType.getElementType() != funcSignatureType)212      return emitError("func argument type #")213             << argNo << "(" << funcSignatureType214             << ") doesn't match entry block referenced type ("215             << blockLocalRefType.getElementType() << ")";216  }217  return success();218}219 220void FuncOp::print(OpAsmPrinter &p) {221  /// If exported, print it before and mask it before printing222  /// using generic interface.223  auto exported = getExported();224  if (exported) {225    p << " exported";226    removeExportedAttr();227  }228  function_interface_impl::printFunctionOp(229      p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),230      getArgAttrsAttrName(), getResAttrsAttrName());231  if (exported)232    setExported(true);233}234 235//===----------------------------------------------------------------------===//236// FuncImportOp237//===----------------------------------------------------------------------===//238 239void FuncImportOp::build(OpBuilder &odsBuilder, OperationState &odsState,240                         StringRef symbol, StringRef moduleName,241                         StringRef importName, FunctionType type) {242  FuncImportOp::build(odsBuilder, odsState, symbol, moduleName, importName,243                      type, {}, {});244}245 246//===----------------------------------------------------------------------===//247// GlobalOp248//===----------------------------------------------------------------------===//249// Custom formats250ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {251  StringAttr symbolName;252  Type globalType;253  auto *ctx = parser.getContext();254  std::string visibilityString;255  auto loc = parser.getNameLoc();256  ParseResult res = parser.parseOptionalKeywordOrString(&visibilityString);257  if (res.succeeded()) {258    if (visibilityString != "exported")259      return parser.emitError(260                 loc, "expecting either `exported` or symbol name. got ")261             << visibilityString;262    result.addAttribute(getExportedAttrName(result.name), UnitAttr::get(ctx));263  }264 265  res = parser.parseSymbolName(symbolName, SymbolTable::getSymbolAttrName(),266                               result.attributes);267  res = parser.parseType(globalType);268  result.addAttribute(getTypeAttrName(result.name), TypeAttr::get(globalType));269  std::string mutableString;270  res = parser.parseOptionalKeywordOrString(&mutableString);271  if (res.succeeded() && mutableString == "mutable")272    result.addAttribute("isMutable", UnitAttr::get(ctx));273 274  res = parser.parseColon();275  Region *globalInitRegion = result.addRegion();276  res = parser.parseRegion(*globalInitRegion);277  return res;278}279 280void GlobalOp::print(OpAsmPrinter &printer) {281  if (getExported())282    printer << " exported";283  printer << " @" << getSymName().str() << " " << getType();284  if (getIsMutable())285    printer << " mutable";286  printer << " :";287  Region &body = getRegion();288  if (!body.empty()) {289    printer << ' ';290    printer.printRegion(body, /*printEntryBlockArgs=*/false,291                        /*printBlockTerminators=*/true);292  }293}294 295//===----------------------------------------------------------------------===//296// GlobalGetOp297//===----------------------------------------------------------------------===//298 299LogicalResult300GlobalGetOp::verifySymbolUses(SymbolTableCollection &symbolTable) {301  // If the parent requires a constant context, verify that global.get is a302  // constant as defined per the wasm standard.303  if (!this->getOperation()304           ->getParentWithTrait<ConstantExpressionInitializerOpTrait>())305    return success();306  Operation *symTabOp = SymbolTable::getNearestSymbolTable(*this);307  StringRef referencedSymbol = getGlobal();308  Operation *definitionOp = symbolTable.lookupSymbolIn(309      symTabOp, StringAttr::get(this->getContext(), referencedSymbol));310  if (!definitionOp)311    return emitError() << "symbol @" << referencedSymbol << " is undefined";312  auto definitionImport = dyn_cast<GlobalImportOp>(definitionOp);313  if (!definitionImport || definitionImport.getIsMutable()) {314    return emitError("global.get op is considered constant if it's referring "315                     "to a import.global symbol marked non-mutable");316  }317  return success();318}319 320//===----------------------------------------------------------------------===//321// GlobalImportOp322//===----------------------------------------------------------------------===//323 324ParseResult GlobalImportOp::parse(OpAsmParser &parser, OperationState &result) {325  auto *ctx = parser.getContext();326  ParseResult res = parseImportOp(parser, result);327  if (res.failed())328    return failure();329  std::string mutableOrSymVisString;330  res = parser.parseOptionalKeywordOrString(&mutableOrSymVisString);331  if (res.succeeded() && mutableOrSymVisString == "mutable") {332    result.addAttribute("isMutable", UnitAttr::get(ctx));333  }334 335  res = parser.parseColon();336 337  Type importedType;338  res = parser.parseType(importedType);339  if (res.succeeded())340    result.addAttribute(getTypeAttrName(result.name),341                        TypeAttr::get(importedType));342  return res;343}344 345void GlobalImportOp::print(OpAsmPrinter &printer) {346  printer << " \"" << getImportName() << "\" from \"" << getModuleName()347          << "\" as @" << getSymName();348  if (getIsMutable())349    printer << " mutable";350  printer << " : " << getType();351}352 353//===----------------------------------------------------------------------===//354// IfOp355//===----------------------------------------------------------------------===//356 357Block *IfOp::getLabelTarget() { return getTarget(); }358 359//===----------------------------------------------------------------------===//360// LocalOp361//===----------------------------------------------------------------------===//362 363LogicalResult LocalOp::inferReturnTypes(364    MLIRContext *context, ::std::optional<Location> location,365    ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,366    RegionRange regions, SmallVectorImpl<Type> &inferredReturnTypes) {367  LocalOp::GenericAdaptor<ValueRange> adaptor{operands, attributes, properties,368                                              regions};369  auto type = adaptor.getTypeAttr();370  if (!type)371    return failure();372  auto resType = LocalRefType::get(type.getContext(), type.getValue());373  inferredReturnTypes.push_back(resType);374  return success();375}376 377//===----------------------------------------------------------------------===//378// LocalGetOp379//===----------------------------------------------------------------------===//380 381LogicalResult LocalGetOp::inferReturnTypes(382    MLIRContext *context, ::std::optional<Location> location,383    ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,384    RegionRange regions, SmallVectorImpl<Type> &inferredReturnTypes) {385  return inferTeeGetResType(operands, inferredReturnTypes);386}387 388//===----------------------------------------------------------------------===//389// LocalSetOp390//===----------------------------------------------------------------------===//391 392LogicalResult LocalSetOp::verify() {393  if (getLocalVar().getType().getElementType() != getValue().getType())394    return emitError("input type and result type of local.set do not match");395  return success();396}397 398//===----------------------------------------------------------------------===//399// LocalTeeOp400//===----------------------------------------------------------------------===//401 402LogicalResult LocalTeeOp::inferReturnTypes(403    MLIRContext *context, ::std::optional<Location> location,404    ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,405    RegionRange regions, SmallVectorImpl<Type> &inferredReturnTypes) {406  return inferTeeGetResType(operands, inferredReturnTypes);407}408 409LogicalResult LocalTeeOp::verify() {410  if (getLocalVar().getType().getElementType() != getValue().getType() ||411      getValue().getType() != getResult().getType())412    return emitError("input type and output type of local.tee do not match");413  return success();414}415 416//===----------------------------------------------------------------------===//417// LoopOp418//===----------------------------------------------------------------------===//419 420Block *LoopOp::getLabelTarget() { return &getBody().front(); }421 422//===----------------------------------------------------------------------===//423// ReinterpretOp424//===----------------------------------------------------------------------===//425 426LogicalResult ReinterpretOp::verify() {427  auto inT = getInput().getType();428  auto resT = getResult().getType();429  if (inT == resT)430    return emitError("reinterpret input and output type should be distinct");431  if (inT.getIntOrFloatBitWidth() != resT.getIntOrFloatBitWidth())432    return emitError() << "input type (" << inT << ") and output type (" << resT433                       << ") have incompatible bit widths";434  return success();435}436 437//===----------------------------------------------------------------------===//438// ReturnOp439//===----------------------------------------------------------------------===//440 441void ReturnOp::build(OpBuilder &odsBuilder, OperationState &odsState) {}442