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
23namespace clang::CIRGen {
24
25class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
26 const CIRGenTypeCache &typeCache;
27 llvm::StringMap<unsigned> recordNames;
28 llvm::StringMap<unsigned> globalsVersioning;
29
30public:
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(u: str.size());
40
41 size_t lastNonZeroPos = str.find_last_not_of(C: '\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(baseName: "anon"); }
63
64 std::string getUniqueRecordName(const std::string &baseName) {
65 auto it = recordNames.find(Key: baseName);
66 if (it == recordNames.end()) {
67 recordNames[baseName] = 0;
68 return baseName;
69 }
70
71 return baseName + "." + std::to_string(val: 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(ToSemantics: fpVal.getSemantics(), RM: llvm::APFloat::rmNearestTiesToEven,
163 losesInfo: &ignored);
164 return fv.bitwiseIsEqual(RHS: 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(val: 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

source code of clang/lib/CIR/CodeGen/CIRGenBuilder.h