diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -75,9 +75,7 @@ class LLVM_Op traits = []> : LLVM_OpBase; -// Base class for LLVM intrinsics operation. It is the same as an LLVM_Op -// but the operation has a ".intr." element in the prefix becoming -// "llvm.intr.*". +// Compatibility class for LLVM intrinsic operations. class LLVM_IntrOp traits = []> : LLVM_Op<"intr."#mnemonic, traits>; @@ -115,42 +113,96 @@ string llvmClassName = llvmName; } -// LLVM vector reduction over a single vector. -class LLVM_VectorReduction : - LLVM_IntrOp<"experimental.vector.reduce." # mnem, []>, - Arguments<(ins LLVM_Type)>, Results<(outs LLVM_Type:$res)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( - module, - llvm::Intrinsic::experimental_vector_reduce_}] # - !subst(".","_", mnem) # [{, { - opInst.getOperand(0).getType().cast() - .getUnderlyingType(), - }); - auto operands = lookupValues(opInst.getOperands()); - $res = builder.CreateCall(fn, operands); - }]; +// 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 values> { + list lst = !foreach(x, values, + !subst("$0", !cast(x), pattern)); } -// LLVM vector reduction over a single vector, with an initial value. -class LLVM_VectorReductionV2 : - LLVM_IntrOp<"experimental.vector.reduce.v2." # mnem, []>, - Arguments<(ins LLVM_Type, LLVM_Type)>, Results<(outs LLVM_Type:$res)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( +// Patterns with code obtaining the LLVM IR type of the given operand or result +// of operation. "$0" is expected to be replaced by the position of the operand +// or result in the operation. +def LLVM_IntrPatterns { + string operand = + [{opInst.getOperand($0).getType() + .cast().getUnderlyingType()}]; + string result = + [{opInst.getResult($0).getType() + .cast().getUnderlyingType()}]; +} + + +// Base class for LLVM intrinsics operation. It is similar to LLVM_Op, but +// provides the "llvmBuilder" field for constructing the intrinsic. The builder +// relies on the contents on "overloadedResults" and "overloadedOperands" lists +// that contain the positions of intrinsic results and operands that are +// overloadable in the LLVM sense, that is their types must be passed in during +// the construction of the intrinsic declaration to differentiate between +// differently-typed versions of the intrinsic. "opName" contains the name of +// the operation to be associated with the intrinsic and "enumName" contains the +// name of the intrinsic as appears in `llvm::Intrinsic` enum; one usually wants +// these to be related. +class LLVM_IntrOpBase overloadedResults, list overloadedOperands, + list traits, bit hasResult> + : LLVM_OpBase, + Results { + let llvmBuilder = [{ + llvm::Module *module = builder.GetInsertBlock()->getModule(); + llvm::Function *fn = llvm::Intrinsic::getDeclaration( module, - llvm::Intrinsic::experimental_vector_reduce_v2_}] # - !subst(".","_", mnem) # [{, { - opInst.getResult(0).getType().cast() - .getUnderlyingType(), - opInst.getOperand(1).getType().cast() - .getUnderlyingType(), + llvm::Intrinsic::}] # enumName # [{, + { }] # StrJoin.lst, + ListIntSubst.lst)>.result # [{ }); - auto operands = lookupValues(opInst.getOperands()); - $res = builder.CreateCall(fn, operands); - }]; + auto operands = lookupValues(opInst.getOperands()); + }] # !if(hasResult, "$res = ", "") # [{builder.CreateCall(fn, operands); + }]; } +// Base class for LLVM intrinsic operations returning no results. Places the +// intrinsic into the LLVM dialect and prefixes its name with "intr.". +// +// Sample use: derive an entry from this class and populate the fields. +// +// def LLVM_Name : LLVM_ZeroResultIntrOp<"name", [0], [NoSideEffect]>, +// Arguments<(ins LLVM_Type, LLVM_Type)>; +// +// The mnemonic will be prefixed with "llvm.intr.", where the "llvm." part comes +// from the LLVM dialect. The overloadedOperands list contains the indices of +// the operands the type of which will be passed in the LLVM IR intrinsic +// builder. In the example above, the Op has two arguments, but only the first +// one (as indicated by `[0]`) is necessary to resolve the overloaded intrinsic. +// The Op has no results. +class LLVM_ZeroResultIntrOp overloadedOperands = [], + list traits = []> + : LLVM_IntrOpBase; + +// Base class for LLVM intrinsic operations returning one result. Places the +// intrinsic into the LLVM dialect and prefixes its name with "intr.". This is +// similar to LLVM_ZeroResultIntrOp but allows one to define Ops returning one +// result, called "res". Additionally, the overloadedResults list should contain +// "0" if the result must be used to resolve overloaded intrinsics, or remain +// empty otherwise. +class LLVM_OneResultIntrOp overloadedResults = [], + list overloadedOperands = [], + list traits = []> + : LLVM_IntrOpBase; + +// LLVM vector reduction over a single vector. +class LLVM_VectorReduction + : LLVM_OneResultIntrOp<"experimental.vector.reduce." # mnem, [], [0], []>, + Arguments<(ins LLVM_Type)>; + +// LLVM vector reduction over a single vector, with an initial value. +class LLVM_VectorReductionV2 + : LLVM_OneResultIntrOp<"experimental.vector.reduce.v2." # mnem, + [0], [1], []>, + Arguments<(ins LLVM_Type, LLVM_Type)>; + #endif // LLVMIR_OP_BASE diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -692,84 +692,34 @@ // "intr." to avoid potential name clashes. class LLVM_UnaryIntrinsicOp traits = []> : - LLVM_OneResultOp<"intr." # func, + LLVM_OneResultIntrOp, - Arguments<(ins LLVM_Type:$in)>, - LLVM_Builder<"$res = builder.CreateCall(llvm::Intrinsic::getDeclaration(" - "builder.GetInsertBlock()->getModule(), llvm::Intrinsic::" # func # "," - "{$in->getType()}), {$in});"> { -} + Arguments<(ins LLVM_Type:$in)>; class LLVM_BinarySameArgsIntrinsicOp traits = []> : - LLVM_OneResultOp<"intr." # func, + LLVM_OneResultIntrOp, - Arguments<(ins LLVM_Type:$a, LLVM_Type:$b)>, - LLVM_Builder<"$res = builder.CreateCall(llvm::Intrinsic::getDeclaration(" - "builder.GetInsertBlock()->getModule(), llvm::Intrinsic::" # func # "," - "{$a->getType()}), {$a, $b});"> { -} + Arguments<(ins LLVM_Type:$a, LLVM_Type:$b)>; class LLVM_TernarySameArgsIntrinsicOp traits = []> : - LLVM_OneResultOp<"intr." # func, + LLVM_OneResultIntrOp, - Arguments<(ins LLVM_Type:$a, LLVM_Type:$b, LLVM_Type:$c)>, - LLVM_Builder<"$res = builder.CreateCall(llvm::Intrinsic::getDeclaration(" - "builder.GetInsertBlock()->getModule(), llvm::Intrinsic::" # func # "," - "{$a->getType()}), {$a, $b, $c});"> { -} + 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_FAbsOp : LLVM_UnaryIntrinsicOp<"fabs">; def LLVM_FCeilOp : LLVM_UnaryIntrinsicOp<"ceil">; -def LLVM_CosOp : LLVM_UnaryIntrinsicOp<"cos">; -def LLVM_CopySignOp : LLVM_BinarySameArgsIntrinsicOp<"copysign">; def LLVM_FMAOp : LLVM_TernarySameArgsIntrinsicOp<"fma">; def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrinsicOp<"fmuladd">; -def LLVM_SqrtOp : LLVM_UnaryIntrinsicOp<"sqrt">; - -def LLVM_LogOp : LLVM_Op<"intr.log", [NoSideEffect]>, - Arguments<(ins LLVM_Type:$in)>, - Results<(outs LLVM_Type:$res)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( - module, llvm::Intrinsic::log, {$in->getType()}); - $res = builder.CreateCall(fn, {$in}); - }]; -} - -def LLVM_Log10Op : LLVM_Op<"intr.log10", [NoSideEffect]>, - Arguments<(ins LLVM_Type:$in)>, - Results<(outs LLVM_Type:$res)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( - module, llvm::Intrinsic::log10, {$in->getType()}); - $res = builder.CreateCall(fn, {$in}); - }]; -} - -def LLVM_Log2Op : LLVM_Op<"intr.log2", [NoSideEffect]>, - Arguments<(ins LLVM_Type:$in)>, - Results<(outs LLVM_Type:$res)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( - module, llvm::Intrinsic::log2, {$in->getType()}); - $res = builder.CreateCall(fn, {$in}); - }]; -} - -def LLVM_Prefetch : LLVM_ZeroResultOp<"intr.prefetch">, +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)> { - let llvmBuilder = [{ - llvm::Module *module = builder.GetInsertBlock()->getModule(); - llvm::Function *fn = llvm::Intrinsic::getDeclaration( - module, llvm::Intrinsic::prefetch, $addr->getType()); - builder.CreateCall(fn, {$addr, $rw, $hint, $cache}); - }]; -} + LLVM_Type:$hint, LLVM_Type:$cache)>; +def LLVM_SqrtOp : LLVM_UnaryIntrinsicOp<"sqrt">; // // Vector Reductions.