xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===----------------------------------------------------------------------===//
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 //
9 // This contains code to emit Builtin calls as CIR or a function call to be
10 // later resolved.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "CIRGenCall.h"
15 #include "CIRGenConstantEmitter.h"
16 #include "CIRGenFunction.h"
17 #include "CIRGenModule.h"
18 #include "CIRGenValue.h"
19 #include "mlir/IR/BuiltinAttributes.h"
20 #include "mlir/IR/Value.h"
21 #include "mlir/Support/LLVM.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/GlobalDecl.h"
24 #include "clang/CIR/MissingFeatures.h"
25 #include "llvm/Support/ErrorHandling.h"
26 
27 using namespace clang;
28 using namespace clang::CIRGen;
29 using namespace llvm;
30 
emitLibraryCall(CIRGenFunction & cgf,const FunctionDecl * fd,const CallExpr * e,mlir::Operation * calleeValue)31 static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd,
32                               const CallExpr *e, mlir::Operation *calleeValue) {
33   CIRGenCallee callee = CIRGenCallee::forDirect(calleeValue, GlobalDecl(fd));
34   return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot());
35 }
36 
37 template <typename Op>
emitBuiltinBitOp(CIRGenFunction & cgf,const CallExpr * e,bool poisonZero=false)38 static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
39                                bool poisonZero = false) {
40   assert(!cir::MissingFeatures::builtinCheckKind());
41 
42   mlir::Value arg = cgf.emitScalarExpr(e->getArg(0));
43   CIRGenBuilderTy &builder = cgf.getBuilder();
44 
45   Op op;
46   if constexpr (std::is_same_v<Op, cir::BitClzOp> ||
47                 std::is_same_v<Op, cir::BitCtzOp>)
48     op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg, poisonZero);
49   else
50     op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg);
51 
52   mlir::Value result = op.getResult();
53   mlir::Type exprTy = cgf.convertType(e->getType());
54   if (exprTy != result.getType())
55     result = builder.createIntCast(result, exprTy);
56 
57   return RValue::get(result);
58 }
59 
emitBuiltinExpr(const GlobalDecl & gd,unsigned builtinID,const CallExpr * e,ReturnValueSlot returnValue)60 RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
61                                        const CallExpr *e,
62                                        ReturnValueSlot returnValue) {
63   mlir::Location loc = getLoc(e->getSourceRange());
64 
65   // See if we can constant fold this builtin.  If so, don't emit it at all.
66   // TODO: Extend this handling to all builtin calls that we can constant-fold.
67   Expr::EvalResult result;
68   if (e->isPRValue() && e->EvaluateAsRValue(result, cgm.getASTContext()) &&
69       !result.hasSideEffects()) {
70     if (result.Val.isInt())
71       return RValue::get(builder.getConstInt(loc, result.Val.getInt()));
72     if (result.Val.isFloat()) {
73       // Note: we are using result type of CallExpr to determine the type of
74       // the constant. Classic codegen uses the result value to determine the
75       // type. We feel it should be Ok to use expression type because it is
76       // hard to imagine a builtin function evaluates to a value that
77       // over/underflows its own defined type.
78       mlir::Type type = convertType(e->getType());
79       return RValue::get(builder.getConstFP(loc, type, result.Val.getFloat()));
80     }
81   }
82 
83   const FunctionDecl *fd = gd.getDecl()->getAsFunction();
84 
85   assert(!cir::MissingFeatures::builtinCallF128());
86 
87   // If the builtin has been declared explicitly with an assembler label,
88   // disable the specialized emitting below. Ideally we should communicate the
89   // rename in IR, or at least avoid generating the intrinsic calls that are
90   // likely to get lowered to the renamed library functions.
91   unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID;
92 
93   assert(!cir::MissingFeatures::builtinCallMathErrno());
94   assert(!cir::MissingFeatures::builtinCall());
95 
96   switch (builtinIDIfNoAsmLabel) {
97   default:
98     break;
99 
100   case Builtin::BI__assume:
101   case Builtin::BI__builtin_assume: {
102     if (e->getArg(0)->HasSideEffects(getContext()))
103       return RValue::get(nullptr);
104 
105     mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0));
106     builder.create<cir::AssumeOp>(loc, argValue);
107     return RValue::get(nullptr);
108   }
109 
110   case Builtin::BI__builtin_complex: {
111     mlir::Value real = emitScalarExpr(e->getArg(0));
112     mlir::Value imag = emitScalarExpr(e->getArg(1));
113     mlir::Value complex = builder.createComplexCreate(loc, real, imag);
114     return RValue::get(complex);
115   }
116 
117   case Builtin::BI__builtin_creal:
118   case Builtin::BI__builtin_crealf:
119   case Builtin::BI__builtin_creall:
120   case Builtin::BIcreal:
121   case Builtin::BIcrealf:
122   case Builtin::BIcreall: {
123     mlir::Value complex = emitComplexExpr(e->getArg(0));
124     mlir::Value real = builder.createComplexReal(loc, complex);
125     return RValue::get(real);
126   }
127 
128   case Builtin::BI__builtin_cimag:
129   case Builtin::BI__builtin_cimagf:
130   case Builtin::BI__builtin_cimagl:
131   case Builtin::BIcimag:
132   case Builtin::BIcimagf:
133   case Builtin::BIcimagl: {
134     mlir::Value complex = emitComplexExpr(e->getArg(0));
135     mlir::Value imag = builder.createComplexImag(loc, complex);
136     return RValue::get(imag);
137   }
138 
139   case Builtin::BI__builtin_clrsb:
140   case Builtin::BI__builtin_clrsbl:
141   case Builtin::BI__builtin_clrsbll:
142     return emitBuiltinBitOp<cir::BitClrsbOp>(*this, e);
143 
144   case Builtin::BI__builtin_ctzs:
145   case Builtin::BI__builtin_ctz:
146   case Builtin::BI__builtin_ctzl:
147   case Builtin::BI__builtin_ctzll:
148   case Builtin::BI__builtin_ctzg:
149     assert(!cir::MissingFeatures::builtinCheckKind());
150     return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/true);
151 
152   case Builtin::BI__builtin_clzs:
153   case Builtin::BI__builtin_clz:
154   case Builtin::BI__builtin_clzl:
155   case Builtin::BI__builtin_clzll:
156   case Builtin::BI__builtin_clzg:
157     assert(!cir::MissingFeatures::builtinCheckKind());
158     return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/true);
159 
160   case Builtin::BI__builtin_parity:
161   case Builtin::BI__builtin_parityl:
162   case Builtin::BI__builtin_parityll:
163     return emitBuiltinBitOp<cir::BitParityOp>(*this, e);
164 
165   case Builtin::BI__lzcnt16:
166   case Builtin::BI__lzcnt:
167   case Builtin::BI__lzcnt64:
168     assert(!cir::MissingFeatures::builtinCheckKind());
169     return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false);
170 
171   case Builtin::BI__popcnt16:
172   case Builtin::BI__popcnt:
173   case Builtin::BI__popcnt64:
174   case Builtin::BI__builtin_popcount:
175   case Builtin::BI__builtin_popcountl:
176   case Builtin::BI__builtin_popcountll:
177   case Builtin::BI__builtin_popcountg:
178     return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e);
179 
180   case Builtin::BI__builtin_expect:
181   case Builtin::BI__builtin_expect_with_probability: {
182     mlir::Value argValue = emitScalarExpr(e->getArg(0));
183     mlir::Value expectedValue = emitScalarExpr(e->getArg(1));
184 
185     mlir::FloatAttr probAttr;
186     if (builtinIDIfNoAsmLabel == Builtin::BI__builtin_expect_with_probability) {
187       llvm::APFloat probability(0.0);
188       const Expr *probArg = e->getArg(2);
189       [[maybe_unused]] bool evalSucceeded =
190           probArg->EvaluateAsFloat(probability, cgm.getASTContext());
191       assert(evalSucceeded &&
192              "probability should be able to evaluate as float");
193       bool loseInfo = false; // ignored
194       probability.convert(llvm::APFloat::IEEEdouble(),
195                           llvm::RoundingMode::Dynamic, &loseInfo);
196       probAttr = mlir::FloatAttr::get(mlir::Float64Type::get(&getMLIRContext()),
197                                       probability);
198     }
199 
200     auto result = builder.create<cir::ExpectOp>(
201         loc, argValue.getType(), argValue, expectedValue, probAttr);
202     return RValue::get(result);
203   }
204 
205   case Builtin::BI__builtin_bswap16:
206   case Builtin::BI__builtin_bswap32:
207   case Builtin::BI__builtin_bswap64:
208   case Builtin::BI_byteswap_ushort:
209   case Builtin::BI_byteswap_ulong:
210   case Builtin::BI_byteswap_uint64: {
211     mlir::Value arg = emitScalarExpr(e->getArg(0));
212     return RValue::get(builder.create<cir::ByteSwapOp>(loc, arg));
213   }
214 
215   case Builtin::BI__builtin_bitreverse8:
216   case Builtin::BI__builtin_bitreverse16:
217   case Builtin::BI__builtin_bitreverse32:
218   case Builtin::BI__builtin_bitreverse64: {
219     mlir::Value arg = emitScalarExpr(e->getArg(0));
220     return RValue::get(builder.create<cir::BitReverseOp>(loc, arg));
221   }
222   }
223 
224   // If this is an alias for a lib function (e.g. __builtin_sin), emit
225   // the call using the normal call path, but using the unmangled
226   // version of the function name.
227   if (getContext().BuiltinInfo.isLibFunction(builtinID))
228     return emitLibraryCall(*this, fd, e,
229                            cgm.getBuiltinLibFunction(fd, builtinID));
230 
231   cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call");
232   return getUndefRValue(e->getType());
233 }
234 
235 /// Given a builtin id for a function like "__builtin_fabsf", return a Function*
236 /// for "fabsf".
getBuiltinLibFunction(const FunctionDecl * fd,unsigned builtinID)237 cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,
238                                                 unsigned builtinID) {
239   assert(astContext.BuiltinInfo.isLibFunction(builtinID));
240 
241   // Get the name, skip over the __builtin_ prefix (if necessary). We may have
242   // to build this up so provide a small stack buffer to handle the vast
243   // majority of names.
244   llvm::SmallString<64> name;
245 
246   assert(!cir::MissingFeatures::asmLabelAttr());
247   name = astContext.BuiltinInfo.getName(builtinID).substr(10);
248 
249   GlobalDecl d(fd);
250   mlir::Type type = convertType(fd->getType());
251   return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false);
252 }
253 
emitCheckedArgForAssume(const Expr * e)254 mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) {
255   mlir::Value argValue = evaluateExprAsBool(e);
256   if (!sanOpts.has(SanitizerKind::Builtin))
257     return argValue;
258 
259   assert(!cir::MissingFeatures::sanitizers());
260   cgm.errorNYI(e->getSourceRange(),
261                "emitCheckedArgForAssume: sanitizers are NYI");
262   return {};
263 }
264