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/CIRGenBuilder.h
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
#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
10
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
11
12
#include "Address.h"
13
#include "CIRGenRecordLayout.h"
14
#include "CIRGenTypeCache.h"
15
#include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
16
#include "clang/CIR/MissingFeatures.h"
17
18
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
19
#include "clang/CIR/MissingFeatures.h"
20
#include "llvm/ADT/APFloat.h"
21
#include "llvm/ADT/STLExtras.h"
22
23
namespace clang::CIRGen {
24
25
class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
26
const CIRGenTypeCache &typeCache;
27
llvm::StringMap<unsigned> recordNames;
28
llvm::StringMap<unsigned> globalsVersioning;
29
30
public:
31
CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc)
32
: CIRBaseBuilderTy(mlirContext), typeCache(tc) {}
33
34
/// Get a cir::ConstArrayAttr for a string literal.
35
/// Note: This is different from what is returned by
36
/// mlir::Builder::getStringAttr() which is an mlir::StringAttr.
37
mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy,
38
std::optional<size_t> size) {
39
size_t finalSize = size.value_or(str.size());
40
41
size_t lastNonZeroPos = str.find_last_not_of('\0');
42
// If the string is full of null bytes, emit a #cir.zero rather than
43
// a #cir.const_array.
44
if (lastNonZeroPos == llvm::StringRef::npos) {
45
auto arrayTy = cir::ArrayType::get(eltTy, finalSize);
46
return cir::ZeroAttr::get(arrayTy);
47
}
48
// We emit trailing zeros only if there are multiple trailing zeros.
49
size_t trailingZerosNum = 0;
50
if (finalSize > lastNonZeroPos + 2)
51
trailingZerosNum = finalSize - lastNonZeroPos - 1;
52
auto truncatedArrayTy =
53
cir::ArrayType::get(eltTy, finalSize - trailingZerosNum);
54
auto fullArrayTy = cir::ArrayType::get(eltTy, finalSize);
55
return cir::ConstArrayAttr::get(
56
fullArrayTy,
57
mlir::StringAttr::get(str.drop_back(trailingZerosNum),
58
truncatedArrayTy),
59
trailingZerosNum);
60
}
61
62
std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
63
64
std::string getUniqueRecordName(const std::string &baseName) {
65
auto it = recordNames.find(baseName);
66
if (it == recordNames.end()) {
67
recordNames[baseName] = 0;
68
return baseName;
69
}
70
71
return baseName + "." + std::to_string(recordNames[baseName]++);
72
}
73
74
cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
75
if (&format == &llvm::APFloat::IEEEdouble())
76
return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy);
77
if (&format == &llvm::APFloat::x87DoubleExtended())
78
return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty);
79
if (&format == &llvm::APFloat::IEEEquad())
80
return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty);
81
if (&format == &llvm::APFloat::PPCDoubleDouble())
82
llvm_unreachable("NYI: PPC double-double format for long double");
83
llvm_unreachable("Unsupported format for long double");
84
}
85
86
/// Get a CIR record kind from a AST declaration tag.
87
cir::RecordType::RecordKind getRecordKind(const clang::TagTypeKind kind) {
88
switch (kind) {
89
case clang::TagTypeKind::Class:
90
return cir::RecordType::Class;
91
case clang::TagTypeKind::Struct:
92
return cir::RecordType::Struct;
93
case clang::TagTypeKind::Union:
94
return cir::RecordType::Union;
95
case clang::TagTypeKind::Interface:
96
llvm_unreachable("interface records are NYI");
97
case clang::TagTypeKind::Enum:
98
llvm_unreachable("enums are not records");
99
}
100
llvm_unreachable("Unsupported record kind");
101
}
102
103
/// Get a CIR named record type.
104
///
105
/// If a record already exists and is complete, but the client tries to fetch
106
/// it with a different set of attributes, this method will crash.
107
cir::RecordType getCompleteRecordTy(llvm::ArrayRef<mlir::Type> members,
108
llvm::StringRef name, bool packed,
109
bool padded) {
110
const auto nameAttr = getStringAttr(name);
111
auto kind = cir::RecordType::RecordKind::Struct;
112
assert(!cir::MissingFeatures::astRecordDeclAttr());
113
114
// Create or get the record.
115
auto type =
116
getType<cir::RecordType>(members, nameAttr, packed, padded, kind);
117
118
// If we found an existing type, verify that either it is incomplete or
119
// it matches the requested attributes.
120
assert(!type.isIncomplete() ||
121
(type.getMembers() == members && type.getPacked() == packed &&
122
type.getPadded() == padded));
123
124
// Complete an incomplete record or ensure the existing complete record
125
// matches the requested attributes.
126
type.complete(members, packed, padded);
127
128
return type;
129
}
130
131
/// Get an incomplete CIR struct type. If we have a complete record
132
/// declaration, we may create an incomplete type and then add the
133
/// members, so \p rd here may be complete.
134
cir::RecordType getIncompleteRecordTy(llvm::StringRef name,
135
const clang::RecordDecl *rd) {
136
const mlir::StringAttr nameAttr = getStringAttr(name);
137
cir::RecordType::RecordKind kind = cir::RecordType::RecordKind::Struct;
138
if (rd)
139
kind = getRecordKind(rd->getTagKind());
140
return getType<cir::RecordType>(nameAttr, kind);
141
}
142
143
// Return true if the value is a null constant such as null pointer, (+0.0)
144
// for floating-point or zero initializer
145
bool isNullValue(mlir::Attribute attr) const {
146
if (mlir::isa<cir::ZeroAttr>(attr))
147
return true;
148
149
if (const auto ptrVal = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
150
return ptrVal.isNullValue();
151
152
if (const auto intVal = mlir::dyn_cast<cir::IntAttr>(attr))
153
return intVal.isNullValue();
154
155
if (const auto boolVal = mlir::dyn_cast<cir::BoolAttr>(attr))
156
return !boolVal.getValue();
157
158
if (auto fpAttr = mlir::dyn_cast<cir::FPAttr>(attr)) {
159
auto fpVal = fpAttr.getValue();
160
bool ignored;
161
llvm::APFloat fv(+0.0);
162
fv.convert(fpVal.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
163
&ignored);
164
return fv.bitwiseIsEqual(fpVal);
165
}
166
167
if (const auto arrayVal = mlir::dyn_cast<cir::ConstArrayAttr>(attr)) {
168
if (mlir::isa<mlir::StringAttr>(arrayVal.getElts()))
169
return false;
170
171
return llvm::all_of(
172
mlir::cast<mlir::ArrayAttr>(arrayVal.getElts()),
173
[&](const mlir::Attribute &elt) { return isNullValue(elt); });
174
}
175
return false;
176
}
177
178
//
179
// Type helpers
180
// ------------
181
//
182
cir::IntType getUIntNTy(int n) {
183
switch (n) {
184
case 8:
185
return getUInt8Ty();
186
case 16:
187
return getUInt16Ty();
188
case 32:
189
return getUInt32Ty();
190
case 64:
191
return getUInt64Ty();
192
default:
193
return cir::IntType::get(getContext(), n, false);
194
}
195
}
196
197
cir::IntType getSIntNTy(int n) {
198
switch (n) {
199
case 8:
200
return getSInt8Ty();
201
case 16:
202
return getSInt16Ty();
203
case 32:
204
return getSInt32Ty();
205
case 64:
206
return getSInt64Ty();
207
default:
208
return cir::IntType::get(getContext(), n, true);
209
}
210
}
211
212
cir::VoidType getVoidTy() { return typeCache.VoidTy; }
213
214
cir::IntType getSInt8Ty() { return typeCache.SInt8Ty; }
215
cir::IntType getSInt16Ty() { return typeCache.SInt16Ty; }
216
cir::IntType getSInt32Ty() { return typeCache.SInt32Ty; }
217
cir::IntType getSInt64Ty() { return typeCache.SInt64Ty; }
218
219
cir::IntType getUInt8Ty() { return typeCache.UInt8Ty; }
220
cir::IntType getUInt16Ty() { return typeCache.UInt16Ty; }
221
cir::IntType getUInt32Ty() { return typeCache.UInt32Ty; }
222
cir::IntType getUInt64Ty() { return typeCache.UInt64Ty; }
223
224
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal);
225
226
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APInt intVal);
227
228
cir::ConstantOp getConstInt(mlir::Location loc, mlir::Type t, uint64_t c);
229
230
cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t,
231
llvm::APFloat fpVal);
232
233
bool isInt8Ty(mlir::Type i) {
234
return i == typeCache.UInt8Ty || i == typeCache.SInt8Ty;
235
}
236
bool isInt16Ty(mlir::Type i) {
237
return i == typeCache.UInt16Ty || i == typeCache.SInt16Ty;
238
}
239
bool isInt32Ty(mlir::Type i) {
240
return i == typeCache.UInt32Ty || i == typeCache.SInt32Ty;
241
}
242
bool isInt64Ty(mlir::Type i) {
243
return i == typeCache.UInt64Ty || i == typeCache.SInt64Ty;
244
}
245
bool isInt(mlir::Type i) { return mlir::isa<cir::IntType>(i); }
246
247
//
248
// Constant creation helpers
249
// -------------------------
250
//
251
cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) {
252
return getConstantInt(loc, getSInt32Ty(), c);
253
}
254
255
// Creates constant nullptr for pointer type ty.
256
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc) {
257
assert(!cir::MissingFeatures::targetCodeGenInfoGetNullPointer());
258
return create<cir::ConstantOp>(loc, getConstPtrAttr(ty, 0));
259
}
260
261
mlir::Value createNeg(mlir::Value value) {
262
263
if (auto intTy = mlir::dyn_cast<cir::IntType>(value.getType())) {
264
// Source is a unsigned integer: first cast it to signed.
265
if (intTy.isUnsigned())
266
value = createIntCast(value, getSIntNTy(intTy.getWidth()));
267
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
268
cir::UnaryOpKind::Minus, value);
269
}
270
271
llvm_unreachable("negation for the given type is NYI");
272
}
273
274
// TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
275
// operations.
276
mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
277
assert(!cir::MissingFeatures::fpConstraints());
278
279
return create<cir::CastOp>(v.getLoc(), destType, cir::CastKind::floating,
280
v);
281
}
282
283
mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
284
assert(!cir::MissingFeatures::metaDataNode());
285
assert(!cir::MissingFeatures::fpConstraints());
286
assert(!cir::MissingFeatures::fastMathFlags());
287
288
return create<cir::BinOp>(loc, cir::BinOpKind::Sub, lhs, rhs);
289
}
290
291
mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
292
assert(!cir::MissingFeatures::metaDataNode());
293
assert(!cir::MissingFeatures::fpConstraints());
294
assert(!cir::MissingFeatures::fastMathFlags());
295
296
return create<cir::BinOp>(loc, cir::BinOpKind::Add, lhs, rhs);
297
}
298
mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
299
assert(!cir::MissingFeatures::metaDataNode());
300
assert(!cir::MissingFeatures::fpConstraints());
301
assert(!cir::MissingFeatures::fastMathFlags());
302
303
return create<cir::BinOp>(loc, cir::BinOpKind::Mul, lhs, rhs);
304
}
305
mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
306
assert(!cir::MissingFeatures::metaDataNode());
307
assert(!cir::MissingFeatures::fpConstraints());
308
assert(!cir::MissingFeatures::fastMathFlags());
309
310
return create<cir::BinOp>(loc, cir::BinOpKind::Div, lhs, rhs);
311
}
312
313
Address createBaseClassAddr(mlir::Location loc, Address addr,
314
mlir::Type destType, unsigned offset,
315
bool assumeNotNull) {
316
if (destType == addr.getElementType())
317
return addr;
318
319
auto ptrTy = getPointerTo(destType);
320
auto baseAddr = create<cir::BaseClassAddrOp>(
321
loc, ptrTy, addr.getPointer(), mlir::APInt(64, offset), assumeNotNull);
322
return Address(baseAddr, destType, addr.getAlignment());
323
}
324
325
/// Cast the element type of the given address to a different type,
326
/// preserving information like the alignment.
327
Address createElementBitCast(mlir::Location loc, Address addr,
328
mlir::Type destType) {
329
if (destType == addr.getElementType())
330
return addr;
331
332
auto ptrTy = getPointerTo(destType);
333
return Address(createBitcast(loc, addr.getPointer(), ptrTy), destType,
334
addr.getAlignment());
335
}
336
337
cir::LoadOp createLoad(mlir::Location loc, Address addr,
338
bool isVolatile = false) {
339
mlir::IntegerAttr align = getAlignmentAttr(addr.getAlignment());
340
return create<cir::LoadOp>(loc, addr.getPointer(), /*isDeref=*/false,
341
align);
342
}
343
344
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst,
345
mlir::IntegerAttr align = {}) {
346
if (!align)
347
align = getAlignmentAttr(dst.getAlignment());
348
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);
349
}
350
351
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
352
mlir::Value imag) {
353
auto resultComplexTy = cir::ComplexType::get(real.getType());
354
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
355
}
356
357
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
358
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
359
return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
360
}
361
362
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
363
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
364
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
365
}
366
367
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
368
/// part of the complex value pointed to by the specified pointer value.
369
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
370
auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
371
auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
372
return create<cir::ComplexRealPtrOp>(
373
loc, getPointerTo(srcComplexTy.getElementType()), value);
374
}
375
376
Address createComplexRealPtr(mlir::Location loc, Address addr) {
377
return Address{createComplexRealPtr(loc, addr.getPointer()),
378
addr.getAlignment()};
379
}
380
381
/// Create a cir.complex.imag_ptr operation that derives a pointer to the
382
/// imaginary part of the complex value pointed to by the specified pointer
383
/// value.
384
mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) {
385
auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType());
386
auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
387
return create<cir::ComplexImagPtrOp>(
388
loc, getPointerTo(srcComplexTy.getElementType()), value);
389
}
390
391
Address createComplexImagPtr(mlir::Location loc, Address addr) {
392
return Address{createComplexImagPtr(loc, addr.getPointer()),
393
addr.getAlignment()};
394
}
395
396
/// Create a cir.ptr_stride operation to get access to an array element.
397
/// \p idx is the index of the element to access, \p shouldDecay is true if
398
/// the result should decay to a pointer to the element type.
399
mlir::Value getArrayElement(mlir::Location arrayLocBegin,
400
mlir::Location arrayLocEnd, mlir::Value arrayPtr,
401
mlir::Type eltTy, mlir::Value idx,
402
bool shouldDecay);
403
404
/// Returns a decayed pointer to the first element of the array
405
/// pointed to by \p arrayPtr.
406
mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr,
407
mlir::Type eltTy);
408
409
/// Creates a versioned global variable. If the symbol is already taken, an ID
410
/// will be appended to the symbol. The returned global must always be queried
411
/// for its name so it can be referenced correctly.
412
[[nodiscard]] cir::GlobalOp
413
createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc,
414
mlir::StringRef name, mlir::Type type,
415
cir::GlobalLinkageKind linkage) {
416
// Create a unique name if the given name is already taken.
417
std::string uniqueName;
418
if (unsigned version = globalsVersioning[name.str()]++)
419
uniqueName = name.str() + "." + std::to_string(version);
420
else
421
uniqueName = name.str();
422
423
return createGlobal(module, loc, uniqueName, type, linkage);
424
}
425
426
mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
427
mlir::Value dstAddr, mlir::Type storageType,
428
mlir::Value src, const CIRGenBitFieldInfo &info,
429
bool isLvalueVolatile, bool useVolatile) {
430
return create<cir::SetBitfieldOp>(loc, resultType, dstAddr, storageType,
431
src, info.name, info.size, info.offset,
432
info.isSigned, isLvalueVolatile);
433
}
434
435
mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
436
mlir::Value addr, mlir::Type storageType,
437
const CIRGenBitFieldInfo &info,
438
bool isLvalueVolatile, bool useVolatile) {
439
return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType,
440
info.name, info.size, info.offset,
441
info.isSigned, isLvalueVolatile);
442
}
443
};
444
445
} // namespace clang::CIRGen
446
447
#endif
448
449