blob: 54b2e9429bc3b19ce764d0cd1803af09bb8235bc [file] [log] [blame]
//===-- LLVMOps.td - LLVM IR dialect op definition file ----*- tablegen -*-===//
//
// 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 is the LLVM IR operation definition file.
//
//===----------------------------------------------------------------------===//
#ifndef LLVMIR_OPS
#define LLVMIR_OPS
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/SideEffects.td"
class LLVM_Builder<string builder> {
string llvmBuilder = builder;
}
def LLVM_OneResultOpBuilder : OpBuilder<
"Builder *, OperationState &result, Type resultType, "
"ValueRange operands, ArrayRef<NamedAttribute> attributes = {}",
[{
if (resultType) result.addTypes(resultType);
result.addOperands(operands);
for (auto namedAttr : attributes) {
result.addAttribute(namedAttr.first, namedAttr.second);
}
}]>;
def LLVM_ZeroResultOpBuilder : OpBuilder<
"Builder *, OperationState &result, ValueRange operands, "
"ArrayRef<NamedAttribute> attributes = {}",
[{
result.addOperands(operands);
for (auto namedAttr : attributes) {
result.addAttribute(namedAttr.first, namedAttr.second);
}
}]>;
class LLVM_TwoBuilders<OpBuilder b1, OpBuilder b2> {
list<OpBuilder> builders = [b1, b2];
}
// Base class for LLVM operations with one result.
class LLVM_OneResultOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, traits>, Results<(outs LLVM_Type:$res)> {
let builders = [LLVM_OneResultOpBuilder];
}
// Compatibility builder that takes an instance of wrapped llvm::VoidType
// to indicate no result.
def LLVM_VoidResultTypeOpBuilder : OpBuilder<
"Builder *builder, OperationState &result, Type resultType, "
"ValueRange operands, ArrayRef<NamedAttribute> attributes = {}",
[{
auto llvmType = resultType.dyn_cast<LLVM::LLVMType>(); (void)llvmType;
assert(llvmType && "result must be an LLVM type");
assert(llvmType.getUnderlyingType() &&
llvmType.getUnderlyingType()->isVoidTy() &&
"for zero-result operands, only 'void' is accepted as result type");
build(builder, result, operands, attributes);
}]>;
// Base class for LLVM operations with zero results.
class LLVM_ZeroResultOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, traits>, Results<(outs)>,
LLVM_TwoBuilders<LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder>;
// Opaque builder used for terminator operations that contain successors.
def LLVM_TerminatorPassthroughOpBuilder : OpBuilder<
"Builder *, OperationState &result, ValueRange operands, "
"SuccessorRange destinations, ArrayRef<NamedAttribute> attributes = {}",
[{
result.addOperands(operands);
result.addSuccessors(destinations);
result.addAttributes(attributes);
}]>;
// Base class for LLVM terminator operations. All terminator operations have
// zero results and an optional list of successors.
class LLVM_TerminatorOp<string mnemonic, list<OpTrait> traits = []> :
LLVM_Op<mnemonic, !listconcat(traits, [Terminator])>;
// Class for arithmetic binary operations.
class LLVM_ArithmeticOp<string mnemonic, string builderFunc,
list<OpTrait> traits = []> :
LLVM_OneResultOp<mnemonic,
!listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
Arguments<(ins LLVM_Type:$lhs, LLVM_Type:$rhs)>,
LLVM_Builder<"$res = builder." # builderFunc # "($lhs, $rhs);"> {
let parser = [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }];
let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }];
}
class LLVM_UnaryArithmeticOp<string mnemonic, string builderFunc,
list<OpTrait> traits = []> :
LLVM_OneResultOp<mnemonic,
!listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
Arguments<(ins LLVM_Type:$operand)>,
LLVM_Builder<"$res = builder." # builderFunc # "($operand);"> {
let parser = [{ return impl::parseOneResultSameOperandTypeOp(parser, result); }];
let printer = [{ mlir::impl::printOneResultOp(this->getOperation(), p); }];
}
// Integer binary operations.
def LLVM_AddOp : LLVM_ArithmeticOp<"add", "CreateAdd", [Commutative]>;
def LLVM_SubOp : LLVM_ArithmeticOp<"sub", "CreateSub">;
def LLVM_MulOp : LLVM_ArithmeticOp<"mul", "CreateMul", [Commutative]>;
def LLVM_UDivOp : LLVM_ArithmeticOp<"udiv", "CreateUDiv">;
def LLVM_SDivOp : LLVM_ArithmeticOp<"sdiv", "CreateSDiv">;
def LLVM_URemOp : LLVM_ArithmeticOp<"urem", "CreateURem">;
def LLVM_SRemOp : LLVM_ArithmeticOp<"srem", "CreateSRem">;
def LLVM_AndOp : LLVM_ArithmeticOp<"and", "CreateAnd">;
def LLVM_OrOp : LLVM_ArithmeticOp<"or", "CreateOr">;
def LLVM_XOrOp : LLVM_ArithmeticOp<"xor", "CreateXor">;
def LLVM_ShlOp : LLVM_ArithmeticOp<"shl", "CreateShl">;
def LLVM_LShrOp : LLVM_ArithmeticOp<"lshr", "CreateLShr">;
def LLVM_AShrOp : LLVM_ArithmeticOp<"ashr", "CreateAShr">;
// Predicate for integer comparisons.
def ICmpPredicateEQ : I64EnumAttrCase<"eq", 0>;
def ICmpPredicateNE : I64EnumAttrCase<"ne", 1>;
def ICmpPredicateSLT : I64EnumAttrCase<"slt", 2>;
def ICmpPredicateSLE : I64EnumAttrCase<"sle", 3>;
def ICmpPredicateSGT : I64EnumAttrCase<"sgt", 4>;
def ICmpPredicateSGE : I64EnumAttrCase<"sge", 5>;
def ICmpPredicateULT : I64EnumAttrCase<"ult", 6>;
def ICmpPredicateULE : I64EnumAttrCase<"ule", 7>;
def ICmpPredicateUGT : I64EnumAttrCase<"ugt", 8>;
def ICmpPredicateUGE : I64EnumAttrCase<"uge", 9>;
def ICmpPredicate : I64EnumAttr<
"ICmpPredicate",
"llvm.icmp comparison predicate",
[ICmpPredicateEQ, ICmpPredicateNE, ICmpPredicateSLT, ICmpPredicateSLE,
ICmpPredicateSGT, ICmpPredicateSGE, ICmpPredicateULT, ICmpPredicateULE,
ICmpPredicateUGT, ICmpPredicateUGE]> {
let cppNamespace = "::mlir::LLVM";
}
// Other integer operations.
def LLVM_ICmpOp : LLVM_OneResultOp<"icmp", [NoSideEffect]>,
Arguments<(ins ICmpPredicate:$predicate, LLVM_Type:$lhs,
LLVM_Type:$rhs)> {
let llvmBuilder = [{
$res = builder.CreateICmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
}];
let builders = [OpBuilder<
"Builder *b, OperationState &result, ICmpPredicate predicate, Value lhs, "
"Value rhs", [{
LLVMDialect *dialect = &lhs.getType().cast<LLVMType>().getDialect();
build(b, result, LLVMType::getInt1Ty(dialect),
b->getI64IntegerAttr(static_cast<int64_t>(predicate)), lhs, rhs);
}]>];
let parser = [{ return parseCmpOp<ICmpPredicate>(parser, result); }];
let printer = [{ printICmpOp(p, *this); }];
}
// Predicate for float comparisons
def FCmpPredicateFALSE : I64EnumAttrCase<"_false", 0>;
def FCmpPredicateOEQ : I64EnumAttrCase<"oeq", 1>;
def FCmpPredicateOGT : I64EnumAttrCase<"ogt", 2>;
def FCmpPredicateOGE : I64EnumAttrCase<"oge", 3>;
def FCmpPredicateOLT : I64EnumAttrCase<"olt", 4>;
def FCmpPredicateOLE : I64EnumAttrCase<"ole", 5>;
def FCmpPredicateONE : I64EnumAttrCase<"one", 6>;
def FCmpPredicateORD : I64EnumAttrCase<"ord", 7>;
def FCmpPredicateUEQ : I64EnumAttrCase<"ueq", 8>;
def FCmpPredicateUGT : I64EnumAttrCase<"ugt", 9>;
def FCmpPredicateUGE : I64EnumAttrCase<"uge", 10>;
def FCmpPredicateULT : I64EnumAttrCase<"ult", 11>;
def FCmpPredicateULE : I64EnumAttrCase<"ule", 12>;
def FCmpPredicateUNE : I64EnumAttrCase<"une", 13>;
def FCmpPredicateUNO : I64EnumAttrCase<"uno", 14>;
def FCmpPredicateTRUE : I64EnumAttrCase<"_true", 15>;
def FCmpPredicate : I64EnumAttr<
"FCmpPredicate",
"llvm.fcmp comparison predicate",
[FCmpPredicateFALSE, FCmpPredicateOEQ, FCmpPredicateOGT, FCmpPredicateOGE,
FCmpPredicateOLT, FCmpPredicateOLE, FCmpPredicateONE, FCmpPredicateORD,
FCmpPredicateUEQ, FCmpPredicateUGT, FCmpPredicateUGE, FCmpPredicateULT,
FCmpPredicateULE, FCmpPredicateUNE, FCmpPredicateUNO, FCmpPredicateTRUE
]> {
let cppNamespace = "::mlir::LLVM";
}
// Other integer operations.
def LLVM_FCmpOp : LLVM_OneResultOp<"fcmp", [NoSideEffect]>,
Arguments<(ins FCmpPredicate:$predicate, LLVM_Type:$lhs,
LLVM_Type:$rhs)> {
let llvmBuilder = [{
$res = builder.CreateFCmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
}];
let builders = [OpBuilder<
"Builder *b, OperationState &result, FCmpPredicate predicate, Value lhs, "
"Value rhs", [{
LLVMDialect *dialect = &lhs.getType().cast<LLVMType>().getDialect();
build(b, result, LLVMType::getInt1Ty(dialect),
b->getI64IntegerAttr(static_cast<int64_t>(predicate)), lhs, rhs);
}]>];
let parser = [{ return parseCmpOp<FCmpPredicate>(parser, result); }];
let printer = [{ printFCmpOp(p, *this); }];
}
// Floating point binary operations.
def LLVM_FAddOp : LLVM_ArithmeticOp<"fadd", "CreateFAdd">;
def LLVM_FSubOp : LLVM_ArithmeticOp<"fsub", "CreateFSub">;
def LLVM_FMulOp : LLVM_ArithmeticOp<"fmul", "CreateFMul">;
def LLVM_FDivOp : LLVM_ArithmeticOp<"fdiv", "CreateFDiv">;
def LLVM_FRemOp : LLVM_ArithmeticOp<"frem", "CreateFRem">;
def LLVM_FNegOp : LLVM_UnaryArithmeticOp<"fneg", "CreateFNeg">;
// Memory-related operations.
def LLVM_AllocaOp :
LLVM_OneResultOp<"alloca">,
Arguments<(ins LLVM_Type:$arraySize, OptionalAttr<I64Attr>:$alignment)> {
string llvmBuilder = [{
auto *alloca = builder.CreateAlloca(
$_resultType->getPointerElementType(), $arraySize);
if ($alignment.hasValue()) {
auto align = $alignment.getValue().getZExtValue();
if (align != 0)
alloca->setAlignment(llvm::MaybeAlign(align));
}
$res = alloca;
}];
let builders = [OpBuilder<
"Builder *b, OperationState &result, Type resultType, Value arraySize, "
"unsigned alignment",
[{
if (alignment == 0)
return build(b, result, resultType, arraySize, IntegerAttr());
build(b, result, resultType, arraySize, b->getI64IntegerAttr(alignment));
}]>];
let parser = [{ return parseAllocaOp(parser, result); }];
let printer = [{ printAllocaOp(p, *this); }];
let verifier = [{
if (alignment().hasValue()) {
auto align = alignment().getValue().getSExtValue();
if (align < 0)
return emitOpError("expected positive alignment");
}
return success();
}];
}
def LLVM_GEPOp : LLVM_OneResultOp<"getelementptr", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$base, Variadic<LLVM_Type>:$indices)>,
LLVM_Builder<"$res = builder.CreateGEP($base, $indices);"> {
let assemblyFormat = [{
$base `[` $indices `]` attr-dict `:` functional-type(operands, results)
}];
}
def LLVM_LoadOp : LLVM_OneResultOp<"load">, Arguments<(ins LLVM_Type:$addr)>,
LLVM_Builder<"$res = builder.CreateLoad($addr);"> {
let builders = [OpBuilder<
"Builder *b, OperationState &result, Value addr",
[{
auto type = addr.getType().cast<LLVM::LLVMType>().getPointerElementTy();
build(b, result, type, addr);
}]>];
let parser = [{ return parseLoadOp(parser, result); }];
let printer = [{ printLoadOp(p, *this); }];
}
def LLVM_StoreOp : LLVM_ZeroResultOp<"store">,
Arguments<(ins LLVM_Type:$value, LLVM_Type:$addr)>,
LLVM_Builder<"builder.CreateStore($value, $addr);"> {
let parser = [{ return parseStoreOp(parser, result); }];
let printer = [{ printStoreOp(p, *this); }];
}
// Casts.
class LLVM_CastOp<string mnemonic, string builderFunc,
list<OpTrait> traits = []> :
LLVM_OneResultOp<mnemonic,
!listconcat([NoSideEffect], traits)>,
Arguments<(ins LLVM_Type:$arg)>,
LLVM_Builder<"$res = builder." # builderFunc # "($arg, $_resultType);"> {
let parser = [{ return mlir::impl::parseCastOp(parser, result); }];
let printer = [{ mlir::impl::printCastOp(this->getOperation(), p); }];
}
def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "CreateBitCast">;
def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "CreateAddrSpaceCast">;
def LLVM_IntToPtrOp : LLVM_CastOp<"inttoptr", "CreateIntToPtr">;
def LLVM_PtrToIntOp : LLVM_CastOp<"ptrtoint", "CreatePtrToInt">;
def LLVM_SExtOp : LLVM_CastOp<"sext", "CreateSExt">;
def LLVM_ZExtOp : LLVM_CastOp<"zext", "CreateZExt">;
def LLVM_TruncOp : LLVM_CastOp<"trunc", "CreateTrunc">;
def LLVM_SIToFPOp : LLVM_CastOp<"sitofp", "CreateSIToFP">;
def LLVM_UIToFPOp : LLVM_CastOp<"uitofp", "CreateUIToFP">;
def LLVM_FPToSIOp : LLVM_CastOp<"fptosi", "CreateFPToSI">;
def LLVM_FPToUIOp : LLVM_CastOp<"fptoui", "CreateFPToUI">;
def LLVM_FPExtOp : LLVM_CastOp<"fpext", "CreateFPExt">;
def LLVM_FPTruncOp : LLVM_CastOp<"fptrunc", "CreateFPTrunc">;
// Call-related operations.
def LLVM_InvokeOp : LLVM_Op<"invoke", [
AttrSizedOperandSegments,
DeclareOpInterfaceMethods<BranchOpInterface>,
Terminator
]>,
Arguments<(ins OptionalAttr<FlatSymbolRefAttr>:$callee,
Variadic<LLVM_Type>:$operands,
Variadic<LLVM_Type>:$normalDestOperands,
Variadic<LLVM_Type>:$unwindDestOperands)>,
Results<(outs Variadic<LLVM_Type>)> {
let successors = (successor AnySuccessor:$normalDest,
AnySuccessor:$unwindDest);
let builders = [OpBuilder<
"Builder *b, OperationState &result, ArrayRef<Type> tys, "
"FlatSymbolRefAttr callee, ValueRange ops, Block* normal, "
"ValueRange normalOps, Block* unwind, ValueRange unwindOps",
[{
result.addAttribute("callee", callee);
build(b, result, tys, ops, normal, normalOps, unwind, unwindOps);
}]>,
OpBuilder<
"Builder *b, OperationState &result, ArrayRef<Type> tys, "
"ValueRange ops, Block* normal, "
"ValueRange normalOps, Block* unwind, ValueRange unwindOps",
[{
build(b, result, tys, /*callee=*/FlatSymbolRefAttr(), ops, normalOps,
unwindOps, normal, unwind);
}]>];
let verifier = [{ return ::verify(*this); }];
let parser = [{ return parseInvokeOp(parser, result); }];
let printer = [{ printInvokeOp(p, *this); }];
}
def LLVM_LandingpadOp : LLVM_OneResultOp<"landingpad">,
Arguments<(ins UnitAttr:$cleanup,
Variadic<LLVM_Type>)> {
let verifier = [{ return ::verify(*this); }];
let parser = [{ return parseLandingpadOp(parser, result); }];
let printer = [{ printLandingpadOp(p, *this); }];
}
def LLVM_CallOp : LLVM_Op<"call">,
Arguments<(ins OptionalAttr<FlatSymbolRefAttr>:$callee,
Variadic<LLVM_Type>)>,
Results<(outs Variadic<LLVM_Type>)> {
let builders = [OpBuilder<
"Builder *builder, OperationState &result, LLVMFuncOp func,"
"ValueRange operands, ArrayRef<NamedAttribute> attributes = {}",
[{
LLVMType resultType = func.getType().getFunctionResultType();
if (!resultType.isVoidTy())
result.addTypes(resultType);
result.addAttribute("callee", builder->getSymbolRefAttr(func));
result.addAttributes(attributes);
result.addOperands(operands);
}]>];
let verifier = [{
if (getNumResults() > 1)
return emitOpError("must have 0 or 1 result");
return success();
}];
let parser = [{ return parseCallOp(parser, result); }];
let printer = [{ printCallOp(p, *this); }];
}
def LLVM_ExtractElementOp : LLVM_OneResultOp<"extractelement", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$vector,
LLVM_Type:$position)> {
string llvmBuilder = [{
$res = builder.CreateExtractElement($vector, $position);
}];
let builders = [OpBuilder<
"Builder *b, OperationState &result, Value vector, Value position,"
"ArrayRef<NamedAttribute> attrs = {}">];
let parser = [{ return parseExtractElementOp(parser, result); }];
let printer = [{ printExtractElementOp(p, *this); }];
}
def LLVM_ExtractValueOp : LLVM_OneResultOp<"extractvalue", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$container,
ArrayAttr:$position)> {
string llvmBuilder = [{
$res = builder.CreateExtractValue($container, extractPosition($position));
}];
let parser = [{ return parseExtractValueOp(parser, result); }];
let printer = [{ printExtractValueOp(p, *this); }];
}
def LLVM_InsertElementOp : LLVM_OneResultOp<"insertelement", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$vector, LLVM_Type:$value,
LLVM_Type:$position)> {
string llvmBuilder = [{
$res = builder.CreateInsertElement($vector, $value, $position);
}];
let parser = [{ return parseInsertElementOp(parser, result); }];
let printer = [{ printInsertElementOp(p, *this); }];
}
def LLVM_InsertValueOp : LLVM_OneResultOp<"insertvalue", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$container, LLVM_Type:$value,
ArrayAttr:$position)> {
string llvmBuilder = [{
$res = builder.CreateInsertValue($container, $value,
extractPosition($position));
}];
let builders = [OpBuilder<
"Builder *b, OperationState &result, Value container, Value value, "
"ArrayAttr position",
[{
build(b, result, container.getType(), container, value, position);
}]>];
let parser = [{ return parseInsertValueOp(parser, result); }];
let printer = [{ printInsertValueOp(p, *this); }];
}
def LLVM_ShuffleVectorOp
: LLVM_OneResultOp<"shufflevector", [NoSideEffect]>,
Arguments<(ins LLVM_Type:$v1, LLVM_Type:$v2, ArrayAttr:$mask)>,
LLVM_Builder<
"$res = builder.CreateShuffleVector($v1, $v2, extractPosition($mask));"> {
let builders = [OpBuilder<
"Builder *b, OperationState &result, Value v1, Value v2, "
"ArrayAttr mask, ArrayRef<NamedAttribute> attrs = {}">];
let verifier = [{
auto wrappedVectorType1 = v1().getType().cast<LLVM::LLVMType>();
auto wrappedVectorType2 = v2().getType().cast<LLVM::LLVMType>();
if (!wrappedVectorType2.getUnderlyingType()->isVectorTy())
return emitOpError("expected LLVM IR Dialect vector type for operand #2");
if (wrappedVectorType1.getVectorElementType() !=
wrappedVectorType2.getVectorElementType())
return emitOpError("expected matching LLVM IR Dialect element types");
return success();
}];
let parser = [{ return parseShuffleVectorOp(parser, result); }];
let printer = [{ printShuffleVectorOp(p, *this); }];
}
// Misc operations.
def LLVM_SelectOp
: LLVM_OneResultOp<"select",
[NoSideEffect, AllTypesMatch<["trueValue", "falseValue", "res"]>]>,
Arguments<(ins LLVM_Type:$condition, LLVM_Type:$trueValue,
LLVM_Type:$falseValue)>,
LLVM_Builder<
"$res = builder.CreateSelect($condition, $trueValue, $falseValue);"> {
let builders = [OpBuilder<
"Builder *b, OperationState &result, Value condition, Value lhs, "
"Value rhs", [{
build(b, result, lhs.getType(), condition, lhs, rhs);
}]>];
let assemblyFormat = "operands attr-dict `:` type($condition) `,` type($res)";
}
def LLVM_FreezeOp : LLVM_OneResultOp<"freeze", [SameOperandsAndResultType]>,
Arguments<(ins LLVM_Type:$val)> {
let assemblyFormat = "$val attr-dict `:` type($val)";
string llvmBuilder = "builder.CreateFreeze($val);";
}
// Terminators.
def LLVM_BrOp : LLVM_TerminatorOp<"br",
[DeclareOpInterfaceMethods<BranchOpInterface>, NoSideEffect]> {
let arguments = (ins Variadic<LLVM_Type>:$destOperands);
let successors = (successor AnySuccessor:$dest);
let assemblyFormat = [{
$dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict
}];
let builders = [LLVM_TerminatorPassthroughOpBuilder];
}
def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br",
[AttrSizedOperandSegments, DeclareOpInterfaceMethods<BranchOpInterface>,
NoSideEffect]> {
let arguments = (ins LLVMI1:$condition,
Variadic<LLVM_Type>:$trueDestOperands,
Variadic<LLVM_Type>:$falseDestOperands);
let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
let assemblyFormat = [{
$condition `,`
$trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,`
$falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)?
attr-dict
}];
let builders = [OpBuilder<
"Builder *builder, OperationState &result, Value condition,"
"Block *trueDest, ValueRange trueOperands,"
"Block *falseDest, ValueRange falseOperands", [{
build(builder, result, condition, trueOperands, falseOperands, trueDest,
falseDest);
}]>, OpBuilder<
"Builder *builder, OperationState &result, Value condition,"
"Block *trueDest, Block *falseDest, ValueRange falseOperands = {}", [{
build(builder, result, condition, trueDest, ValueRange(), falseDest,
falseOperands);
}]>, LLVM_TerminatorPassthroughOpBuilder];
}
def LLVM_ReturnOp : LLVM_TerminatorOp<"return", [NoSideEffect]>,
Arguments<(ins Variadic<LLVM_Type>:$args)> {
string llvmBuilder = [{
if ($_numOperands != 0)
builder.CreateRet($args[0]);
else
builder.CreateRetVoid();
}];
let verifier = [{
if (getNumOperands() > 1)
return emitOpError("expects at most 1 operand");
return success();
}];
let parser = [{ return parseReturnOp(parser, result); }];
let printer = [{ printReturnOp(p, *this); }];
}
def LLVM_ResumeOp : LLVM_TerminatorOp<"resume", []> {
let arguments = (ins LLVM_Type:$value);
string llvmBuilder = [{ builder.CreateResume($value); }];
let verifier = [{
if (!isa_and_nonnull<LandingpadOp>(value().getDefiningOp()))
return emitOpError("expects landingpad value as operand");
// No check for personality of function - landingpad op verifies it.
return success();
}];
let assemblyFormat = "$value attr-dict `:` type($value)";
}
def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable", []> {
string llvmBuilder = [{ builder.CreateUnreachable(); }];
let parser = [{ return success(); }];
let printer = [{ p << getOperationName(); }];
}
////////////////////////////////////////////////////////////////////////////////
// Auxiliary operations (do not appear in LLVM IR but necessary for the dialect
// to work correctly).
////////////////////////////////////////////////////////////////////////////////
// Linkage attribute is used on functions and globals. The order follows that of
// https://llvm.org/docs/LangRef.html#linkage-types. The names are equivalent to
// visible names in the IR rather than to enum values names in llvm::GlobalValue
// since the latter is easier to change.
def LinkagePrivate
: LLVM_EnumAttrCase<"Private", "private", "PrivateLinkage", 0>;
def LinkageInternal
: LLVM_EnumAttrCase<"Internal", "internal", "InternalLinkage", 1>;
def LinkageAvailableExternally
: LLVM_EnumAttrCase<"AvailableExternally", "available_externally",
"AvailableExternallyLinkage", 2>;
def LinkageLinkonce
: LLVM_EnumAttrCase<"Linkonce", "linkonce", "LinkOnceAnyLinkage", 3>;
def LinkageWeak
: LLVM_EnumAttrCase<"Weak", "weak", "WeakAnyLinkage", 4>;
def LinkageCommon
: LLVM_EnumAttrCase<"Common", "common", "CommonLinkage", 5>;
def LinkageAppending
: LLVM_EnumAttrCase<"Appending", "appending", "AppendingLinkage", 6>;
def LinkageExternWeak
: LLVM_EnumAttrCase<"ExternWeak", "extern_weak", "ExternalWeakLinkage", 7>;
def LinkageLinkonceODR
: LLVM_EnumAttrCase<"LinkonceODR", "linkonce_odr", "LinkOnceODRLinkage", 8>;
def LinkageWeakODR
: LLVM_EnumAttrCase<"WeakODR", "weak_odr", "WeakODRLinkage", 9>;
def LinkageExternal
: LLVM_EnumAttrCase<"External", "external", "ExternalLinkage", 10>;
def Linkage : LLVM_EnumAttr<
"Linkage",
"::llvm::GlobalValue::LinkageTypes",
"LLVM linkage types",
[LinkagePrivate, LinkageInternal, LinkageAvailableExternally,
LinkageLinkonce, LinkageWeak, LinkageCommon, LinkageAppending,
LinkageExternWeak, LinkageLinkonceODR, LinkageWeakODR, LinkageExternal]> {
let cppNamespace = "::mlir::LLVM";
}
def LLVM_AddressOfOp
: LLVM_OneResultOp<"mlir.addressof">,
Arguments<(ins FlatSymbolRefAttr:$global_name)> {
let builders = [
OpBuilder<"Builder *builder, OperationState &result, LLVMType resType, "
"StringRef name, ArrayRef<NamedAttribute> attrs = {}", [{
result.addAttribute("global_name", builder->getSymbolRefAttr(name));
result.addAttributes(attrs);
result.addTypes(resType);}]>,
OpBuilder<"Builder *builder, OperationState &result, GlobalOp global, "
"ArrayRef<NamedAttribute> attrs = {}", [{
build(builder, result,
global.getType().getPointerTo(global.addr_space().getZExtValue()),
global.sym_name(), attrs);}]>
];
let extraClassDeclaration = [{
/// Return the llvm.mlir.global operation that defined the value referenced
/// here.
GlobalOp getGlobal();
}];
let assemblyFormat = "$global_name attr-dict `:` type($res)";
let verifier = "return ::verify(*this);";
}
def LLVM_GlobalOp
: LLVM_ZeroResultOp<"mlir.global",
[IsolatedFromAbove,
SingleBlockImplicitTerminator<"ReturnOp">, Symbol]> {
let arguments = (ins
TypeAttr:$type,
UnitAttr:$constant,
StrAttr:$sym_name,
Linkage:$linkage,
OptionalAttr<AnyAttr>:$value,
DefaultValuedAttr<Confined<I32Attr, [IntNonNegative]>, "0">:$addr_space
);
let summary = "LLVM dialect global.";
let description = [{
Can contain an optional initializer region or attribute for simple
initializers.
Examples:
// Initialized using an attribute.
llvm.mlir.global @a("abc") : !llvm<"[3 x i8]">
// Initialized using a region.
llvm.mlir.global constant @b() : !llvm<"i32*"> {
%0 = llvm.constant(0 : i32) : !llvm.i32
%1 = llvm.inttoptr %0 : !llvm.i32 to !llvm<"i32*">
llvm.return %1 : !llvm<"i32*">
}
}];
let regions = (region AnyRegion:$initializer);
let builders = [
OpBuilder<"Builder *builder, OperationState &result, LLVMType type, "
"bool isConstant, Linkage linkage, StringRef name, "
"Attribute value, unsigned addrSpace = 0, "
"ArrayRef<NamedAttribute> attrs = {}">
];
let extraClassDeclaration = [{
/// Return the LLVM type of the global.
LLVMType getType() {
return type().cast<LLVMType>();
}
/// Return the initializer attribute if it exists, or a null attribute.
Attribute getValueOrNull() {
return value().getValueOr(Attribute());
}
/// Return the initializer region. This may be empty, but if it is not it
/// terminates in an `llvm.return` op with the initializer value.
Region &getInitializerRegion() {
return getOperation()->getRegion(0);
}
/// Return the initializer block. If the initializer region is empty this
/// is nullptr. If it is not nullptr, it terminates with an `llvm.return`
/// op with the initializer value.
Block *getInitializerBlock() {
return getInitializerRegion().empty() ?
nullptr : &getInitializerRegion().front();
}
}];
let printer = "printGlobalOp(p, *this);";
let parser = "return parseGlobalOp(parser, result);";
let verifier = "return ::verify(*this);";
}
def LLVM_LLVMFuncOp
: LLVM_ZeroResultOp<"func", [IsolatedFromAbove, FunctionLike, Symbol]>,
Arguments<(ins DefaultValuedAttr<Linkage,
"Linkage::External">:$linkage,
OptionalAttr<FlatSymbolRefAttr>:$personality,
OptionalAttr<ArrayAttr>:$passthrough)> {
let summary = "LLVM dialect function, has wrapped LLVM IR function type";
let regions = (region AnyRegion:$body);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<"Builder *builder, OperationState &result, StringRef name, "
"LLVMType type, LLVM::Linkage linkage = LLVM::Linkage::External, "
"ArrayRef<NamedAttribute> attrs = {}, "
"ArrayRef<NamedAttributeList> argAttrs = {}">
];
let extraClassDeclaration = [{
// Add an entry block to an empty function, and set up the block arguments
// to match the signature of the function.
Block *addEntryBlock();
LLVMType getType() {
return getAttrOfType<TypeAttr>(getTypeAttrName())
.getValue().cast<LLVMType>();
}
bool isVarArg() {
return getType().getUnderlyingType()->isFunctionVarArg();
}
// Hook for OpTrait::FunctionLike, returns the number of function arguments.
// Depends on the type attribute being correct as checked by verifyType.
unsigned getNumFuncArguments();
// Hook for OpTrait::FunctionLike, returns the number of function results.
// Depends on the type attribute being correct as checked by verifyType.
unsigned getNumFuncResults();
// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
// attribute is present. This can check for preconditions of the
// getNumArguments hook not failing.
LogicalResult verifyType();
}];
let verifier = [{ return ::verify(*this); }];
let printer = [{ printLLVMFuncOp(p, *this); }];
let parser = [{ return parseLLVMFuncOp(parser, result); }];
}
def LLVM_NullOp
: LLVM_OneResultOp<"mlir.null", [NoSideEffect]>,
LLVM_Builder<"$res = llvm::ConstantPointerNull::get("
" cast<llvm::PointerType>($_resultType));"> {
let assemblyFormat = "attr-dict `:` type($res)";
let verifier = [{ return ::verify(*this); }];
}
def LLVM_UndefOp : LLVM_OneResultOp<"mlir.undef", [NoSideEffect]>,
LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> {
let assemblyFormat = "attr-dict `:` type($res)";
}
def LLVM_ConstantOp
: LLVM_OneResultOp<"mlir.constant", [NoSideEffect]>,
Arguments<(ins AnyAttr:$value)>,
LLVM_Builder<"$res = getLLVMConstant($_resultType, $value, $_location);">
{
let assemblyFormat = "`(` $value `)` attr-dict `:` type($res)";
}
def LLVM_DialectCastOp : LLVM_Op<"mlir.cast", [NoSideEffect]>,
Results<(outs AnyType:$res)>,
Arguments<(ins AnyType:$in)> {
let summary = "Type cast between LLVM dialect and Standard.";
let description = [{
llvm.mlir.cast op casts between Standard and LLVM dialects. It only changes
the dialect, but does not change compile-time or runtime semantics.
Notice that index type is not supported, as it's Standard-specific.
Example:
llvm.mlir.cast %v : f16 to llvm.half
llvm.mlir.cast %v : llvm.float to f32
llvm.mlir.cast %v : !llvm<"<2 x float>"> to vector<2xf32>
}];
let assemblyFormat = "$in attr-dict `:` type($in) `to` type($res)";
let verifier = "return ::verify(*this);";
}
// Operations that correspond to LLVM intrinsics. With MLIR operation set being
// extendable, there is no reason to introduce a hard boundary between "core"
// operations and intrinsics. However, we systematically prefix them with
// "intr." to avoid potential name clashes.
class LLVM_UnaryIntrinsicOp<string func, list<OpTrait> traits = []> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
Arguments<(ins LLVM_Type:$in)>;
class LLVM_BinarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
Arguments<(ins LLVM_Type:$a, LLVM_Type:$b)>;
class LLVM_TernarySameArgsIntrinsicOp<string func, list<OpTrait> traits = []> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([NoSideEffect, SameOperandsAndResultType], traits)>,
Arguments<(ins LLVM_Type:$a, LLVM_Type:$b, LLVM_Type:$c)>;
def LLVM_CopySignOp : LLVM_BinarySameArgsIntrinsicOp<"copysign">;
def LLVM_CosOp : LLVM_UnaryIntrinsicOp<"cos">;
def LLVM_ExpOp : LLVM_UnaryIntrinsicOp<"exp">;
def LLVM_Exp2Op : LLVM_UnaryIntrinsicOp<"exp2">;
def LLVM_FAbsOp : LLVM_UnaryIntrinsicOp<"fabs">;
def LLVM_FCeilOp : LLVM_UnaryIntrinsicOp<"ceil">;
def LLVM_FMAOp : LLVM_TernarySameArgsIntrinsicOp<"fma">;
def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrinsicOp<"fmuladd">;
def LLVM_Log10Op : LLVM_UnaryIntrinsicOp<"log10">;
def LLVM_Log2Op : LLVM_UnaryIntrinsicOp<"log2">;
def LLVM_LogOp : LLVM_UnaryIntrinsicOp<"log">;
def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0]>,
Arguments<(ins LLVM_Type:$addr, LLVM_Type:$rw,
LLVM_Type:$hint, LLVM_Type:$cache)>;
def LLVM_SqrtOp : LLVM_UnaryIntrinsicOp<"sqrt">;
//
// Vector Reductions.
//
def LLVM_experimental_vector_reduce_add : LLVM_VectorReduction<"add">;
def LLVM_experimental_vector_reduce_and : LLVM_VectorReduction<"and">;
def LLVM_experimental_vector_reduce_mul : LLVM_VectorReduction<"mul">;
def LLVM_experimental_vector_reduce_fmax : LLVM_VectorReduction<"fmax">;
def LLVM_experimental_vector_reduce_fmin : LLVM_VectorReduction<"fmin">;
def LLVM_experimental_vector_reduce_or : LLVM_VectorReduction<"or">;
def LLVM_experimental_vector_reduce_smax : LLVM_VectorReduction<"smax">;
def LLVM_experimental_vector_reduce_smin : LLVM_VectorReduction<"smin">;
def LLVM_experimental_vector_reduce_umax : LLVM_VectorReduction<"umax">;
def LLVM_experimental_vector_reduce_umin : LLVM_VectorReduction<"umin">;
def LLVM_experimental_vector_reduce_xor : LLVM_VectorReduction<"xor">;
def LLVM_experimental_vector_reduce_v2_fadd : LLVM_VectorReductionV2<"fadd">;
def LLVM_experimental_vector_reduce_v2_fmul : LLVM_VectorReductionV2<"fmul">;
//
// LLVM Matrix operations.
//
/// Create a columnwise, strided 2-D matrix load, as specified in the LLVM
/// MatrixBuilder.
/// data - Start address of the matrix read
/// rows - Number of rows in matrix (must be a constant)
/// columns - Number of columns in matrix (must be a constant)
/// stride - Space between columns
def LLVM_MatrixColumnsWiseLoadOp
: LLVM_OneResultOp<"intr.matrix.columnwise.load">,
Arguments<(ins LLVM_Type:$data, LLVM_Type:$stride,
I32Attr:$rows, I32Attr:$columns)> {
string llvmBuilder = [{
llvm::MatrixBuilder<decltype(builder)> mb(builder);
$res = mb.CreateMatrixColumnwiseLoad(
$data, $rows.getZExtValue(), $columns.getZExtValue(), $stride);
}];
let assemblyFormat = "$data `,` `<` `stride` `=` $stride `>` attr-dict"
"`:` type($res) `from` type($data) `stride` type($stride)";
}
/// Create a columnwise, strided 2-D matrix store, as specified in the LLVM
/// MatrixBuilder.
/// matrix - Matrix to store
/// ptr - Pointer to write back to
/// rows - Number of rows in matrix (must be a constant)
/// columns - Number of columns in matrix (must be a constant)
/// stride - Space between columns
def LLVM_MatrixColumnsWiseStoreOp
: LLVM_ZeroResultOp<"intr.matrix.columnwise.store">,
Arguments<(ins LLVM_Type:$matrix, LLVM_Type:$data, LLVM_Type:$stride,
I32Attr:$rows, I32Attr:$columns)> {
string llvmBuilder = [{
llvm::MatrixBuilder<decltype(builder)> mb(builder);
mb.CreateMatrixColumnwiseStore(
$matrix, $data, $stride, $rows.getZExtValue(), $columns.getZExtValue());
}];
let assemblyFormat = "$matrix `,` $data `,` `<` `stride` `=` $stride `>` "
"attr-dict`:` type($matrix) `to` type($data) `stride` type($stride)";
}
/// Create a llvm.matrix.multiply call, multiplying 2-D matrices LHS and RHS, as
/// specified in the LLVM MatrixBuilder.
def LLVM_MatrixMultiplyOp
: LLVM_OneResultOp<"intr.matrix.multiply">,
Arguments<(
ins LLVM_Type:$lhs, LLVM_Type:$rhs,
I32Attr:$lhs_rows, I32Attr:$lhs_columns, I32Attr:$rhs_columns)> {
string llvmBuilder = [{
llvm::MatrixBuilder<decltype(builder)> mb(builder);
$res = mb.CreateMatrixMultiply(
$lhs, $rhs, $lhs_rows.getZExtValue(), $lhs_columns.getZExtValue(),
$rhs_columns.getZExtValue());
}];
let assemblyFormat = "$lhs `,` $rhs attr-dict "
"`:` `(` type($lhs) `,` type($rhs) `)` `->` type($res)";
}
/// Create a llvm.matrix.transpose call, transposing a `rows` x `columns` 2-D
/// `matrix`, as specified in the LLVM MatrixBuilder.
def LLVM_MatrixTransposeOp
: LLVM_OneResultOp<"intr.matrix.transpose">,
Arguments<(ins LLVM_Type:$matrix, I32Attr:$rows, I32Attr:$columns)> {
string llvmBuilder = [{
llvm::MatrixBuilder<decltype(builder)> mb(builder);
$res = mb.CreateMatrixTranspose(
$matrix, $rows.getZExtValue(), $columns.getZExtValue());
}];
let assemblyFormat = "$matrix attr-dict `:` type($matrix) `into` type($res)";
}
//
// LLVM masked operations.
//
/// Create a call to Masked Load intrinsic.
def LLVM_MaskedLoadOp
: LLVM_OneResultOp<"intr.masked.load">,
Arguments<(ins LLVM_Type:$data, LLVM_Type:$mask,
Variadic<LLVM_Type>:$pass_thru, I32Attr:$alignment)> {
string llvmBuilder = [{
$res = $pass_thru.empty() ? builder.CreateMaskedLoad(
$data, llvm::Align($alignment.getZExtValue()), $mask) :
builder.CreateMaskedLoad(
$data, llvm::Align($alignment.getZExtValue()), $mask, $pass_thru[0]);
}];
let assemblyFormat =
"operands attr-dict `:` functional-type(operands, results)";
}
/// Create a call to Masked Store intrinsic.
def LLVM_MaskedStoreOp
: LLVM_ZeroResultOp<"intr.masked.store">,
Arguments<(ins LLVM_Type:$value, LLVM_Type:$data, LLVM_Type:$mask,
I32Attr:$alignment)> {
string llvmBuilder = [{
builder.CreateMaskedStore(
$value, $data, llvm::Align($alignment.getZExtValue()), $mask);
}];
let assemblyFormat = "$value `,` $data `,` $mask attr-dict `:` "
"type($value) `,` type($mask) `into` type($data)";
}
//
// Atomic operations.
//
def AtomicBinOpXchg : I64EnumAttrCase<"xchg", 0>;
def AtomicBinOpAdd : I64EnumAttrCase<"add", 1>;
def AtomicBinOpSub : I64EnumAttrCase<"sub", 2>;
def AtomicBinOpAnd : I64EnumAttrCase<"_and", 3>;
def AtomicBinOpNand : I64EnumAttrCase<"nand", 4>;
def AtomicBinOpOr : I64EnumAttrCase<"_or", 5>;
def AtomicBinOpXor : I64EnumAttrCase<"_xor", 6>;
def AtomicBinOpMax : I64EnumAttrCase<"max", 7>;
def AtomicBinOpMin : I64EnumAttrCase<"min", 8>;
def AtomicBinOpUMax : I64EnumAttrCase<"umax", 9>;
def AtomicBinOpUMin : I64EnumAttrCase<"umin", 10>;
def AtomicBinOpFAdd : I64EnumAttrCase<"fadd", 11>;
def AtomicBinOpFSub : I64EnumAttrCase<"fsub", 12>;
def AtomicBinOp : I64EnumAttr<
"AtomicBinOp",
"llvm.atomicrmw binary operations",
[AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd,
AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax,
AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd,
AtomicBinOpFSub]> {
let cppNamespace = "::mlir::LLVM";
}
def AtomicOrderingNotAtomic : I64EnumAttrCase<"not_atomic", 0>;
def AtomicOrderingUnordered : I64EnumAttrCase<"unordered", 1>;
def AtomicOrderingMonotonic : I64EnumAttrCase<"monotonic", 2>;
def AtomicOrderingAcquire : I64EnumAttrCase<"acquire", 4>;
def AtomicOrderingRelease : I64EnumAttrCase<"release", 5>;
def AtomicOrderingAcquireRelease : I64EnumAttrCase<"acq_rel", 6>;
def AtomicOrderingSequentiallyConsistent : I64EnumAttrCase<"seq_cst", 7>;
def AtomicOrdering : I64EnumAttr<
"AtomicOrdering",
"Atomic ordering for LLVM's memory model",
[AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic,
AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcquireRelease,
AtomicOrderingSequentiallyConsistent]> {
let cppNamespace = "::mlir::LLVM";
}
def LLVM_AtomicRMWOp : LLVM_Op<"atomicrmw">,
Arguments<(ins AtomicBinOp:$bin_op, LLVM_Type:$ptr, LLVM_Type:$val,
AtomicOrdering:$ordering)>,
Results<(outs LLVM_Type:$res)> {
let llvmBuilder = [{
$res = builder.CreateAtomicRMW(getLLVMAtomicBinOp($bin_op), $ptr, $val,
getLLVMAtomicOrdering($ordering));
}];
let parser = [{ return parseAtomicRMWOp(parser, result); }];
let printer = [{ printAtomicRMWOp(p, *this); }];
let verifier = "return ::verify(*this);";
}
def LLVM_AtomicCmpXchgOp : LLVM_Op<"cmpxchg">,
Arguments<(ins LLVM_Type:$ptr, LLVM_Type:$cmp, LLVM_Type:$val,
AtomicOrdering:$success_ordering,
AtomicOrdering:$failure_ordering)>,
Results<(outs LLVM_Type:$res)> {
let llvmBuilder = [{
$res = builder.CreateAtomicCmpXchg($ptr, $cmp, $val,
getLLVMAtomicOrdering($success_ordering),
getLLVMAtomicOrdering($failure_ordering));
}];
let parser = [{ return parseAtomicCmpXchgOp(parser, result); }];
let printer = [{ printAtomicCmpXchgOp(p, *this); }];
let verifier = "return ::verify(*this);";
}
def LLVM_AssumeOp : LLVM_Op<"intr.assume", []>,
Arguments<(ins LLVM_Type:$cond)> {
let llvmBuilder = [{
llvm::Module *module = builder.GetInsertBlock()->getModule();
llvm::Function *fn =
llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::assume, {});
builder.CreateCall(fn, {$cond});
}];
}
def LLVM_FenceOp : LLVM_ZeroResultOp<"fence", []>,
Arguments<(ins AtomicOrdering:$ordering,
StrAttr:$syncscope)> {
let llvmBuilder = [{
llvm::LLVMContext &llvmContext = builder.getContext();
builder.CreateFence(getLLVMAtomicOrdering($ordering),
llvmContext.getOrInsertSyncScopeID($syncscope));
}];
let parser = [{ return parseFenceOp(parser, result); }];
let printer = [{ printFenceOp(p, *this); }];
let verifier = "return ::verify(*this);";
}
#endif // LLVMIR_OPS