Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
213799 views
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
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>
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
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".
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
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
265