MLIR 23.0.0git
OpToFuncCallLowering.h
Go to the documentation of this file.
1//===- OpToFuncCallLowering.h - GPU ops lowering to custom calls *- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#ifndef MLIR_CONVERSION_GPUCOMMON_OPTOFUNCCALLLOWERING_H_
9#define MLIR_CONVERSION_GPUCOMMON_OPTOFUNCCALLLOWERING_H_
10
15#include "mlir/IR/Builders.h"
16
17namespace mlir {
18
19namespace {
20/// Detection trait tor the `getFastmath` instance method.
21template <typename T>
22using has_get_fastmath_t = decltype(std::declval<T>().getFastmath());
23} // namespace
24
25/// Rewriting that replaces SourceOp with a CallOp to `f32Func` or `f64Func` or
26/// `f32ApproxFunc` or `f16Func` or `i32Type` depending on the element type and
27/// the fastMathFlag of that Op, if present. The function declaration is added
28/// in case it was not added before.
29///
30/// If the input values are of bf16 type (or f16 type if f16Func is empty), the
31/// value is first casted to f32, the function called and then the result casted
32/// back.
33///
34/// Example with NVVM:
35/// %exp_f32 = math.exp %arg_f32 : f32
36///
37/// will be transformed into
38/// llvm.call @__nv_expf(%arg_f32) : (f32) -> f32
39///
40/// If the fastMathFlag attribute of SourceOp is `afn` or `fast`, this Op lowers
41/// to the approximate calculation function.
42///
43/// Also example with NVVM:
44/// %exp_f32 = math.exp %arg_f32 fastmath<afn> : f32
45///
46/// will be transformed into
47/// llvm.call @__nv_fast_expf(%arg_f32) : (f32) -> f32
48///
49/// Final example with NVVM:
50/// %pow_f32 = math.fpowi %arg_f32, %arg_i32
51///
52/// will be transformed into
53/// llvm.call @__nv_powif(%arg_f32, %arg_i32) : (f32, i32) -> f32
54template <typename SourceOp>
56public:
58 const LLVMTypeConverter &lowering, StringRef f32Func, StringRef f64Func,
59 StringRef f32ApproxFunc, StringRef f16Func, StringRef i32Func = "",
60 PatternBenefit benefit = 1,
61 LLVM::cconv::CConv cconv = LLVM::cconv::CConv::C)
62 : ConvertOpToLLVMPattern<SourceOp>(lowering, benefit), f32Func(f32Func),
65
66 LogicalResult
67 matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor,
68 ConversionPatternRewriter &rewriter) const override {
69 using LLVM::LLVMFuncOp;
70
71 static_assert(
72 std::is_base_of<OpTrait::OneResult<SourceOp>, SourceOp>::value,
73 "expected single result op");
74
75 bool isResultBool = op->getResultTypes().front().isInteger(1);
76 if constexpr (!std::is_base_of<OpTrait::SameOperandsAndResultType<SourceOp>,
77 SourceOp>::value) {
78 assert(op->getNumOperands() > 0 &&
79 "expected op to take at least one operand");
80 assert((op->getResultTypes().front() == op->getOperand(0).getType() ||
81 isResultBool) &&
82 "expected op with same operand and result types");
83 }
84
85 if (!op->template getParentOfType<FunctionOpInterface>()) {
86 return rewriter.notifyMatchFailure(
87 op, "expected op to be within a function region");
88 }
89
90 SmallVector<Value, 1> castedOperands;
91 for (Value operand : adaptor.getOperands())
92 castedOperands.push_back(maybeCast(operand, rewriter));
93
94 Type castedOperandType = castedOperands.front().getType();
95
96 // At ABI level, booleans are treated as i32.
97 Type resultType =
98 isResultBool ? rewriter.getIntegerType(32) : castedOperandType;
99 Type funcType = getFunctionType(resultType, castedOperands);
100 StringRef funcName = getFunctionName(castedOperandType, op);
101 if (funcName.empty())
102 return failure();
103
104 LLVMFuncOp funcOp = appendOrGetFuncOp(funcName, funcType, op);
105 auto callOp =
106 LLVM::CallOp::create(rewriter, op->getLoc(), funcOp, castedOperands);
107 callOp.setCConv(cconv);
108
109 if (resultType == adaptor.getOperands().front().getType()) {
110 rewriter.replaceOp(op, {callOp.getResult()});
111 return success();
112 }
113
114 // Boolean result are mapping to i32 at the ABI level with zero values being
115 // interpreted as false and non-zero values being interpreted as true. Since
116 // there is no guarantee of a specific value being used to indicate true,
117 // compare for inequality with zero (rather than truncate or shift).
118 if (isResultBool) {
119 Value zero = LLVM::ConstantOp::create(rewriter, op->getLoc(),
120 rewriter.getIntegerType(32),
121 rewriter.getI32IntegerAttr(0));
122 Value truncated =
123 LLVM::ICmpOp::create(rewriter, op->getLoc(), LLVM::ICmpPredicate::ne,
124 callOp.getResult(), zero);
125 rewriter.replaceOp(op, {truncated});
126 return success();
127 }
128
129 assert(callOp.getResult().getType().isF32() &&
130 "only f32 types are supposed to be truncated back");
131 Value truncated = LLVM::FPTruncOp::create(
132 rewriter, op->getLoc(), adaptor.getOperands().front().getType(),
133 callOp.getResult());
134 rewriter.replaceOp(op, {truncated});
135 return success();
136 }
137
138 Value maybeCast(Value operand, PatternRewriter &rewriter) const {
139 Type type = operand.getType();
140 if (!isa<Float16Type, BFloat16Type>(type))
141 return operand;
142
143 // If there's an f16 function, no need to cast f16 values.
144 if (!f16Func.empty() && isa<Float16Type>(type))
145 return operand;
146
147 return LLVM::FPExtOp::create(rewriter, operand.getLoc(),
148 Float32Type::get(rewriter.getContext()),
149 operand);
150 }
151
152 Type getFunctionType(Type resultType, ValueRange operands) const {
153 SmallVector<Type> operandTypes(operands.getTypes());
154 return LLVM::LLVMFunctionType::get(resultType, operandTypes);
155 }
156
157 LLVM::LLVMFuncOp appendOrGetFuncOp(StringRef funcName, Type funcType,
158 Operation *op) const {
159 using LLVM::LLVMFuncOp;
160
161 auto funcAttr = StringAttr::get(op->getContext(), funcName);
162 auto funcOp =
164 if (funcOp)
165 return funcOp;
166
167 auto parentFunc = op->getParentOfType<FunctionOpInterface>();
168 assert(parentFunc && "expected there to be a parent function");
169 OpBuilder b(parentFunc);
170
171 // Create a valid global location removing any metadata attached to the
172 // location as debug info metadata inside of a function cannot be used
173 // outside of that function.
174 auto globalloc = op->getLoc()->findInstanceOfOrUnknown<FileLineColLoc>();
175 auto newFuncOp = LLVMFuncOp::create(b, globalloc, funcName, funcType);
176 newFuncOp.setCConv(cconv);
177 return newFuncOp;
178 }
179
180 StringRef getFunctionName(Type type, SourceOp op) const {
181 bool useApprox = false;
182 if constexpr (llvm::is_detected<has_get_fastmath_t, SourceOp>::value) {
183 arith::FastMathFlags flag = op.getFastmath();
184 useApprox = ((uint32_t)arith::FastMathFlags::afn & (uint32_t)flag) &&
185 !f32ApproxFunc.empty();
186 }
187
188 if (isa<Float16Type>(type))
189 return f16Func;
190 if (isa<Float32Type>(type)) {
191 if (useApprox)
192 return f32ApproxFunc;
193 return f32Func;
194 }
195 if (isa<Float64Type>(type))
196 return f64Func;
197
198 if (type.isInteger(32))
199 return i32Func;
200 return "";
201 }
202
203 const std::string f32Func;
204 const std::string f64Func;
205 const std::string f32ApproxFunc;
206 const std::string f16Func;
207 const std::string i32Func;
208 const LLVM::cconv::CConv cconv;
209};
210
211} // namespace mlir
212
213#endif // MLIR_CONVERSION_GPUCOMMON_OPTOFUNCCALLLOWERING_H_
return success()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
MLIRContext * getContext() const
Definition Builders.h:56
ConvertOpToLLVMPattern(const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
Definition Pattern.h:233
An instance of this location represents a tuple of file, line number, and column number.
Definition Location.h:174
Conversion from types to the LLVM IR dialect.
LocationAttr findInstanceOfOrUnknown()
Return an instance of the given location type if one is nested under the current location else return...
Definition Location.h:60
This class helps build Operations.
Definition Builders.h:209
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition Types.cpp:58
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
Location getLoc() const
Return the location of this value.
Definition Value.cpp:24
Include the generated interface declarations.
const LLVM::cconv::CConv cconv
OpToFuncCallLowering(const LLVMTypeConverter &lowering, StringRef f32Func, StringRef f64Func, StringRef f32ApproxFunc, StringRef f16Func, StringRef i32Func="", PatternBenefit benefit=1, LLVM::cconv::CConv cconv=LLVM::cconv::CConv::C)
StringRef getFunctionName(Type type, SourceOp op) const
LLVM::LLVMFuncOp appendOrGetFuncOp(StringRef funcName, Type funcType, Operation *op) const
LogicalResult matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const override
Methods that operate on the SourceOp type.
Type getFunctionType(Type resultType, ValueRange operands) const
Value maybeCast(Value operand, PatternRewriter &rewriter) const