//===- LLVMAttrs.cpp - LLVM Attributes registration -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the attribute details for the LLVM IR dialect in MLIR. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/BinaryFormat/Dwarf.h" using namespace mlir; using namespace mlir::LLVM; #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc" #define GET_ATTRDEF_CLASSES #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" //===----------------------------------------------------------------------===// // LLVMDialect registration //===----------------------------------------------------------------------===// void LLVMDialect::registerAttributes() { addAttributes< #define GET_ATTRDEF_LIST #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" >(); } //===----------------------------------------------------------------------===// // DINodeAttr //===----------------------------------------------------------------------===// bool DINodeAttr::classof(Attribute attr) { return llvm::isa( attr); } //===----------------------------------------------------------------------===// // DIScopeAttr //===----------------------------------------------------------------------===// bool DIScopeAttr::classof(Attribute attr) { return llvm::isa(attr); } //===----------------------------------------------------------------------===// // DITypeAttr //===----------------------------------------------------------------------===// bool DITypeAttr::classof(Attribute attr) { return llvm::isa(attr); } //===----------------------------------------------------------------------===// // LoopOptionsAttrBuilder //===----------------------------------------------------------------------===// LoopOptionsAttrBuilder::LoopOptionsAttrBuilder(LoopOptionsAttr attr) : options(attr.getOptions().begin(), attr.getOptions().end()) {} template LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setOption(LoopOptionCase tag, Optional value) { auto option = llvm::find_if( options, [tag](auto option) { return option.first == tag; }); if (option != options.end()) { if (value) option->second = *value; else options.erase(option); } else { options.push_back(LoopOptionsAttr::OptionValuePair(tag, *value)); } return *this; } LoopOptionsAttrBuilder & LoopOptionsAttrBuilder::setDisableLICM(Optional value) { return setOption(LoopOptionCase::disable_licm, value); } /// Set the `interleave_count` option to the provided value. If no value /// is provided the option is deleted. LoopOptionsAttrBuilder & LoopOptionsAttrBuilder::setInterleaveCount(Optional count) { return setOption(LoopOptionCase::interleave_count, count); } /// Set the `disable_unroll` option to the provided value. If no value /// is provided the option is deleted. LoopOptionsAttrBuilder & LoopOptionsAttrBuilder::setDisableUnroll(Optional value) { return setOption(LoopOptionCase::disable_unroll, value); } /// Set the `disable_pipeline` option to the provided value. If no value /// is provided the option is deleted. LoopOptionsAttrBuilder & LoopOptionsAttrBuilder::setDisablePipeline(Optional value) { return setOption(LoopOptionCase::disable_pipeline, value); } /// Set the `pipeline_initiation_interval` option to the provided value. /// If no value is provided the option is deleted. LoopOptionsAttrBuilder &LoopOptionsAttrBuilder::setPipelineInitiationInterval( Optional count) { return setOption(LoopOptionCase::pipeline_initiation_interval, count); } //===----------------------------------------------------------------------===// // LoopOptionsAttr //===----------------------------------------------------------------------===// template static Optional getOption(ArrayRef> options, LoopOptionCase option) { auto it = lower_bound(options, option, [](auto optionPair, LoopOptionCase option) { return optionPair.first < option; }); if (it == options.end()) return {}; return static_cast(it->second); } Optional LoopOptionsAttr::disableUnroll() { return getOption(getOptions(), LoopOptionCase::disable_unroll); } Optional LoopOptionsAttr::disableLICM() { return getOption(getOptions(), LoopOptionCase::disable_licm); } Optional LoopOptionsAttr::interleaveCount() { return getOption(getOptions(), LoopOptionCase::interleave_count); } /// Build the LoopOptions Attribute from a sorted array of individual options. LoopOptionsAttr LoopOptionsAttr::get( MLIRContext *context, ArrayRef> sortedOptions) { assert(llvm::is_sorted(sortedOptions, llvm::less_first()) && "LoopOptionsAttr ctor expects a sorted options array"); return Base::get(context, sortedOptions); } /// Build the LoopOptions Attribute from a sorted array of individual options. LoopOptionsAttr LoopOptionsAttr::get(MLIRContext *context, LoopOptionsAttrBuilder &optionBuilders) { llvm::sort(optionBuilders.options, llvm::less_first()); return Base::get(context, optionBuilders.options); } void LoopOptionsAttr::print(AsmPrinter &printer) const { printer << "<"; llvm::interleaveComma(getOptions(), printer, [&](auto option) { printer << stringifyEnum(option.first) << " = "; switch (option.first) { case LoopOptionCase::disable_licm: case LoopOptionCase::disable_unroll: case LoopOptionCase::disable_pipeline: printer << (option.second ? "true" : "false"); break; case LoopOptionCase::interleave_count: case LoopOptionCase::pipeline_initiation_interval: printer << option.second; break; } }); printer << ">"; } Attribute LoopOptionsAttr::parse(AsmParser &parser, Type type) { if (failed(parser.parseLess())) return {}; SmallVector> options; llvm::SmallDenseSet seenOptions; auto parseLoopOptions = [&]() -> ParseResult { StringRef optionName; if (parser.parseKeyword(&optionName)) return failure(); auto option = symbolizeLoopOptionCase(optionName); if (!option) return parser.emitError(parser.getNameLoc(), "unknown loop option: ") << optionName; if (!seenOptions.insert(*option).second) return parser.emitError(parser.getNameLoc(), "loop option present twice"); if (failed(parser.parseEqual())) return failure(); int64_t value; switch (*option) { case LoopOptionCase::disable_licm: case LoopOptionCase::disable_unroll: case LoopOptionCase::disable_pipeline: if (succeeded(parser.parseOptionalKeyword("true"))) value = 1; else if (succeeded(parser.parseOptionalKeyword("false"))) value = 0; else { return parser.emitError(parser.getNameLoc(), "expected boolean value 'true' or 'false'"); } break; case LoopOptionCase::interleave_count: case LoopOptionCase::pipeline_initiation_interval: if (failed(parser.parseInteger(value))) return parser.emitError(parser.getNameLoc(), "expected integer value"); break; } options.push_back(std::make_pair(*option, value)); return success(); }; if (parser.parseCommaSeparatedList(parseLoopOptions) || parser.parseGreater()) return {}; llvm::sort(options, llvm::less_first()); return get(parser.getContext(), options); }