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