#define MLIR_DIALECT_LLVMIR_LLVMDIALECT_H_
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Dialect.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
-#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h.inc"
-
namespace llvm {
class Type;
class LLVMContext;
--- /dev/null
+//===- LLVMInterfaces.h - LLVM Interfaces -----------------------*- C++ -*-===//
+//
+// 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 op interfaces for the LLVM dialect in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_LLVMIR_LLVMINTERFACES_H_
+#define MLIR_DIALECT_LLVMIR_LLVMINTERFACES_H_
+
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+
+namespace mlir {
+namespace LLVM {
+namespace detail {
+
+/// Verifies the access groups attribute of memory operations that implement the
+/// access group interface.
+LogicalResult verifyAccessGroupOpInterface(Operation *op);
+
+/// Verifies the alias analysis attributes of memory operations that implement
+/// the alias analysis interface.
+LogicalResult verifyAliasAnalysisOpInterface(Operation *op);
+
+} // namespace detail
+} // namespace LLVM
+} // namespace mlir
+
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h.inc"
+
+#endif // MLIR_DIALECT_LLVMIR_LLVMINTERFACES_H_
];
}
+def AccessGroupOpInterface : OpInterface<"AccessGroupOpInterface"> {
+ let description = [{
+ An interface for memory operations that can carry access groups metadata.
+ It provides setters and getters for the operation's access groups attribute.
+ The default implementations of the interface methods expect the operation
+ to have an attribute of type ArrayAttr named access_groups.
+ }];
+
+ let cppNamespace = "::mlir::LLVM";
+ let verify = [{ return detail::verifyAccessGroupOpInterface($_op); }];
+
+ let methods = [
+ InterfaceMethod<
+ /*desc=*/ "Returns the access groups attribute or nullptr",
+ /*returnType=*/ "ArrayAttr",
+ /*methodName=*/ "getAccessGroupsOrNull",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ return op.getAccessGroupsAttr();
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Sets the access groups attribute",
+ /*returnType=*/ "void",
+ /*methodName=*/ "setAccessGroups",
+ /*args=*/ (ins "const ArrayAttr":$attr),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ op.setAccessGroupsAttr(attr);
+ }]
+ >
+ ];
+}
+
+def AliasAnalysisOpInterface : OpInterface<"AliasAnalysisOpInterface"> {
+ let description = [{
+ An interface for memory operations that can carry alias analysis metadata.
+ It provides setters and getters for the operation's alias analysis
+ attributes. The default implementations of the interface methods expect
+ the operation to have attributes of type ArrayAttr named alias_scopes,
+ noalias_scopes, and tbaa.
+ }];
+
+ let cppNamespace = "::mlir::LLVM";
+ let verify = [{ return detail::verifyAliasAnalysisOpInterface($_op); }];
+
+ let methods = [
+ InterfaceMethod<
+ /*desc=*/ "Returns the alias scopes attribute or nullptr",
+ /*returnType=*/ "ArrayAttr",
+ /*methodName=*/ "getAliasScopesOrNull",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ return op.getAliasScopesAttr();
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Sets the alias scopes attribute",
+ /*returnType=*/ "void",
+ /*methodName=*/ "setAliasScopes",
+ /*args=*/ (ins "const ArrayAttr":$attr),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ op.setAliasScopesAttr(attr);
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Returns the noalias scopes attribute or nullptr",
+ /*returnType=*/ "ArrayAttr",
+ /*methodName=*/ "getNoAliasScopesOrNull",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ return op.getNoaliasScopesAttr();
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Sets the noalias scopes attribute",
+ /*returnType=*/ "void",
+ /*methodName=*/ "setNoAliasScopes",
+ /*args=*/ (ins "const ArrayAttr":$attr),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ op.setNoaliasScopesAttr(attr);
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Returns the tbaa attribute or nullptr",
+ /*returnType=*/ "ArrayAttr",
+ /*methodName=*/ "getTBAATagsOrNull",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ return op.getTbaaAttr();
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Sets the tbaa attribute",
+ /*returnType=*/ "void",
+ /*methodName=*/ "setTBAATags",
+ /*args=*/ (ins "const ArrayAttr":$attr),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ ConcreteOp op = cast<ConcreteOp>(this->getOperation());
+ op.setTbaaAttr(attr);
+ }]
+ >
+ ];
+}
+
//===----------------------------------------------------------------------===//
// LLVM dialect type interfaces.
//===----------------------------------------------------------------------===//
];
}
-
#endif // LLVMIR_INTERFACES
}
//===----------------------------------------------------------------------===//
-// Base classes for LLVM dialect operations.
+// Base classes for LLVM enum attributes.
//===----------------------------------------------------------------------===//
-// Base class for LLVM operations. All operations get an "llvm." prefix in
-// their name automatically. LLVM operations have either zero or one result,
-// this class is specialized below for both cases and should not be used
-// directly.
-class LLVM_Op<string mnemonic, list<Trait> traits = []> :
- LLVM_OpBase<LLVM_Dialect, mnemonic, traits>;
-
// Case of the LLVM enum attribute backed by I64Attr with customized string
// representation that corresponds to what is visible in the textual IR form.
// The parameters are as follows:
// is printed/parsed as `weak` in MLIR custom textual format.
class LLVM_EnumAttrCase<string cppSym, string irSym, string llvmSym, int val> :
I64EnumAttrCase<cppSym, val, irSym> {
-
// The name of the equivalent enumerant in LLVM.
string llvmEnumerant = llvmSym;
}
list<LLVM_EnumAttrCase> cases,
list<LLVM_EnumAttrCase> unsupportedCases = []> :
I64EnumAttr<name, description, cases> {
-
-
// List of unsupported cases that have no conversion to an MLIR value.
list<LLVM_EnumAttrCase> unsupported = unsupportedCases;
string llvmClassName = llvmNS;
}
-// For every value in the list, substitutes the value in the place of "$0" in
-// "pattern" and stores the list of strings as "lst".
-class ListIntSubst<string pattern, list<int> values> {
- list<string> lst = !foreach(x, values,
- !subst("$0", !cast<string>(x), pattern));
+//===----------------------------------------------------------------------===//
+// Patterns for LLVM dialect operations.
+//===----------------------------------------------------------------------===//
+
+// Patterns with code to set flags and metadata of memory operations after their
+// translation to LLVM IR instructions. Operations may use the patterns to
+// implement their "llvmBuilder". The patterns assume the `op` and `inst`
+// variables exist and refer to the original MLIR operation and the translated
+// LLVM IR instruction, respectively.
+class LLVM_MemOpPatterns {
+ code setAlignmentCode = [{
+ if ($alignment.has_value()) {
+ auto align = *$alignment;
+ if (align != 0)
+ inst->setAlignment(llvm::Align(align));
+ }
+ }];
+ code setVolatileCode = [{
+ inst->setVolatile($volatile_);
+ }];
+ code setSyncScopeCode = [{
+ if ($syncscope.has_value()) {
+ llvm::LLVMContext &llvmContext = builder.getContext();
+ inst->setSyncScopeID(llvmContext.getOrInsertSyncScopeID(*$syncscope));
+ }
+ }];
+ code setOrderingCode = [{
+ inst->setAtomic(convertAtomicOrderingToLLVM($ordering));
+ }];
+ code setNonTemporalMetadataCode = [{
+ if ($nontemporal) {
+ llvm::MDNode *metadata = llvm::MDNode::get(
+ inst->getContext(), llvm::ConstantAsMetadata::get(
+ builder.getInt32(1)));
+ inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata);
+ }
+ }];
+ code setAccessGroupsMetadataCode = [{
+ moduleTranslation.setAccessGroupsMetadata(op, inst);
+ }];
+ code setAliasAnalysisMetadataCode = [{
+ moduleTranslation.setAliasScopeMetadata(op, inst);
+ moduleTranslation.setTBAAMetadata(op, inst);
+ }];
}
// Patterns with code obtaining the LLVM IR type of the given operand or result
.getBody()[$0])}];
}
+// For every value in the list, substitutes the value in the place of "$0" in
+// "pattern" and stores the list of strings as "lst".
+class ListIntSubst<string pattern, list<int> values> {
+ list<string> lst = !foreach(x, values,
+ !subst("$0", !cast<string>(x), pattern));
+}
+
+//===----------------------------------------------------------------------===//
+// Base classes for LLVM dialect operations.
+//===----------------------------------------------------------------------===//
+
+// Base class for LLVM operations. All operations get an "llvm." prefix in
+// their name automatically and should either have zero or one result.
+class LLVM_Op<string mnemonic, list<Trait> traits = []> :
+ LLVM_OpBase<LLVM_Dialect, mnemonic, traits>;
+
+// Base class for LLVM memory access operations that implement the access group
+// and alias analysis interfaces. The "aliasAttrs" list contains the arguments
+// required by the access group and alias analysis interfaces. Derived
+// operations should append the "aliasAttrs" to their argument list.
+class LLVM_MemAccessOpBase<string mnemonic, list<Trait> traits = []> :
+ LLVM_Op<mnemonic, !listconcat([
+ DeclareOpInterfaceMethods<AccessGroupOpInterface>,
+ DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], traits)>,
+ LLVM_MemOpPatterns {
+ dag aliasAttrs = (ins OptionalAttr<SymbolRefArrayAttr>:$access_groups,
+ OptionalAttr<SymbolRefArrayAttr>:$alias_scopes,
+ OptionalAttr<SymbolRefArrayAttr>:$noalias_scopes,
+ OptionalAttr<SymbolRefArrayAttr>:$tbaa);
+}
// Base class for LLVM intrinsics operation. It is similar to LLVM_Op, but
// provides the "llvmBuilder" field for constructing the intrinsic.
def LLVM_FNegOp : LLVM_UnaryFloatArithmeticOp<
LLVM_ScalarOrVectorOf<LLVM_AnyFloat>, "fneg", "FNeg">;
-// Common code definitions used to set memory operation attributes and flags.
-class MemoryOpBase {
- code setAlignmentCode = [{
- if ($alignment.has_value()) {
- auto align = *$alignment;
- if (align != 0)
- inst->setAlignment(llvm::Align(align));
- }
- }];
- code setVolatileCode = [{
- inst->setVolatile($volatile_);
- }];
- code setSyncScopeCode = [{
- if ($syncscope.has_value()) {
- llvm::LLVMContext &llvmContext = builder.getContext();
- inst->setSyncScopeID(llvmContext.getOrInsertSyncScopeID(*$syncscope));
- }
- }];
- code setOrderingCode = [{
- inst->setAtomic(convertAtomicOrderingToLLVM($ordering));
- }];
- code setNonTemporalMetadataCode = [{
- if ($nontemporal) {
- llvm::MDNode *metadata = llvm::MDNode::get(
- inst->getContext(), llvm::ConstantAsMetadata::get(
- builder.getInt32(1)));
- inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata);
- }
- }];
- code setAccessGroupsMetadataCode = [{
- moduleTranslation.setAccessGroupsMetadata(op, inst);
- }];
- code setAliasScopeMetadataCode = [{
- moduleTranslation.setAliasScopeMetadata(op, inst);
- }];
- code setTBAAMetadataCode = [{
- moduleTranslation.setTBAAMetadata(op, inst);
- }];
-}
-
// Memory-related operations.
-def LLVM_AllocaOp : LLVM_Op<"alloca">, MemoryOpBase {
+def LLVM_AllocaOp : LLVM_Op<"alloca">, LLVM_MemOpPatterns {
let arguments = (ins AnyInteger:$arraySize,
OptionalAttr<I64Attr>:$alignment,
OptionalAttr<TypeAttr>:$elem_type);
let hasVerifier = 1;
}
-def LLVM_LoadOp : LLVM_Op<"load">, MemoryOpBase {
- let arguments = (ins Arg<LLVM_PointerTo<LLVM_LoadableType>, "", [MemRead]>:$addr,
- OptionalAttr<SymbolRefArrayAttr>:$access_groups,
- OptionalAttr<SymbolRefArrayAttr>:$alias_scopes,
- OptionalAttr<SymbolRefArrayAttr>:$noalias_scopes,
- OptionalAttr<SymbolRefArrayAttr>:$tbaa,
- OptionalAttr<I64Attr>:$alignment,
- UnitAttr:$volatile_,
- UnitAttr:$nontemporal,
- DefaultValuedAttr<AtomicOrdering,
- "AtomicOrdering::not_atomic">:$ordering,
- OptionalAttr<StrAttr>:$syncscope);
+def LLVM_LoadOp : LLVM_MemAccessOpBase<"load"> {
+ dag args = (ins Arg<LLVM_PointerTo<LLVM_LoadableType>, "", [MemRead]>:$addr,
+ OptionalAttr<I64Attr>:$alignment,
+ UnitAttr:$volatile_,
+ UnitAttr:$nontemporal,
+ DefaultValuedAttr<
+ AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
+ OptionalAttr<StrAttr>:$syncscope);
+ // Append the aliasing related attributes define in LLVM_MemAccessOpBase.
+ let arguments = !con(args, aliasAttrs);
let results = (outs LLVM_LoadableType:$res);
string llvmInstName = "Load";
let description = [{
}];
string llvmBuilder = [{
auto *inst = builder.CreateLoad($_resultType, $addr, $volatile_);
+ $res = inst;
}] # setOrderingCode
# setSyncScopeCode
# setAlignmentCode
# setNonTemporalMetadataCode
# setAccessGroupsMetadataCode
- # setAliasScopeMetadataCode
- # setTBAAMetadataCode
- # [{
- $res = inst;
- }];
+ # setAliasAnalysisMetadataCode;
string mlirBuilder = [{
auto *loadInst = cast<llvm::LoadInst>(inst);
unsigned alignment = loadInst->getAlign().value();
let hasVerifier = 1;
}
-def LLVM_StoreOp : LLVM_Op<"store">, MemoryOpBase {
- let arguments = (ins LLVM_LoadableType:$value,
- Arg<LLVM_PointerTo<LLVM_LoadableType>,"",[MemWrite]>:$addr,
- OptionalAttr<SymbolRefArrayAttr>:$access_groups,
- OptionalAttr<SymbolRefArrayAttr>:$alias_scopes,
- OptionalAttr<SymbolRefArrayAttr>:$noalias_scopes,
- OptionalAttr<SymbolRefArrayAttr>:$tbaa,
- OptionalAttr<I64Attr>:$alignment,
- UnitAttr:$volatile_,
- UnitAttr:$nontemporal,
- DefaultValuedAttr<AtomicOrdering,
- "AtomicOrdering::not_atomic">:$ordering,
- OptionalAttr<StrAttr>:$syncscope);
+def LLVM_StoreOp : LLVM_MemAccessOpBase<"store"> {
+ dag args = (ins LLVM_LoadableType:$value,
+ Arg<LLVM_PointerTo<LLVM_LoadableType>,"",[MemWrite]>:$addr,
+ OptionalAttr<I64Attr>:$alignment,
+ UnitAttr:$volatile_,
+ UnitAttr:$nontemporal,
+ DefaultValuedAttr<
+ AtomicOrdering, "AtomicOrdering::not_atomic">:$ordering,
+ OptionalAttr<StrAttr>:$syncscope);
+ // Append the aliasing related attributes define in LLVM_MemAccessOpBase.
+ let arguments = !con(args, aliasAttrs);
string llvmInstName = "Store";
let description = [{
The `store` operation is used to write to memory. A store may be marked as
# setAlignmentCode
# setNonTemporalMetadataCode
# setAccessGroupsMetadataCode
- # setAliasScopeMetadataCode
- # setTBAAMetadataCode;
+ # setAliasAnalysisMetadataCode;
string mlirBuilder = [{
auto *storeInst = cast<llvm::StoreInst>(inst);
unsigned alignment = storeInst->getAlign().value();
def LLVM_AtomicRMWType : AnyTypeOf<[LLVM_AnyFloat, AnyInteger]>;
-def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw", [
+def LLVM_AtomicRMWOp : LLVM_MemAccessOpBase<"atomicrmw", [
TypesMatchWith<"result #0 and operand #1 have the same type",
- "val", "res", "$_self">]>, MemoryOpBase {
- let arguments = (ins AtomicBinOp:$bin_op,
- LLVM_PointerTo<LLVM_AtomicRMWType>:$ptr,
- LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering,
- OptionalAttr<StrAttr>:$syncscope,
- OptionalAttr<I64Attr>:$alignment,
- UnitAttr:$volatile_);
+ "val", "res", "$_self">]> {
+ dag args = (ins AtomicBinOp:$bin_op,
+ LLVM_PointerTo<LLVM_AtomicRMWType>:$ptr,
+ LLVM_AtomicRMWType:$val, AtomicOrdering:$ordering,
+ OptionalAttr<StrAttr>:$syncscope,
+ OptionalAttr<I64Attr>:$alignment,
+ UnitAttr:$volatile_);
+ // Append the aliasing related attributes define in LLVM_MemAccessOpBase.
+ let arguments = !con(args, aliasAttrs);
let results = (outs LLVM_AtomicRMWType:$res);
let assemblyFormat = [{
(`volatile` $volatile_^)? $bin_op $ptr `,` $val
$res = inst;
}] # setVolatileCode
# setSyncScopeCode
- # setAlignmentCode;
+ # setAlignmentCode
+ # setAccessGroupsMetadataCode
+ # setAliasAnalysisMetadataCode;
string mlirBuilder = [{
auto *atomicInst = cast<llvm::AtomicRMWInst>(inst);
unsigned alignment = atomicInst->getAlign().value();
convertAtomicOrderingFromLLVM(atomicInst->getOrdering()),
getLLVMSyncScope(atomicInst), alignment, atomicInst->isVolatile());
}];
- list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1];
+ list<int> llvmArgIndices = [-1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1];
let builders = [
OpBuilder<(ins "LLVM::AtomicBinOp":$binOp, "Value":$ptr, "Value":$val,
"LLVM::AtomicOrdering":$ordering,
def LLVM_AtomicCmpXchgType : AnyTypeOf<[AnyInteger, LLVM_AnyPointer]>;
-def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg", [
+def LLVM_AtomicCmpXchgOp : LLVM_MemAccessOpBase<"cmpxchg", [
TypesMatchWith<"operand #1 and operand #2 have the same type",
"val", "cmp", "$_self">,
TypesMatchWith<"result #0 has an LLVM struct type consisting of "
"the type of operand #2 and a bool", "val", "res",
- "getValAndBoolStructType($_self)">]>, MemoryOpBase {
- let arguments = (ins LLVM_PointerTo<LLVM_AtomicCmpXchgType>:$ptr,
- LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val,
- AtomicOrdering:$success_ordering,
- AtomicOrdering:$failure_ordering,
- OptionalAttr<StrAttr>:$syncscope,
- OptionalAttr<I64Attr>:$alignment,
- UnitAttr:$weak,
- UnitAttr:$volatile_);
+ "getValAndBoolStructType($_self)">]> {
+ dag args = (ins LLVM_PointerTo<LLVM_AtomicCmpXchgType>:$ptr,
+ LLVM_AtomicCmpXchgType:$cmp, LLVM_AtomicCmpXchgType:$val,
+ AtomicOrdering:$success_ordering,
+ AtomicOrdering:$failure_ordering,
+ OptionalAttr<StrAttr>:$syncscope,
+ OptionalAttr<I64Attr>:$alignment,
+ UnitAttr:$weak,
+ UnitAttr:$volatile_);
+ // Append the aliasing related attributes define in LLVM_MemAccessOpBase.
+ let arguments = !con(args, aliasAttrs);
let results = (outs LLVM_AnyStruct:$res);
let assemblyFormat = [{
(`weak` $weak^)? (`volatile` $volatile_^)? $ptr `,` $cmp `,` $val
inst->setWeak($weak);
}] # setVolatileCode
# setSyncScopeCode
- # setAlignmentCode;
+ # setAlignmentCode
+ # setAccessGroupsMetadataCode
+ # setAliasAnalysisMetadataCode;
string mlirBuilder = [{
auto *cmpXchgInst = cast<llvm::AtomicCmpXchgInst>(inst);
unsigned alignment = cmpXchgInst->getAlign().value();
let hasVerifier = 1;
}
-def LLVM_FenceOp : LLVM_Op<"fence">, MemoryOpBase {
+def LLVM_FenceOp : LLVM_Op<"fence">, LLVM_MemOpPatterns {
let arguments = (ins AtomicOrdering:$ordering,
OptionalAttr<StrAttr>:$syncscope);
let assemblyFormat = "(`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict";
#ifndef MLIR_TARGET_LLVMIR_MODULETRANSLATION_H
#define MLIR_TARGET_LLVMIR_MODULETRANSLATION_H
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/SymbolTable.h"
#include "mlir/IR/Value.h"
// Sets LLVM metadata for memory operations that have alias scope information.
void setAliasScopeMetadata(Operation *op, llvm::Instruction *inst);
- /// Sets LLVM TBAA metadata for memory operations that have
- /// TBAA attributes.
- void setTBAAMetadata(Operation *op, llvm::Instruction *inst);
+ /// Sets LLVM TBAA metadata for memory operations that have TBAA attributes.
+ void setTBAAMetadata(AliasAnalysisOpInterface op, llvm::Instruction *inst);
/// Sets LLVM loop metadata for branch operations that have a loop annotation
/// attribute.
IR/FunctionCallUtils.cpp
IR/LLVMAttrs.cpp
IR/LLVMDialect.cpp
+ IR/LLVMInterfaces.cpp
IR/LLVMTypes.cpp
IR/LLVMTypeSyntax.cpp
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "TypeDetail.h"
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
static constexpr const char kElemTypeAttrName[] = "elem_type";
-#include "mlir/Dialect/LLVMIR/LLVMInterfaces.cpp.inc"
-
static auto processFMFAttr(ArrayRef<NamedAttribute> attrs) {
SmallVector<NamedAttribute, 8> filteredAttrs(
llvm::make_filter_range(attrs, [&](NamedAttribute attr) {
// LoadOp
//===----------------------------------------------------------------------===//
-/// Verifies the given array attribute contains symbol references and checks the
-/// referenced symbol types using the provided verification function.
-LogicalResult verifyMemOpSymbolRefs(
- Operation *op, StringRef name, ArrayAttr symbolRefs,
- llvm::function_ref<LogicalResult(Operation *, SymbolRefAttr)>
- verifySymbolType) {
- assert(symbolRefs && "expected a non-null attribute");
-
- // Verify that the attribute is a symbol ref array attribute,
- // because this constraint is not verified for all attribute
- // names processed here (e.g. 'tbaa'). This verification
- // is redundant in some cases.
- if (!llvm::all_of(symbolRefs, [](Attribute attr) {
- return attr && attr.isa<SymbolRefAttr>();
- }))
- return op->emitOpError("attribute '")
- << name
- << "' failed to satisfy constraint: symbol ref array attribute";
-
- for (SymbolRefAttr symbolRef : symbolRefs.getAsRange<SymbolRefAttr>()) {
- StringAttr metadataName = symbolRef.getRootReference();
- StringAttr symbolName = symbolRef.getLeafReference();
- // We want @metadata::@symbol, not just @symbol
- if (metadataName == symbolName) {
- return op->emitOpError() << "expected '" << symbolRef
- << "' to specify a fully qualified reference";
- }
- auto metadataOp = SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>(
- op->getParentOp(), metadataName);
- if (!metadataOp)
- return op->emitOpError()
- << "expected '" << symbolRef << "' to reference a metadata op";
- Operation *symbolOp =
- SymbolTable::lookupNearestSymbolFrom(metadataOp, symbolName);
- if (!symbolOp)
- return op->emitOpError()
- << "expected '" << symbolRef << "' to be a valid reference";
- if (failed(verifySymbolType(symbolOp, symbolRef))) {
- return failure();
- }
- }
-
- return success();
-}
-
-/// Verifies the given array attribute contains symbol references that point to
-/// metadata operations of the given type.
-template <typename OpTy>
-static LogicalResult
-verifyMemOpSymbolRefsPointTo(Operation *op, StringRef name,
- std::optional<ArrayAttr> symbolRefs) {
- if (!symbolRefs)
- return success();
-
- auto verifySymbolType = [op](Operation *symbolOp,
- SymbolRefAttr symbolRef) -> LogicalResult {
- if (!isa<OpTy>(symbolOp)) {
- return op->emitOpError()
- << "expected '" << symbolRef << "' to resolve to a "
- << OpTy::getOperationName();
- }
- return success();
- };
- return verifyMemOpSymbolRefs(op, name, *symbolRefs, verifySymbolType);
-}
-
-/// Verifies the types of the metadata operations referenced by aliasing and
-/// access group metadata.
-template <typename OpTy>
-LogicalResult verifyMemOpMetadata(OpTy memOp) {
- if (failed(verifyMemOpSymbolRefsPointTo<LLVM::AccessGroupMetadataOp>(
- memOp, memOp.getAccessGroupsAttrName(), memOp.getAccessGroups())))
- return failure();
-
- if (failed(verifyMemOpSymbolRefsPointTo<LLVM::AliasScopeMetadataOp>(
- memOp, memOp.getAliasScopesAttrName(), memOp.getAliasScopes())))
- return failure();
-
- if (failed(verifyMemOpSymbolRefsPointTo<LLVM::AliasScopeMetadataOp>(
- memOp, memOp.getNoaliasScopesAttrName(), memOp.getNoaliasScopes())))
- return failure();
-
- if (failed(verifyMemOpSymbolRefsPointTo<LLVM::TBAATagOp>(
- memOp, memOp.getTbaaAttrName(), memOp.getTbaa())))
- return failure();
-
- return success();
-}
-
/// Returns true if the given type is supported by atomic operations. All
/// integer and float types with limited bit width are supported. Additionally,
/// depending on the operation pointers may be supported as well.
LogicalResult LoadOp::verify() {
Type valueType = getResult().getType();
- if (failed(verifyAtomicMemOp(
- *this, valueType,
- {AtomicOrdering::release, AtomicOrdering::acq_rel})))
- return failure();
-
- return verifyMemOpMetadata(*this);
+ return verifyAtomicMemOp(*this, valueType,
+ {AtomicOrdering::release, AtomicOrdering::acq_rel});
}
void LoadOp::build(OpBuilder &builder, OperationState &state, Value addr,
bool isNonTemporal, AtomicOrdering ordering,
StringRef syncscope) {
build(builder, state, type, addr,
- /*access_groups=*/nullptr,
- /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
- /*tbaa=*/nullptr,
alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
isNonTemporal, ordering,
- syncscope.empty() ? nullptr : builder.getStringAttr(syncscope));
+ syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
+ /*access_groups=*/nullptr,
+ /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr,
+ /*tbaa=*/nullptr);
}
// Extract the pointee type from the LLVM pointer type wrapped in MLIR. Return
LogicalResult StoreOp::verify() {
Type valueType = getValue().getType();
- if (failed(verifyAtomicMemOp(
- *this, valueType,
- {AtomicOrdering::acquire, AtomicOrdering::acq_rel})))
- return failure();
-
- return verifyMemOpMetadata(*this);
+ return verifyAtomicMemOp(*this, valueType,
+ {AtomicOrdering::acquire, AtomicOrdering::acq_rel});
}
void StoreOp::build(OpBuilder &builder, OperationState &state, Value value,
Value addr, unsigned alignment, bool isVolatile,
bool isNonTemporal, AtomicOrdering ordering,
StringRef syncscope) {
- build(builder, state, value, addr, /*access_groups=*/nullptr,
- /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr,
+ build(builder, state, value, addr,
alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
isNonTemporal, ordering,
- syncscope.empty() ? nullptr : builder.getStringAttr(syncscope));
+ syncscope.empty() ? nullptr : builder.getStringAttr(syncscope),
+ /*access_groups=*/nullptr,
+ /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}
/// Parses the StoreOp type either using the typed or opaque pointer format.
unsigned alignment, bool isVolatile) {
build(builder, state, val.getType(), binOp, ptr, val, ordering,
!syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
- alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile);
+ alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isVolatile,
+ /*access_groups=*/nullptr,
+ /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}
LogicalResult AtomicRMWOp::verify() {
successOrdering, failureOrdering,
!syncscope.empty() ? builder.getStringAttr(syncscope) : nullptr,
alignment ? builder.getI64IntegerAttr(alignment) : nullptr, isWeak,
- isVolatile);
+ isVolatile, /*access_groups=*/nullptr,
+ /*alias_scopes=*/nullptr, /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}
LogicalResult AtomicCmpXchgOp::verify() {
bool isLegalToInline(Operation *op, Region *, bool, IRMapping &) const final {
if (isPure(op))
return true;
- return llvm::TypeSwitch<Operation *, bool>(op)
- .Case<LLVM::LoadOp, LLVM::StoreOp>([&](auto memOp) {
- // Some attributes on load and store operations require handling
- // during inlining. Since this is not yet implemented, refuse to
- // inline memory operations that have any of these attributes.
- if (memOp.getAccessGroups())
- return false;
- if (memOp.getAliasScopes())
- return false;
- if (memOp.getNoaliasScopes())
- return false;
- return true;
- })
- .Case<LLVM::CallOp, LLVM::AllocaOp, LLVM::LifetimeStartOp,
- LLVM::LifetimeEndOp>([](auto) { return true; })
- .Default([](auto) { return false; });
+ // Some attributes on memory operations require handling during
+ // inlining. Since this is not yet implemented, refuse to inline memory
+ // operations that have any of these attributes.
+ if (auto iface = dyn_cast<AliasAnalysisOpInterface>(op))
+ if (iface.getAliasScopesOrNull() || iface.getNoAliasScopesOrNull())
+ return false;
+ if (auto iface = dyn_cast<AccessGroupOpInterface>(op))
+ if (iface.getAccessGroupsOrNull())
+ return false;
+ return isa<LLVM::CallOp, LLVM::AllocaOp, LLVM::LifetimeStartOp,
+ LLVM::LifetimeEndOp, LLVM::LoadOp, LLVM::StoreOp>(op);
}
/// Handle the given inlined return by replacing it with a branch. This
--- /dev/null
+//===- LLVMInterfaces.cpp - LLVM Interfaces ---------------------*- C++ -*-===//
+//
+// 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 op interfaces for the LLVM dialect in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+
+using namespace mlir;
+using namespace mlir::LLVM;
+
+/// Verifies the given array attribute contains symbol references and checks the
+/// referenced symbol types using the provided verification function.
+static LogicalResult
+verifySymbolRefs(Operation *op, StringRef name, ArrayAttr symbolRefs,
+ llvm::function_ref<LogicalResult(Operation *, SymbolRefAttr)>
+ verifySymbolType) {
+ assert(symbolRefs && "expected a non-null attribute");
+
+ // Verify that the attribute is a symbol ref array attribute,
+ // because this constraint is not verified for all attribute
+ // names processed here (e.g. 'tbaa'). This verification
+ // is redundant in some cases.
+ if (!llvm::all_of(symbolRefs, [](Attribute attr) {
+ return attr && attr.isa<SymbolRefAttr>();
+ }))
+ return op->emitOpError() << name
+ << " attribute failed to satisfy constraint: "
+ "symbol ref array attribute";
+
+ for (SymbolRefAttr symbolRef : symbolRefs.getAsRange<SymbolRefAttr>()) {
+ StringAttr metadataName = symbolRef.getRootReference();
+ StringAttr symbolName = symbolRef.getLeafReference();
+ // We want @metadata::@symbol, not just @symbol
+ if (metadataName == symbolName) {
+ return op->emitOpError() << "expected '" << symbolRef
+ << "' to specify a fully qualified reference";
+ }
+ auto metadataOp = SymbolTable::lookupNearestSymbolFrom<LLVM::MetadataOp>(
+ op->getParentOp(), metadataName);
+ if (!metadataOp)
+ return op->emitOpError()
+ << "expected '" << symbolRef << "' to reference a metadata op";
+ Operation *symbolOp =
+ SymbolTable::lookupNearestSymbolFrom(metadataOp, symbolName);
+ if (!symbolOp)
+ return op->emitOpError()
+ << "expected '" << symbolRef << "' to be a valid reference";
+ if (failed(verifySymbolType(symbolOp, symbolRef))) {
+ return failure();
+ }
+ }
+
+ return success();
+}
+
+/// Verifies the given array attribute contains symbol references that point to
+/// metadata operations of the given type.
+template <typename OpTy>
+LogicalResult verifySymbolRefsPointTo(Operation *op, StringRef name,
+ ArrayAttr symbolRefs) {
+ if (!symbolRefs)
+ return success();
+
+ auto verifySymbolType = [op](Operation *symbolOp,
+ SymbolRefAttr symbolRef) -> LogicalResult {
+ if (!isa<OpTy>(symbolOp)) {
+ return op->emitOpError()
+ << "expected '" << symbolRef << "' to resolve to a "
+ << OpTy::getOperationName();
+ }
+ return success();
+ };
+ return verifySymbolRefs(op, name, symbolRefs, verifySymbolType);
+}
+
+//===----------------------------------------------------------------------===//
+// AccessGroupOpInterface
+//===----------------------------------------------------------------------===//
+
+LogicalResult mlir::LLVM::detail::verifyAccessGroupOpInterface(Operation *op) {
+ auto iface = cast<AccessGroupOpInterface>(op);
+ if (failed(verifySymbolRefsPointTo<LLVM::AccessGroupMetadataOp>(
+ iface, "access groups", iface.getAccessGroupsOrNull())))
+ return failure();
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// AliasAnalysisOpInterface
+//===----------------------------------------------------------------------===//
+
+LogicalResult
+mlir::LLVM::detail::verifyAliasAnalysisOpInterface(Operation *op) {
+ auto iface = cast<AliasAnalysisOpInterface>(op);
+ if (failed(verifySymbolRefsPointTo<LLVM::AliasScopeMetadataOp>(
+ iface, "alias scopes", iface.getAliasScopesOrNull())))
+ return failure();
+ if (failed(verifySymbolRefsPointTo<LLVM::AliasScopeMetadataOp>(
+ iface, "noalias scopes", iface.getNoAliasScopesOrNull())))
+ return failure();
+ if (failed(verifySymbolRefsPointTo<LLVM::TBAATagOp>(
+ iface, "tbaa tags", iface.getTBAATagsOrNull())))
+ return failure();
+ return success();
+}
+
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.cpp.inc"
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Target/LLVMIR/ModuleImport.h"
return convertibleMetadata;
}
-namespace {
-/// Helper class to attach metadata attributes to specific operation types. It
-/// specializes TypeSwitch to take an Operation and return a LogicalResult.
-template <typename... OpTys>
-struct AttributeSetter {
- AttributeSetter(Operation *op) : op(op) {}
-
- /// Calls `attachFn` on the provided Operation if it has one of
- /// the given operation types. Returns failure otherwise.
- template <typename CallableT>
- LogicalResult apply(CallableT &&attachFn) {
- return llvm::TypeSwitch<Operation *, LogicalResult>(op)
- .Case<OpTys...>([&attachFn](auto concreteOp) {
- attachFn(concreteOp);
- return success();
- })
- .Default([&](auto) { return failure(); });
- }
-
-private:
- Operation *op;
-};
-} // namespace
-
/// Converts the given profiling metadata `node` to an MLIR profiling attribute
/// and attaches it to the imported operation if the translation succeeds.
/// Returns failure otherwise.
branchWeights.push_back(branchWeight->getZExtValue());
}
- return AttributeSetter<CondBrOp, SwitchOp, CallOp, InvokeOp>(op).apply(
- [&](auto branchWeightOp) {
+ return TypeSwitch<Operation *, LogicalResult>(op)
+ .Case<CondBrOp, SwitchOp, CallOp, InvokeOp>([&](auto branchWeightOp) {
branchWeightOp.setBranchWeightsAttr(
builder.getI32VectorAttr(branchWeights));
- });
+ return success();
+ })
+ .Default([](auto) { return failure(); });
}
/// Searches the symbol reference pointing to the metadata operation that
if (!tbaaTagSym)
return failure();
- return AttributeSetter<LoadOp, StoreOp>(op).apply([&](auto memOp) {
- memOp.setTbaaAttr(ArrayAttr::get(memOp.getContext(), tbaaTagSym));
- });
+ auto iface = dyn_cast<AliasAnalysisOpInterface>(op);
+ if (!iface)
+ return failure();
+
+ iface.setTBAATags(ArrayAttr::get(iface.getContext(), tbaaTagSym));
+ return success();
}
/// Looks up all the symbol references pointing to the access group operations
if (failed(accessGroups))
return failure();
- SmallVector<Attribute> accessGroupAttrs(accessGroups->begin(),
- accessGroups->end());
- return AttributeSetter<LoadOp, StoreOp>(op).apply([&](auto memOp) {
- memOp.setAccessGroupsAttr(
- ArrayAttr::get(memOp.getContext(), accessGroupAttrs));
- });
+ auto iface = dyn_cast<AccessGroupOpInterface>(op);
+ if (!iface)
+ return failure();
+
+ iface.setAccessGroups(ArrayAttr::get(
+ iface.getContext(),
+ SmallVector<Attribute>{accessGroups->begin(), accessGroups->end()}));
+ return success();
}
/// Converts the given loop metadata node to an MLIR loop annotation attribute
if (failed(aliasScopes))
return failure();
- SmallVector<Attribute> aliasScopeAttrs(aliasScopes->begin(),
- aliasScopes->end());
- return AttributeSetter<LoadOp, StoreOp>(op).apply([&](auto memOp) {
- memOp.setAliasScopesAttr(
- ArrayAttr::get(memOp.getContext(), aliasScopeAttrs));
- });
+ auto iface = dyn_cast<AliasAnalysisOpInterface>(op);
+ if (!iface)
+ return failure();
+
+ iface.setAliasScopes(ArrayAttr::get(
+ iface.getContext(),
+ SmallVector<Attribute>{aliasScopes->begin(), aliasScopes->end()}));
+ return success();
}
/// Looks up all the symbol references pointing to the alias scope operations
static LogicalResult setNoaliasScopesAttr(const llvm::MDNode *node,
Operation *op,
LLVM::ModuleImport &moduleImport) {
- FailureOr<SmallVector<SymbolRefAttr>> noaliasScopes =
+ FailureOr<SmallVector<SymbolRefAttr>> noAliasScopes =
moduleImport.lookupAliasScopeAttrs(node);
- if (failed(noaliasScopes))
+ if (failed(noAliasScopes))
return failure();
- SmallVector<Attribute> noaliasScopeAttrs(noaliasScopes->begin(),
- noaliasScopes->end());
- return AttributeSetter<LoadOp, StoreOp>(op).apply([&](auto memOp) {
- memOp.setNoaliasScopesAttr(
- ArrayAttr::get(memOp.getContext(), noaliasScopeAttrs));
- });
+ auto iface = dyn_cast<AliasAnalysisOpInterface>(op);
+ if (!iface)
+ return failure();
+
+ iface.setNoAliasScopes(ArrayAttr::get(
+ iface.getContext(),
+ SmallVector<Attribute>{noAliasScopes->begin(), noAliasScopes->end()}));
+ return success();
}
namespace {
#include "LoopAnnotationTranslation.h"
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMInterfaces.h"
#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/IR/Attributes.h"
return tbaaMetadataMapping.lookup(tagOp);
}
-void ModuleTranslation::setTBAAMetadata(Operation *op,
+void ModuleTranslation::setTBAAMetadata(AliasAnalysisOpInterface op,
llvm::Instruction *inst) {
- auto populateTBAAMetadata = [&](std::optional<ArrayAttr> tagRefs) {
- if (!tagRefs || tagRefs->empty())
- return;
-
- // LLVM IR currently does not support attaching more than one
- // TBAA access tag to a memory accessing instruction.
- // It may be useful to support this in future, but for the time being
- // just ignore the metadata if MLIR operation has multiple access tags.
- if (tagRefs->size() > 1) {
- op->emitWarning() << "TBAA access tags were not translated, because LLVM "
- "IR only supports a single tag per instruction";
- return;
- }
+ ArrayAttr tagRefs = op.getTBAATagsOrNull();
+ if (!tagRefs || tagRefs.empty())
+ return;
- SymbolRefAttr tagRef = (*tagRefs)[0].cast<SymbolRefAttr>();
- llvm::MDNode *node = getTBAANode(op, tagRef);
- inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
- };
+ // LLVM IR currently does not support attaching more than one TBAA access tag
+ // to a memory accessing instruction. It may be useful to support this in
+ // future, but for the time being just ignore the metadata if MLIR operation
+ // has multiple access tags.
+ if (tagRefs.size() > 1) {
+ op.emitWarning() << "TBAA access tags were not translated, because LLVM "
+ "IR only supports a single tag per instruction";
+ return;
+ }
- llvm::TypeSwitch<Operation *>(op)
- .Case<LoadOp, StoreOp>(
- [&](auto memOp) { populateTBAAMetadata(memOp.getTbaa()); })
- .Default([](auto) { llvm_unreachable("expected LoadOp or StoreOp"); });
+ SymbolRefAttr tagRef = tagRefs[0].cast<SymbolRefAttr>();
+ llvm::MDNode *node = getTBAANode(op, tagRef);
+ inst->setMetadata(llvm::LLVMContext::MD_tbaa, node);
}
LogicalResult ModuleTranslation::createTBAAMetadata() {
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @accessGroups(%arg0 : !llvm.ptr) {
// expected-error@below {{expected '@func1' to specify a fully qualified reference}}
- %0 = llvm.load %arg0 { "access_groups" = [@func1] } : !llvm.ptr<i32>
+ %0 = llvm.load %arg0 { "access_groups" = [@func1] } : !llvm.ptr -> i32
llvm.return
}
llvm.func @func1() {
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @accessGroups(%arg0 : i32, %arg1 : !llvm.ptr) {
// expected-error@below {{expected '@accessGroups::@group1' to reference a metadata op}}
- %0 = llvm.load %arg0 { "access_groups" = [@accessGroups::@group1] } : !llvm.ptr<i32>
+ llvm.store %arg0, %arg1 { "access_groups" = [@accessGroups::@group1] } : i32, !llvm.ptr
llvm.return
}
llvm.metadata @metadata {
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @accessGroups(%arg0 : !llvm.ptr, %arg1 : f32) {
// expected-error@below {{expected '@metadata::@group1' to be a valid reference}}
- %0 = llvm.load %arg0 { "access_groups" = [@metadata::@group1] } : !llvm.ptr<i32>
+ %0 = llvm.atomicrmw fadd %arg0, %arg1 monotonic { "access_groups" = [@metadata::@group1] } : !llvm.ptr, f32
llvm.return
}
llvm.metadata @metadata {
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @accessGroups(%arg0 : !llvm.ptr, %arg1 : i32, %arg2 : i32) {
// expected-error@below {{expected '@metadata::@scope' to resolve to a llvm.access_group}}
- %0 = llvm.load %arg0 { "access_groups" = [@metadata::@scope] } : !llvm.ptr<i32>
+ %0 = llvm.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "access_groups" = [@metadata::@scope] } : !llvm.ptr, i32
llvm.return
}
llvm.metadata @metadata {
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @aliasScope(%arg0 : !llvm.ptr, %arg1 : i32, %arg2 : i32) {
// expected-error@below {{attribute 'alias_scopes' failed to satisfy constraint: symbol ref array attribute}}
- %0 = llvm.load %arg0 { "alias_scopes" = "test" } : !llvm.ptr<i32>
+ %0 = llvm.cmpxchg %arg0, %arg1, %arg2 acq_rel monotonic { "alias_scopes" = "test" } : !llvm.ptr, i32
llvm.return
}
}
// -----
module {
- llvm.func @accessGroups(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @noAliasScopes(%arg0 : !llvm.ptr) {
// expected-error@below {{attribute 'noalias_scopes' failed to satisfy constraint: symbol ref array attribute}}
- %0 = llvm.load %arg0 { "noalias_scopes" = "test" } : !llvm.ptr<i32>
+ %0 = llvm.load %arg0 { "noalias_scopes" = "test" } : !llvm.ptr -> i32
llvm.return
}
}
// -----
module {
- llvm.func @aliasScope(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @aliasScope(%arg0 : i32, %arg1 : !llvm.ptr) {
// expected-error@below {{expected '@metadata::@group' to resolve to a llvm.alias_scope}}
- %0 = llvm.load %arg0 { "alias_scopes" = [@metadata::@group] } : !llvm.ptr<i32>
+ llvm.store %arg0, %arg1 { "alias_scopes" = [@metadata::@group] } : i32, !llvm.ptr
llvm.return
}
llvm.metadata @metadata {
// -----
module {
- llvm.func @aliasScope(%arg0 : !llvm.ptr<i32>) {
+ llvm.func @aliasScope(%arg0 : !llvm.ptr, %arg1 : f32) {
// expected-error@below {{expected '@metadata::@group' to resolve to a llvm.alias_scope}}
- %0 = llvm.load %arg0 { "noalias_scopes" = [@metadata::@group] } : !llvm.ptr<i32>
+ %0 = llvm.atomicrmw fadd %arg0, %arg1 monotonic { "noalias_scopes" = [@metadata::@group] } : !llvm.ptr, f32
llvm.return
}
llvm.metadata @metadata {
!3 = !{!3, !1}
!4 = !{!2}
!5 = !{!3}
+
+; // -----
+
+; CHECK-LABEL: llvm.func @supported_ops
+define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
+ ; CHECK: llvm.load {{.*}}alias_scopes =
+ %1 = load i32, ptr %arg1, !alias.scope !3
+ ; CHECK: llvm.store {{.*}}alias_scopes =
+ store i32 %1, ptr %arg1, !alias.scope !3
+ ; CHECK: llvm.atomicrmw {{.*}}alias_scopes =
+ %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !alias.scope !3
+ ; CHECK: llvm.cmpxchg {{.*}}alias_scopes =
+ %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !alias.scope !3
+ ret void
+}
+
+!0 = distinct !{!0, !"The domain"}
+!1 = distinct !{!1}
+!2 = !{!2, !0}
+!3 = !{!2}
; // -----
+; CHECK-LABEL: llvm.func @supported_ops
+define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
+ ; CHECK: llvm.load {{.*}}access_groups =
+ %1 = load i32, ptr %arg1, !llvm.access.group !0
+ ; CHECK: llvm.store {{.*}}access_groups =
+ store i32 %1, ptr %arg1, !llvm.access.group !0
+ ; CHECK: llvm.atomicrmw {{.*}}access_groups =
+ %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !llvm.access.group !0
+ ; CHECK: llvm.cmpxchg {{.*}}access_groups =
+ %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !llvm.access.group !0
+ ret void
+}
+
+!0 = !{!1, !2}
+!1 = distinct !{}
+!2 = distinct !{}
+
+; // -----
+
; CHECK: #[[$ANNOT_ATTR:.*]] = #llvm.loop_annotation<disableNonforced = true, mustProgress = true, isVectorized = true>
; CHECK-LABEL: @simple
!4 = !{!"other scalar type", !5, i64 0}
!5 = !{!"Other language TBAA"}
-// -----
+; // -----
; CHECK-LABEL: llvm.metadata @__llvm_global_metadata {
; CHECK-NEXT: llvm.tbaa_root @[[R0:tbaa_root_[0-9]+]] {id = "Simple C/C++ TBAA"}
!11 = !{!12, !13, i64 0}
!12 = !{!"agg1_t", !13, i64 0, !13, i64 4}
!13 = !{!"int", !9, i64 0}
+
+; // -----
+
+; CHECK-LABEL: llvm.func @supported_ops
+define void @supported_ops(ptr %arg1, float %arg2, i32 %arg3, i32 %arg4) {
+ ; CHECK: llvm.load {{.*}}tbaa =
+ %1 = load i32, ptr %arg1, !tbaa !0
+ ; CHECK: llvm.store {{.*}}tbaa =
+ store i32 %1, ptr %arg1, !tbaa !0
+ ; CHECK: llvm.atomicrmw {{.*}}tbaa =
+ %2 = atomicrmw fmax ptr %arg1, float %arg2 acquire, !tbaa !0
+ ; CHECK: llvm.cmpxchg {{.*}}tbaa =
+ %3 = cmpxchg ptr %arg1, i32 %arg3, i32 %arg4 monotonic seq_cst, !tbaa !0
+ ret void
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"scalar type", !2, i64 0}
+!2 = !{!"Simple C/C++ TBAA"}
// -----
module {
- llvm.func @aliasScope(%arg1 : !llvm.ptr<i32>, %arg2 : !llvm.ptr<i32>, %arg3 : !llvm.ptr<i32>) {
+ llvm.func @aliasScope(%arg1 : !llvm.ptr) {
%0 = llvm.mlir.constant(0 : i32) : i32
- llvm.store %0, %arg1 { alias_scopes = [@metadata::@scope1], noalias_scopes = [@metadata::@scope2, @metadata::@scope3] } : !llvm.ptr<i32>
- llvm.store %0, %arg2 { alias_scopes = [@metadata::@scope2], noalias_scopes = [@metadata::@scope1, @metadata::@scope3] } : !llvm.ptr<i32>
- %1 = llvm.load %arg3 { alias_scopes = [@metadata::@scope3], noalias_scopes = [@metadata::@scope1, @metadata::@scope2] } : !llvm.ptr<i32>
+ llvm.store %0, %arg1 {alias_scopes = [@metadata::@scope1], noalias_scopes = [@metadata::@scope2, @metadata::@scope3]} : i32, !llvm.ptr
+ %1 = llvm.load %arg1 {alias_scopes = [@metadata::@scope2], noalias_scopes = [@metadata::@scope1, @metadata::@scope3]} : !llvm.ptr -> i32
+ %2 = llvm.atomicrmw add %arg1, %0 monotonic {alias_scopes = [@metadata::@scope3], noalias_scopes = [@metadata::@scope1, @metadata::@scope2]} : !llvm.ptr, i32
+ %3 = llvm.cmpxchg %arg1, %1, %2 acq_rel monotonic {alias_scopes = [@metadata::@scope3]} : !llvm.ptr, i32
llvm.return
}
llvm.metadata @metadata {
- llvm.alias_scope_domain @domain { description = "The domain"}
- llvm.alias_scope @scope1 { domain = @domain, description = "The first scope" }
- llvm.alias_scope @scope2 { domain = @domain }
- llvm.alias_scope @scope3 { domain = @domain }
+ llvm.alias_scope_domain @domain {description = "The domain"}
+ llvm.alias_scope @scope1 {domain = @domain, description = "The first scope"}
+ llvm.alias_scope @scope2 {domain = @domain}
+ llvm.alias_scope @scope3 {domain = @domain}
}
}
// Function
// CHECK-LABEL: aliasScope
// CHECK: store {{.*}}, !alias.scope ![[SCOPES1:[0-9]+]], !noalias ![[SCOPES23:[0-9]+]]
-// CHECK: store {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
-// CHECK: load {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
+// CHECK: load {{.*}}, !alias.scope ![[SCOPES2:[0-9]+]], !noalias ![[SCOPES13:[0-9]+]]
+// CHECK: atomicrmw {{.*}}, !alias.scope ![[SCOPES3:[0-9]+]], !noalias ![[SCOPES12:[0-9]+]]
+// CHECK: cmpxchg {{.*}}, !alias.scope ![[SCOPES3]]
// Metadata
// CHECK-DAG: ![[DOMAIN:[0-9]+]] = distinct !{![[DOMAIN]], !"The domain"}
llvm.func @vectorizeOptions() {
// CHECK: br {{.*}} !llvm.loop ![[LOOP_NODE:[0-9]+]]
llvm.br ^bb1 {loop_annotation = #llvm.loop_annotation<vectorize = <
- disable = false, predicateEnable = true, scalableEnable = false, width = 16 : i32,
+ disable = false, predicateEnable = true, scalableEnable = false, width = 16 : i32,
followupVectorized = #followup, followupEpilogue = #followup, followupAll = #followup>
>}
^bb1:
llvm.return
}
-// CHECK: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}}
// CHECK-DAG: ![[VEC_NODE0:[0-9]+]] = !{!"llvm.loop.unroll.enable"}
// CHECK-DAG: ![[VEC_NODE2:[0-9]+]] = !{!"llvm.loop.unroll.full"}
// CHECK-LABEL: @loopOptions
llvm.func @loopOptions(%arg1 : i32, %arg2 : i32) {
%0 = llvm.mlir.constant(0 : i32) : i32
- %4 = llvm.alloca %arg1 x i32 : (i32) -> (!llvm.ptr<i32>)
+ %4 = llvm.alloca %arg1 x i32 : (i32) -> (!llvm.ptr)
llvm.br ^bb3(%0 : i32)
^bb3(%1: i32):
%2 = llvm.icmp "slt" %1, %arg1 : i32
^bb4:
%3 = llvm.add %1, %arg2 : i32
// CHECK: = load i32, ptr %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE:[0-9]+]]
- %5 = llvm.load %4 { access_groups = [@metadata::@group1, @metadata::@group2] } : !llvm.ptr<i32>
+ %5 = llvm.load %4 {access_groups = [@metadata::@group1, @metadata::@group2]} : !llvm.ptr -> i32
+ // CHECK: store i32 %{{.*}}, ptr %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
+ llvm.store %5, %4 {access_groups = [@metadata::@group1, @metadata::@group2]} : i32, !llvm.ptr
+ // CHECK: = atomicrmw add ptr %{{.*}}, i32 %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
+ %6 = llvm.atomicrmw add %4, %5 monotonic {access_groups = [@metadata::@group1, @metadata::@group2]} : !llvm.ptr, i32
+ // CHECK: = cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} !llvm.access.group ![[ACCESS_GROUPS_NODE]]
+ %7 = llvm.cmpxchg %4, %5, %6 acq_rel monotonic {access_groups = [@metadata::@group1, @metadata::@group2]} : !llvm.ptr, i32
// CHECK: br label {{.*}} !llvm.loop ![[LOOP_NODE]]
llvm.br ^bb3(%3 : i32) {loop_annotation = #llvm.loop_annotation<
licm = <disable = true>,
llvm.access_group @group2
}
-// CHECK: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+// CHECK: ![[LOOP_NODE]] = distinct !{![[LOOP_NODE]], !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
// CHECK-DAG: ![[PA_NODE:[0-9]+]] = !{!"llvm.loop.parallel_accesses", ![[GROUP_NODE1:[0-9]+]], ![[GROUP_NODE2:[0-9]+]]}
// CHECK-DAG: ![[GROUP_NODE1:[0-9]+]] = distinct !{}
// CHECK-DAG: ![[GROUP_NODE2:[0-9]+]] = distinct !{}
%5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
// CHECK: store i32 %{{.*}}, ptr %{{.*}},{{.*}}!tbaa ![[STAG:[0-9]*]]
llvm.store %4, %5 {tbaa = [@__tbaa::@tbaa_tag_7]} : i32, !llvm.ptr
+ // CHECK: atomicrmw add ptr %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
+ %6 = llvm.atomicrmw add %5, %4 monotonic {tbaa = [@__tbaa::@tbaa_tag_7]} : !llvm.ptr, i32
+ // CHECK: cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
+ %7 = llvm.cmpxchg %5, %6, %4 acq_rel monotonic {tbaa = [@__tbaa::@tbaa_tag_7]} : !llvm.ptr, i32
llvm.return
}
}