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

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