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 // Internal per-function state used for AST-to-ClangIR code gen 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H 14 #define CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H 15 16 #include "CIRGenBuilder.h" 17 #include "CIRGenCall.h" 18 #include "CIRGenModule.h" 19 #include "CIRGenTypeCache.h" 20 #include "CIRGenValue.h" 21 22 #include "Address.h" 23 24 #include "clang/AST/ASTContext.h" 25 #include "clang/AST/CharUnits.h" 26 #include "clang/AST/Decl.h" 27 #include "clang/AST/Stmt.h" 28 #include "clang/AST/Type.h" 29 #include "clang/CIR/Dialect/IR/CIRDialect.h" 30 #include "clang/CIR/MissingFeatures.h" 31 #include "clang/CIR/TypeEvaluationKind.h" 32 33 namespace { 34 class ScalarExprEmitter; 35 } // namespace 36 37 namespace mlir { 38 namespace acc { 39 class LoopOp; 40 } // namespace acc 41 } // namespace mlir 42 43 namespace clang::CIRGen { 44 45 class CIRGenFunction : public CIRGenTypeCache { 46 public: 47 CIRGenModule &cgm; 48 49 private: 50 friend class ::ScalarExprEmitter; 51 /// The builder is a helper class to create IR inside a function. The 52 /// builder is stateful, in particular it keeps an "insertion point": this 53 /// is where the next operations will be introduced. 54 CIRGenBuilderTy &builder; 55 56 public: 57 /// The GlobalDecl for the current function being compiled or the global 58 /// variable currently being initialized. 59 clang::GlobalDecl curGD; 60 61 /// The compiler-generated variable that holds the return value. 62 std::optional<mlir::Value> fnRetAlloca; 63 64 /// CXXThisDecl - When generating code for a C++ member function, 65 /// this will hold the implicit 'this' declaration. 66 ImplicitParamDecl *cxxabiThisDecl = nullptr; 67 mlir::Value cxxabiThisValue = nullptr; 68 mlir::Value cxxThisValue = nullptr; 69 clang::CharUnits cxxThisAlignment; 70 71 /// The value of 'this' to sue when evaluating CXXDefaultInitExprs within this 72 /// expression. 73 Address cxxDefaultInitExprThis = Address::invalid(); 74 75 // Holds the Decl for the current outermost non-closure context 76 const clang::Decl *curFuncDecl = nullptr; 77 78 /// The function for which code is currently being generated. 79 cir::FuncOp curFn; 80 81 using DeclMapTy = llvm::DenseMap<const clang::Decl *, Address>; 82 /// This keeps track of the CIR allocas or globals for local C 83 /// declarations. 84 DeclMapTy localDeclMap; 85 86 /// The type of the condition for the emitting switch statement. 87 llvm::SmallVector<mlir::Type, 2> condTypeStack; 88 getContext()89 clang::ASTContext &getContext() const { return cgm.getASTContext(); } 90 getBuilder()91 CIRGenBuilderTy &getBuilder() { return builder; } 92 getCIRGenModule()93 CIRGenModule &getCIRGenModule() { return cgm; } getCIRGenModule()94 const CIRGenModule &getCIRGenModule() const { return cgm; } 95 getCurFunctionEntryBlock()96 mlir::Block *getCurFunctionEntryBlock() { return &curFn.getRegion().front(); } 97 98 /// Sanitizers enabled for this function. 99 clang::SanitizerSet sanOpts; 100 101 /// Whether or not a Microsoft-style asm block has been processed within 102 /// this fuction. These can potentially set the return value. 103 bool sawAsmBlock = false; 104 105 mlir::Type convertTypeForMem(QualType t); 106 107 mlir::Type convertType(clang::QualType t); convertType(const TypeDecl * t)108 mlir::Type convertType(const TypeDecl *t) { 109 return convertType(getContext().getTypeDeclType(t)); 110 } 111 112 /// Return the cir::TypeEvaluationKind of QualType \c type. 113 static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type); 114 hasScalarEvaluationKind(clang::QualType type)115 static bool hasScalarEvaluationKind(clang::QualType type) { 116 return getEvaluationKind(type) == cir::TEK_Scalar; 117 } 118 hasAggregateEvaluationKind(clang::QualType type)119 static bool hasAggregateEvaluationKind(clang::QualType type) { 120 return getEvaluationKind(type) == cir::TEK_Aggregate; 121 } 122 123 CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, 124 bool suppressNewContext = false); 125 ~CIRGenFunction(); 126 getTypes()127 CIRGenTypes &getTypes() const { return cgm.getTypes(); } 128 getTarget()129 const TargetInfo &getTarget() const { return cgm.getTarget(); } getMLIRContext()130 mlir::MLIRContext &getMLIRContext() { return cgm.getMLIRContext(); } 131 132 // --------------------- 133 // Opaque value handling 134 // --------------------- 135 136 /// Keeps track of the current set of opaque value expressions. 137 llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues; 138 llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues; 139 140 public: 141 /// A non-RAII class containing all the information about a bound 142 /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for 143 /// this which makes individual mappings very simple; using this 144 /// class directly is useful when you have a variable number of 145 /// opaque values or don't want the RAII functionality for some 146 /// reason. 147 class OpaqueValueMappingData { 148 const OpaqueValueExpr *opaqueValue; 149 bool boundLValue; 150 OpaqueValueMappingData(const OpaqueValueExpr * ov,bool boundLValue)151 OpaqueValueMappingData(const OpaqueValueExpr *ov, bool boundLValue) 152 : opaqueValue(ov), boundLValue(boundLValue) {} 153 154 public: OpaqueValueMappingData()155 OpaqueValueMappingData() : opaqueValue(nullptr) {} 156 shouldBindAsLValue(const Expr * expr)157 static bool shouldBindAsLValue(const Expr *expr) { 158 // gl-values should be bound as l-values for obvious reasons. 159 // Records should be bound as l-values because IR generation 160 // always keeps them in memory. Expressions of function type 161 // act exactly like l-values but are formally required to be 162 // r-values in C. 163 return expr->isGLValue() || expr->getType()->isFunctionType() || 164 hasAggregateEvaluationKind(expr->getType()); 165 } 166 167 static OpaqueValueMappingData bind(CIRGenFunction & cgf,const OpaqueValueExpr * ov,const Expr * e)168 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const Expr *e) { 169 if (shouldBindAsLValue(ov)) 170 return bind(cgf, ov, cgf.emitLValue(e)); 171 return bind(cgf, ov, cgf.emitAnyExpr(e)); 172 } 173 174 static OpaqueValueMappingData bind(CIRGenFunction & cgf,const OpaqueValueExpr * ov,const LValue & lv)175 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const LValue &lv) { 176 assert(shouldBindAsLValue(ov)); 177 cgf.opaqueLValues.insert(std::make_pair(ov, lv)); 178 return OpaqueValueMappingData(ov, true); 179 } 180 181 static OpaqueValueMappingData bind(CIRGenFunction & cgf,const OpaqueValueExpr * ov,const RValue & rv)182 bind(CIRGenFunction &cgf, const OpaqueValueExpr *ov, const RValue &rv) { 183 assert(!shouldBindAsLValue(ov)); 184 cgf.opaqueRValues.insert(std::make_pair(ov, rv)); 185 186 OpaqueValueMappingData data(ov, false); 187 188 // Work around an extremely aggressive peephole optimization in 189 // EmitScalarConversion which assumes that all other uses of a 190 // value are extant. 191 assert(!cir::MissingFeatures::peepholeProtection() && "NYI"); 192 return data; 193 } 194 isValid()195 bool isValid() const { return opaqueValue != nullptr; } clear()196 void clear() { opaqueValue = nullptr; } 197 unbind(CIRGenFunction & cgf)198 void unbind(CIRGenFunction &cgf) { 199 assert(opaqueValue && "no data to unbind!"); 200 201 if (boundLValue) { 202 cgf.opaqueLValues.erase(opaqueValue); 203 } else { 204 cgf.opaqueRValues.erase(opaqueValue); 205 assert(!cir::MissingFeatures::peepholeProtection() && "NYI"); 206 } 207 } 208 }; 209 210 /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr. 211 class OpaqueValueMapping { 212 CIRGenFunction &cgf; 213 OpaqueValueMappingData data; 214 215 public: shouldBindAsLValue(const Expr * expr)216 static bool shouldBindAsLValue(const Expr *expr) { 217 return OpaqueValueMappingData::shouldBindAsLValue(expr); 218 } 219 220 /// Build the opaque value mapping for the given conditional 221 /// operator if it's the GNU ?: extension. This is a common 222 /// enough pattern that the convenience operator is really 223 /// helpful. 224 /// OpaqueValueMapping(CIRGenFunction & cgf,const AbstractConditionalOperator * op)225 OpaqueValueMapping(CIRGenFunction &cgf, 226 const AbstractConditionalOperator *op) 227 : cgf(cgf) { 228 if (mlir::isa<ConditionalOperator>(op)) 229 // Leave Data empty. 230 return; 231 232 const BinaryConditionalOperator *e = 233 mlir::cast<BinaryConditionalOperator>(op); 234 data = OpaqueValueMappingData::bind(cgf, e->getOpaqueValue(), 235 e->getCommon()); 236 } 237 238 /// Build the opaque value mapping for an OpaqueValueExpr whose source 239 /// expression is set to the expression the OVE represents. OpaqueValueMapping(CIRGenFunction & cgf,const OpaqueValueExpr * ov)240 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *ov) 241 : cgf(cgf) { 242 if (ov) { 243 assert(ov->getSourceExpr() && "wrong form of OpaqueValueMapping used " 244 "for OVE with no source expression"); 245 data = OpaqueValueMappingData::bind(cgf, ov, ov->getSourceExpr()); 246 } 247 } 248 OpaqueValueMapping(CIRGenFunction & cgf,const OpaqueValueExpr * opaqueValue,LValue lvalue)249 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue, 250 LValue lvalue) 251 : cgf(cgf), 252 data(OpaqueValueMappingData::bind(cgf, opaqueValue, lvalue)) {} 253 OpaqueValueMapping(CIRGenFunction & cgf,const OpaqueValueExpr * opaqueValue,RValue rvalue)254 OpaqueValueMapping(CIRGenFunction &cgf, const OpaqueValueExpr *opaqueValue, 255 RValue rvalue) 256 : cgf(cgf), 257 data(OpaqueValueMappingData::bind(cgf, opaqueValue, rvalue)) {} 258 pop()259 void pop() { 260 data.unbind(cgf); 261 data.clear(); 262 } 263 ~OpaqueValueMapping()264 ~OpaqueValueMapping() { 265 if (data.isValid()) 266 data.unbind(cgf); 267 } 268 }; 269 270 private: 271 /// Declare a variable in the current scope, return success if the variable 272 /// wasn't declared yet. 273 void declare(mlir::Value addrVal, const clang::Decl *var, clang::QualType ty, 274 mlir::Location loc, clang::CharUnits alignment, 275 bool isParam = false); 276 277 public: 278 mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt); 279 280 void emitNullInitialization(mlir::Location loc, Address destPtr, QualType ty); 281 282 private: 283 // Track current variable initialization (if there's one) 284 const clang::VarDecl *currVarDecl = nullptr; 285 class VarDeclContext { 286 CIRGenFunction &p; 287 const clang::VarDecl *oldVal = nullptr; 288 289 public: VarDeclContext(CIRGenFunction & p,const VarDecl * value)290 VarDeclContext(CIRGenFunction &p, const VarDecl *value) : p(p) { 291 if (p.currVarDecl) 292 oldVal = p.currVarDecl; 293 p.currVarDecl = value; 294 } 295 296 /// Can be used to restore the state early, before the dtor 297 /// is run. restore()298 void restore() { p.currVarDecl = oldVal; } ~VarDeclContext()299 ~VarDeclContext() { restore(); } 300 }; 301 302 public: 303 /// Use to track source locations across nested visitor traversals. 304 /// Always use a `SourceLocRAIIObject` to change currSrcLoc. 305 std::optional<mlir::Location> currSrcLoc; 306 class SourceLocRAIIObject { 307 CIRGenFunction &cgf; 308 std::optional<mlir::Location> oldLoc; 309 310 public: SourceLocRAIIObject(CIRGenFunction & cgf,mlir::Location value)311 SourceLocRAIIObject(CIRGenFunction &cgf, mlir::Location value) : cgf(cgf) { 312 if (cgf.currSrcLoc) 313 oldLoc = cgf.currSrcLoc; 314 cgf.currSrcLoc = value; 315 } 316 317 /// Can be used to restore the state early, before the dtor 318 /// is run. restore()319 void restore() { cgf.currSrcLoc = oldLoc; } ~SourceLocRAIIObject()320 ~SourceLocRAIIObject() { restore(); } 321 }; 322 323 /// Hold counters for incrementally naming temporaries 324 unsigned counterAggTmp = 0; 325 std::string getCounterAggTmpAsString(); 326 327 /// Helpers to convert Clang's SourceLocation to a MLIR Location. 328 mlir::Location getLoc(clang::SourceLocation srcLoc); 329 mlir::Location getLoc(clang::SourceRange srcLoc); 330 mlir::Location getLoc(mlir::Location lhs, mlir::Location rhs); 331 getLangOpts()332 const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); } 333 334 // Wrapper for function prototype sources. Wraps either a FunctionProtoType or 335 // an ObjCMethodDecl. 336 struct PrototypeWrapper { 337 llvm::PointerUnion<const clang::FunctionProtoType *, 338 const clang::ObjCMethodDecl *> 339 p; 340 PrototypeWrapperPrototypeWrapper341 PrototypeWrapper(const clang::FunctionProtoType *ft) : p(ft) {} PrototypeWrapperPrototypeWrapper342 PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {} 343 }; 344 345 bool isLValueSuitableForInlineAtomic(LValue lv); 346 347 /// An abstract representation of regular/ObjC call/message targets. 348 class AbstractCallee { 349 /// The function declaration of the callee. 350 [[maybe_unused]] const clang::Decl *calleeDecl; 351 352 public: AbstractCallee()353 AbstractCallee() : calleeDecl(nullptr) {} AbstractCallee(const clang::FunctionDecl * fd)354 AbstractCallee(const clang::FunctionDecl *fd) : calleeDecl(fd) {} 355 hasFunctionDecl()356 bool hasFunctionDecl() const { 357 return llvm::isa_and_nonnull<clang::FunctionDecl>(calleeDecl); 358 } 359 getNumParams()360 unsigned getNumParams() const { 361 if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl)) 362 return fd->getNumParams(); 363 return llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_size(); 364 } 365 getParamDecl(unsigned I)366 const clang::ParmVarDecl *getParamDecl(unsigned I) const { 367 if (const auto *fd = llvm::dyn_cast<clang::FunctionDecl>(calleeDecl)) 368 return fd->getParamDecl(I); 369 return *(llvm::cast<clang::ObjCMethodDecl>(calleeDecl)->param_begin() + 370 I); 371 } 372 }; 373 374 void finishFunction(SourceLocation endLoc); 375 376 /// Determine whether the given initializer is trivial in the sense 377 /// that it requires no code to be generated. 378 bool isTrivialInitializer(const Expr *init); 379 380 /// If the specified expression does not fold to a constant, or if it does but 381 /// contains a label, return false. If it constant folds return true and set 382 /// the boolean result in Result. 383 bool constantFoldsToBool(const clang::Expr *cond, bool &resultBool, 384 bool allowLabels = false); 385 bool constantFoldsToSimpleInteger(const clang::Expr *cond, 386 llvm::APSInt &resultInt, 387 bool allowLabels = false); 388 389 /// Return true if the statement contains a label in it. If 390 /// this statement is not executed normally, it not containing a label means 391 /// that we can just remove the code. 392 bool containsLabel(const clang::Stmt *s, bool ignoreCaseStmts = false); 393 394 class ConstantEmission { 395 // Cannot use mlir::TypedAttr directly here because of bit availability. 396 llvm::PointerIntPair<mlir::Attribute, 1, bool> valueAndIsReference; ConstantEmission(mlir::TypedAttr c,bool isReference)397 ConstantEmission(mlir::TypedAttr c, bool isReference) 398 : valueAndIsReference(c, isReference) {} 399 400 public: ConstantEmission()401 ConstantEmission() {} forReference(mlir::TypedAttr c)402 static ConstantEmission forReference(mlir::TypedAttr c) { 403 return ConstantEmission(c, true); 404 } forValue(mlir::TypedAttr c)405 static ConstantEmission forValue(mlir::TypedAttr c) { 406 return ConstantEmission(c, false); 407 } 408 409 explicit operator bool() const { 410 return valueAndIsReference.getOpaqueValue() != nullptr; 411 } 412 isReference()413 bool isReference() const { return valueAndIsReference.getInt(); } getReferenceLValue(CIRGenFunction & cgf,Expr * refExpr)414 LValue getReferenceLValue(CIRGenFunction &cgf, Expr *refExpr) const { 415 assert(isReference()); 416 cgf.cgm.errorNYI(refExpr->getSourceRange(), 417 "ConstantEmission::getReferenceLValue"); 418 return {}; 419 } 420 getValue()421 mlir::TypedAttr getValue() const { 422 assert(!isReference()); 423 return mlir::cast<mlir::TypedAttr>(valueAndIsReference.getPointer()); 424 } 425 }; 426 427 ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); 428 429 struct AutoVarEmission { 430 const clang::VarDecl *Variable; 431 /// The address of the alloca for languages with explicit address space 432 /// (e.g. OpenCL) or alloca casted to generic pointer for address space 433 /// agnostic languages (e.g. C++). Invalid if the variable was emitted 434 /// as a global constant. 435 Address Addr; 436 437 /// True if the variable is of aggregate type and has a constant 438 /// initializer. 439 bool IsConstantAggregate = false; 440 441 /// True if the variable is a __block variable that is captured by an 442 /// escaping block. 443 bool IsEscapingByRef = false; 444 445 mlir::Value NRVOFlag{}; 446 447 struct Invalid {}; AutoVarEmissionAutoVarEmission448 AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {} 449 AutoVarEmissionAutoVarEmission450 AutoVarEmission(const clang::VarDecl &variable) 451 : Variable(&variable), Addr(Address::invalid()) {} 452 invalidAutoVarEmission453 static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); } 454 wasEmittedAsGlobalAutoVarEmission455 bool wasEmittedAsGlobal() const { return !Addr.isValid(); } 456 457 /// Returns the raw, allocated address, which is not necessarily 458 /// the address of the object itself. It is casted to default 459 /// address space for address space agnostic languages. getAllocatedAddressAutoVarEmission460 Address getAllocatedAddress() const { return Addr; } 461 462 /// Returns the address of the object within this declaration. 463 /// Note that this does not chase the forwarding pointer for 464 /// __block decls. getObjectAddressAutoVarEmission465 Address getObjectAddress(CIRGenFunction &cgf) const { 466 if (!IsEscapingByRef) 467 return Addr; 468 469 assert(!cir::MissingFeatures::opAllocaEscapeByReference()); 470 return Address::invalid(); 471 } 472 }; 473 474 /// Perform the usual unary conversions on the specified expression and 475 /// compare the result against zero, returning an Int1Ty value. 476 mlir::Value evaluateExprAsBool(const clang::Expr *e); 477 478 cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d, 479 cir::GlobalOp gv, 480 cir::GetGlobalOp gvAddr); 481 482 /// Set the address of a local variable. setAddrOfLocalVar(const clang::VarDecl * vd,Address addr)483 void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) { 484 assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!"); 485 localDeclMap.insert({vd, addr}); 486 // TODO: Add symbol table support 487 } 488 489 bool shouldNullCheckClassCastValue(const CastExpr *ce); 490 491 RValue convertTempToRValue(Address addr, clang::QualType type, 492 clang::SourceLocation loc); 493 494 static bool 495 isConstructorDelegationValid(const clang::CXXConstructorDecl *ctor); 496 497 /// A scope within which we are constructing the fields of an object which 498 /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use if 499 /// we need to evaluate the CXXDefaultInitExpr within the evaluation. 500 class FieldConstructionScope { 501 public: FieldConstructionScope(CIRGenFunction & cgf,Address thisAddr)502 FieldConstructionScope(CIRGenFunction &cgf, Address thisAddr) 503 : cgf(cgf), oldCXXDefaultInitExprThis(cgf.cxxDefaultInitExprThis) { 504 cgf.cxxDefaultInitExprThis = thisAddr; 505 } ~FieldConstructionScope()506 ~FieldConstructionScope() { 507 cgf.cxxDefaultInitExprThis = oldCXXDefaultInitExprThis; 508 } 509 510 private: 511 CIRGenFunction &cgf; 512 Address oldCXXDefaultInitExprThis; 513 }; 514 515 LValue makeNaturalAlignPointeeAddrLValue(mlir::Value v, clang::QualType t); 516 LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty); 517 518 /// Construct an address with the natural alignment of T. If a pointer to T 519 /// is expected to be signed, the pointer passed to this function must have 520 /// been signed, and the returned Address will have the pointer authentication 521 /// information needed to authenticate the signed pointer. 522 Address makeNaturalAddressForPointer(mlir::Value ptr, QualType t, 523 CharUnits alignment, 524 bool forPointeeType = false, 525 LValueBaseInfo *baseInfo = nullptr) { 526 if (alignment.isZero()) 527 alignment = cgm.getNaturalTypeAlignment(t, baseInfo); 528 return Address(ptr, convertTypeForMem(t), alignment); 529 } 530 531 Address getAddressOfBaseClass( 532 Address value, const CXXRecordDecl *derived, 533 llvm::iterator_range<CastExpr::path_const_iterator> path, 534 bool nullCheckValue, SourceLocation loc); 535 536 LValue makeAddrLValue(Address addr, QualType ty, 537 AlignmentSource source = AlignmentSource::Type) { 538 return makeAddrLValue(addr, ty, LValueBaseInfo(source)); 539 } 540 makeAddrLValue(Address addr,QualType ty,LValueBaseInfo baseInfo)541 LValue makeAddrLValue(Address addr, QualType ty, LValueBaseInfo baseInfo) { 542 return LValue::makeAddr(addr, ty, baseInfo); 543 } 544 545 /// Return the address of a local variable. getAddrOfLocalVar(const clang::VarDecl * vd)546 Address getAddrOfLocalVar(const clang::VarDecl *vd) { 547 auto it = localDeclMap.find(vd); 548 assert(it != localDeclMap.end() && 549 "Invalid argument to getAddrOfLocalVar(), no decl!"); 550 return it->second; 551 } 552 553 Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field, 554 mlir::Type fieldType, unsigned index); 555 556 /// Load the value for 'this'. This function is only valid while generating 557 /// code for an C++ member function. 558 /// FIXME(cir): this should return a mlir::Value! loadCXXThis()559 mlir::Value loadCXXThis() { 560 assert(cxxThisValue && "no 'this' value for this function"); 561 return cxxThisValue; 562 } 563 Address loadCXXThisAddress(); 564 565 /// Convert the given pointer to a complete class to the given direct base. 566 Address getAddressOfDirectBaseInCompleteClass(mlir::Location loc, 567 Address value, 568 const CXXRecordDecl *derived, 569 const CXXRecordDecl *base, 570 bool baseIsVirtual); 571 572 /// Determine whether a base class initialization may overlap some other 573 /// object. 574 AggValueSlot::Overlap_t getOverlapForBaseInit(const CXXRecordDecl *rd, 575 const CXXRecordDecl *baseRD, 576 bool isVirtual); 577 578 /// Get an appropriate 'undef' rvalue for the given type. 579 /// TODO: What's the equivalent for MLIR? Currently we're only using this for 580 /// void types so it just returns RValue::get(nullptr) but it'll need 581 /// addressed later. 582 RValue getUndefRValue(clang::QualType ty); 583 584 cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn, 585 cir::FuncType funcType); 586 587 clang::QualType buildFunctionArgList(clang::GlobalDecl gd, 588 FunctionArgList &args); 589 590 /// Emit code for the start of a function. 591 /// \param loc The location to be associated with the function. 592 /// \param startLoc The location of the function body. 593 void startFunction(clang::GlobalDecl gd, clang::QualType returnType, 594 cir::FuncOp fn, cir::FuncType funcType, 595 FunctionArgList args, clang::SourceLocation loc, 596 clang::SourceLocation startLoc); 597 598 /// Represents a scope, including function bodies, compound statements, and 599 /// the substatements of if/while/do/for/switch/try statements. This class 600 /// handles any automatic cleanup, along with the return value. 601 struct LexicalScope { 602 private: 603 // TODO(CIR): This will live in the base class RunCleanupScope once that 604 // class is upstreamed. 605 CIRGenFunction &cgf; 606 607 // Points to the scope entry block. This is useful, for instance, for 608 // helping to insert allocas before finalizing any recursive CodeGen from 609 // switches. 610 mlir::Block *entryBlock; 611 612 LexicalScope *parentScope = nullptr; 613 614 // Only Regular is used at the moment. Support for other kinds will be 615 // added as the relevant statements/expressions are upstreamed. 616 enum Kind { 617 Regular, // cir.if, cir.scope, if_regions 618 Ternary, // cir.ternary 619 Switch, // cir.switch 620 Try, // cir.try 621 GlobalInit // cir.global initialization code 622 }; 623 Kind scopeKind = Kind::Regular; 624 625 // The scope return value. 626 mlir::Value retVal = nullptr; 627 628 mlir::Location beginLoc; 629 mlir::Location endLoc; 630 631 public: 632 unsigned depth = 0; 633 LexicalScopeLexicalScope634 LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb) 635 : cgf(cgf), entryBlock(eb), parentScope(cgf.curLexScope), beginLoc(loc), 636 endLoc(loc) { 637 638 assert(entryBlock && "LexicalScope requires an entry block"); 639 cgf.curLexScope = this; 640 if (parentScope) 641 ++depth; 642 643 if (const auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc)) { 644 assert(fusedLoc.getLocations().size() == 2 && "too many locations"); 645 beginLoc = fusedLoc.getLocations()[0]; 646 endLoc = fusedLoc.getLocations()[1]; 647 } 648 } 649 setRetValLexicalScope650 void setRetVal(mlir::Value v) { retVal = v; } 651 652 void cleanup(); restoreLexicalScope653 void restore() { cgf.curLexScope = parentScope; } 654 ~LexicalScopeLexicalScope655 ~LexicalScope() { 656 assert(!cir::MissingFeatures::generateDebugInfo()); 657 cleanup(); 658 restore(); 659 } 660 661 // --- 662 // Kind 663 // --- isGlobalInitLexicalScope664 bool isGlobalInit() { return scopeKind == Kind::GlobalInit; } isRegularLexicalScope665 bool isRegular() { return scopeKind == Kind::Regular; } isSwitchLexicalScope666 bool isSwitch() { return scopeKind == Kind::Switch; } isTernaryLexicalScope667 bool isTernary() { return scopeKind == Kind::Ternary; } isTryLexicalScope668 bool isTry() { return scopeKind == Kind::Try; } 669 setAsGlobalInitLexicalScope670 void setAsGlobalInit() { scopeKind = Kind::GlobalInit; } setAsSwitchLexicalScope671 void setAsSwitch() { scopeKind = Kind::Switch; } setAsTernaryLexicalScope672 void setAsTernary() { scopeKind = Kind::Ternary; } 673 674 // --- 675 // Return handling. 676 // --- 677 678 private: 679 // `returnBlock`, `returnLoc`, and all the functions that deal with them 680 // will change and become more complicated when `switch` statements are 681 // upstreamed. `case` statements within the `switch` are in the same scope 682 // but have their own regions. Therefore the LexicalScope will need to 683 // keep track of multiple return blocks. 684 mlir::Block *returnBlock = nullptr; 685 std::optional<mlir::Location> returnLoc; 686 687 // See the comment on `getOrCreateRetBlock`. createRetBlockLexicalScope688 mlir::Block *createRetBlock(CIRGenFunction &cgf, mlir::Location loc) { 689 assert(returnBlock == nullptr && "only one return block per scope"); 690 // Create the cleanup block but don't hook it up just yet. 691 mlir::OpBuilder::InsertionGuard guard(cgf.builder); 692 returnBlock = 693 cgf.builder.createBlock(cgf.builder.getBlock()->getParent()); 694 updateRetLoc(returnBlock, loc); 695 return returnBlock; 696 } 697 698 cir::ReturnOp emitReturn(mlir::Location loc); 699 void emitImplicitReturn(); 700 701 public: getRetBlockLexicalScope702 mlir::Block *getRetBlock() { return returnBlock; } getRetLocLexicalScope703 mlir::Location getRetLoc(mlir::Block *b) { return *returnLoc; } updateRetLocLexicalScope704 void updateRetLoc(mlir::Block *b, mlir::Location loc) { returnLoc = loc; } 705 706 // Create the return block for this scope, or return the existing one. 707 // This get-or-create logic is necessary to handle multiple return 708 // statements within the same scope, which can happen if some of them are 709 // dead code or if there is a `goto` into the middle of the scope. getOrCreateRetBlockLexicalScope710 mlir::Block *getOrCreateRetBlock(CIRGenFunction &cgf, mlir::Location loc) { 711 if (returnBlock == nullptr) { 712 returnBlock = createRetBlock(cgf, loc); 713 return returnBlock; 714 } 715 updateRetLoc(returnBlock, loc); 716 return returnBlock; 717 } 718 getEntryBlockLexicalScope719 mlir::Block *getEntryBlock() { return entryBlock; } 720 }; 721 722 LexicalScope *curLexScope = nullptr; 723 724 /// ---------------------- 725 /// CIR emit functions 726 /// ---------------------- 727 private: 728 void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc, 729 clang::CharUnits alignment); 730 731 CIRGenCallee emitDirectCallee(const GlobalDecl &gd); 732 733 public: 734 Address emitAddrOfFieldStorage(Address base, const FieldDecl *field, 735 llvm::StringRef fieldName, 736 unsigned fieldIndex); 737 738 mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty, 739 mlir::Location loc, clang::CharUnits alignment, 740 bool insertIntoFnEntryBlock, 741 mlir::Value arraySize = nullptr); 742 mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty, 743 mlir::Location loc, clang::CharUnits alignment, 744 mlir::OpBuilder::InsertPoint ip, 745 mlir::Value arraySize = nullptr); 746 747 void emitAggregateStore(mlir::Value value, Address dest); 748 749 void emitAggExpr(const clang::Expr *e, AggValueSlot slot); 750 751 LValue emitAggExprToLValue(const Expr *e); 752 753 /// Emit code to compute the specified expression which can have any type. The 754 /// result is returned as an RValue struct. If this is an aggregate 755 /// expression, the aggloc/agglocvolatile arguments indicate where the result 756 /// should be returned. 757 RValue emitAnyExpr(const clang::Expr *e, 758 AggValueSlot aggSlot = AggValueSlot::ignored()); 759 760 /// Similarly to emitAnyExpr(), however, the result will always be accessible 761 /// even if no aggregate location is provided. 762 RValue emitAnyExprToTemp(const clang::Expr *e); 763 764 LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e); 765 766 Address emitArrayToPointerDecay(const Expr *array); 767 768 AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d); 769 770 /// Emit code and set up symbol table for a variable declaration with auto, 771 /// register, or no storage class specifier. These turn into simple stack 772 /// objects, globals depending on target. 773 void emitAutoVarDecl(const clang::VarDecl &d); 774 775 void emitAutoVarCleanups(const AutoVarEmission &emission); 776 void emitAutoVarInit(const AutoVarEmission &emission); 777 778 void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl, 779 CXXCtorInitializer *baseInit); 780 781 LValue emitBinaryOperatorLValue(const BinaryOperator *e); 782 783 mlir::LogicalResult emitBreakStmt(const clang::BreakStmt &s); 784 785 RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID, 786 const clang::CallExpr *e, ReturnValueSlot returnValue); 787 788 RValue emitCall(const CIRGenFunctionInfo &funcInfo, 789 const CIRGenCallee &callee, ReturnValueSlot returnValue, 790 const CallArgList &args, cir::CIRCallOpInterface *callOp, 791 mlir::Location loc); 792 RValue emitCall(const CIRGenFunctionInfo &funcInfo, 793 const CIRGenCallee &callee, ReturnValueSlot returnValue, 794 const CallArgList &args, 795 cir::CIRCallOpInterface *callOrTryCall = nullptr) { 796 assert(currSrcLoc && "source location must have been set"); 797 return emitCall(funcInfo, callee, returnValue, args, callOrTryCall, 798 *currSrcLoc); 799 } 800 801 RValue emitCall(clang::QualType calleeTy, const CIRGenCallee &callee, 802 const clang::CallExpr *e, ReturnValueSlot returnValue); 803 void emitCallArg(CallArgList &args, const clang::Expr *e, 804 clang::QualType argType); 805 void emitCallArgs( 806 CallArgList &args, PrototypeWrapper prototype, 807 llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange, 808 AbstractCallee callee = AbstractCallee(), unsigned paramsToSkip = 0); 809 RValue emitCallExpr(const clang::CallExpr *e, 810 ReturnValueSlot returnValue = ReturnValueSlot()); 811 LValue emitCallExprLValue(const clang::CallExpr *e); 812 CIRGenCallee emitCallee(const clang::Expr *e); 813 814 template <typename T> 815 mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type condType, 816 mlir::ArrayAttr value, 817 cir::CaseOpKind kind, 818 bool buildingTopLevelCase); 819 820 mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s, 821 mlir::Type condType, 822 bool buildingTopLevelCase); 823 824 LValue emitCastLValue(const CastExpr *e); 825 826 /// Emits an argument for a call to a `__builtin_assume`. If the builtin 827 /// sanitizer is enabled, a runtime check is also emitted. 828 mlir::Value emitCheckedArgForAssume(const Expr *e); 829 830 LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e); 831 832 void emitConstructorBody(FunctionArgList &args); 833 void emitDestructorBody(FunctionArgList &args); 834 835 mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s); 836 837 void emitCXXConstructExpr(const clang::CXXConstructExpr *e, 838 AggValueSlot dest); 839 840 void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, 841 clang::CXXCtorType type, bool forVirtualBase, 842 bool delegating, AggValueSlot thisAVS, 843 const clang::CXXConstructExpr *e); 844 845 void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, 846 clang::CXXCtorType type, bool forVirtualBase, 847 bool delegating, Address thisAddr, 848 CallArgList &args, clang::SourceLocation loc); 849 850 mlir::LogicalResult emitCXXForRangeStmt(const CXXForRangeStmt &s, 851 llvm::ArrayRef<const Attr *> attrs); 852 853 RValue emitCXXMemberCallExpr(const clang::CXXMemberCallExpr *e, 854 ReturnValueSlot returnValue); 855 856 RValue emitCXXMemberOrOperatorCall( 857 const clang::CXXMethodDecl *md, const CIRGenCallee &callee, 858 ReturnValueSlot returnValue, mlir::Value thisPtr, 859 mlir::Value implicitParam, clang::QualType implicitParamTy, 860 const clang::CallExpr *ce, CallArgList *rtlArgs); 861 862 RValue emitCXXMemberOrOperatorMemberCallExpr( 863 const clang::CallExpr *ce, const clang::CXXMethodDecl *md, 864 ReturnValueSlot returnValue, bool hasQualifier, 865 clang::NestedNameSpecifier *qualifier, bool isArrow, 866 const clang::Expr *base); 867 868 mlir::Value emitCXXNewExpr(const CXXNewExpr *e); 869 870 RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e, 871 const CXXMethodDecl *md, 872 ReturnValueSlot returnValue); 873 874 void emitCtorPrologue(const clang::CXXConstructorDecl *ctor, 875 clang::CXXCtorType ctorType, FunctionArgList &args); 876 877 // It's important not to confuse this and emitDelegateCXXConstructorCall. 878 // Delegating constructors are the C++11 feature. The constructor delegate 879 // optimization is used to reduce duplication in the base and complete 880 // constructors where they are substantially the same. 881 void emitDelegatingCXXConstructorCall(const CXXConstructorDecl *ctor, 882 const FunctionArgList &args); 883 884 mlir::LogicalResult emitDoStmt(const clang::DoStmt &s); 885 886 /// Emit an expression as an initializer for an object (variable, field, etc.) 887 /// at the given location. The expression is not necessarily the normal 888 /// initializer for the object, and the address is not necessarily 889 /// its normal location. 890 /// 891 /// \param init the initializing expression 892 /// \param d the object to act as if we're initializing 893 /// \param lvalue the lvalue to initialize 894 /// \param capturedByInit true if \p d is a __block variable whose address is 895 /// potentially changed by the initializer 896 void emitExprAsInit(const clang::Expr *init, const clang::ValueDecl *d, 897 LValue lvalue, bool capturedByInit = false); 898 899 mlir::LogicalResult emitFunctionBody(const clang::Stmt *body); 900 901 void emitImplicitAssignmentOperatorBody(FunctionArgList &args); 902 903 void emitInitializerForField(clang::FieldDecl *field, LValue lhs, 904 clang::Expr *init); 905 906 mlir::Value emitPromotedComplexExpr(const Expr *e, QualType promotionType); 907 908 mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType); 909 910 /// Emit the computation of the specified expression of scalar type. 911 mlir::Value emitScalarExpr(const clang::Expr *e); 912 913 mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv, 914 bool isInc, bool isPre); 915 916 /// Build a debug stoppoint if we are emitting debug info. 917 void emitStopPoint(const Stmt *s); 918 919 // Build CIR for a statement. useCurrentScope should be true if no 920 // new scopes need be created when finding a compound statement. 921 mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, 922 llvm::ArrayRef<const Attr *> attrs = {}); 923 924 mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s, 925 bool useCurrentScope); 926 927 mlir::LogicalResult emitForStmt(const clang::ForStmt &s); 928 929 /// Emit the computation of the specified expression of complex type, 930 /// returning the result. 931 mlir::Value emitComplexExpr(const Expr *e); 932 933 LValue emitComplexAssignmentLValue(const BinaryOperator *e); 934 935 void emitCompoundStmt(const clang::CompoundStmt &s); 936 937 void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); 938 939 void emitDecl(const clang::Decl &d); 940 mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s); 941 LValue emitDeclRefLValue(const clang::DeclRefExpr *e); 942 943 mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s, 944 mlir::Type condType, 945 bool buildingTopLevelCase); 946 947 void emitDelegateCXXConstructorCall(const clang::CXXConstructorDecl *ctor, 948 clang::CXXCtorType ctorType, 949 const FunctionArgList &args, 950 clang::SourceLocation loc); 951 952 /// We are performing a delegate call; that is, the current function is 953 /// delegating to another one. Produce a r-value suitable for passing the 954 /// given parameter. 955 void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param, 956 clang::SourceLocation loc); 957 958 /// Emit an `if` on a boolean condition to the specified blocks. 959 /// FIXME: Based on the condition, this might try to simplify the codegen of 960 /// the conditional based on the branch. 961 /// In the future, we may apply code generation simplifications here, 962 /// similar to those used in classic LLVM codegen 963 /// See `EmitBranchOnBoolExpr` for inspiration. 964 mlir::LogicalResult emitIfOnBoolExpr(const clang::Expr *cond, 965 const clang::Stmt *thenS, 966 const clang::Stmt *elseS); 967 cir::IfOp emitIfOnBoolExpr(const clang::Expr *cond, 968 BuilderCallbackRef thenBuilder, 969 mlir::Location thenLoc, 970 BuilderCallbackRef elseBuilder, 971 std::optional<mlir::Location> elseLoc = {}); 972 973 mlir::Value emitOpOnBoolExpr(mlir::Location loc, const clang::Expr *cond); 974 975 mlir::LogicalResult emitIfStmt(const clang::IfStmt &s); 976 977 /// Emit code to compute the specified expression, 978 /// ignoring the result. 979 void emitIgnoredExpr(const clang::Expr *e); 980 981 RValue emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc); 982 983 /// Given an expression that represents a value lvalue, this method emits 984 /// the address of the lvalue, then loads the result as an rvalue, 985 /// returning the rvalue. 986 RValue emitLoadOfLValue(LValue lv, SourceLocation loc); 987 988 Address emitLoadOfReference(LValue refLVal, mlir::Location loc, 989 LValueBaseInfo *pointeeBaseInfo); 990 LValue emitLoadOfReferenceLValue(Address refAddr, mlir::Location loc, 991 QualType refTy, AlignmentSource source); 992 993 /// EmitLoadOfScalar - Load a scalar value from an address, taking 994 /// care to appropriately convert from the memory representation to 995 /// the LLVM value representation. The l-value must be a simple 996 /// l-value. 997 mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc); 998 999 /// Emit code to compute a designator that specifies the location 1000 /// of the expression. 1001 /// FIXME: document this function better. 1002 LValue emitLValue(const clang::Expr *e); 1003 LValue emitLValueForBitField(LValue base, const FieldDecl *field); 1004 LValue emitLValueForField(LValue base, const clang::FieldDecl *field); 1005 1006 /// Like emitLValueForField, excpet that if the Field is a reference, this 1007 /// will return the address of the reference and not the address of the value 1008 /// stored in the reference. 1009 LValue emitLValueForFieldInitialization(LValue base, 1010 const clang::FieldDecl *field, 1011 llvm::StringRef fieldName); 1012 1013 LValue emitMemberExpr(const MemberExpr *e); 1014 1015 /// Given an expression with a pointer type, emit the value and compute our 1016 /// best estimate of the alignment of the pointee. 1017 /// 1018 /// One reasonable way to use this information is when there's a language 1019 /// guarantee that the pointer must be aligned to some stricter value, and 1020 /// we're simply trying to ensure that sufficiently obvious uses of under- 1021 /// aligned objects don't get miscompiled; for example, a placement new 1022 /// into the address of a local variable. In such a case, it's quite 1023 /// reasonable to just ignore the returned alignment when it isn't from an 1024 /// explicit source. 1025 Address emitPointerWithAlignment(const clang::Expr *expr, 1026 LValueBaseInfo *baseInfo); 1027 1028 /// Emits a reference binding to the passed in expression. 1029 RValue emitReferenceBindingToExpr(const Expr *e); 1030 1031 mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s); 1032 1033 mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e); 1034 1035 /// Emit a conversion from the specified type to the specified destination 1036 /// type, both of which are CIR scalar types. 1037 mlir::Value emitScalarConversion(mlir::Value src, clang::QualType srcType, 1038 clang::QualType dstType, 1039 clang::SourceLocation loc); 1040 1041 void emitScalarInit(const clang::Expr *init, mlir::Location loc, 1042 LValue lvalue, bool capturedByInit = false); 1043 1044 void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage); 1045 1046 void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, 1047 bool isInit); 1048 1049 void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, 1050 clang::QualType ty, bool isInit = false, 1051 bool isNontemporal = false); 1052 void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit); 1053 1054 /// Store the specified rvalue into the specified 1055 /// lvalue, where both are guaranteed to the have the same type, and that type 1056 /// is 'Ty'. 1057 void emitStoreThroughLValue(RValue src, LValue dst, bool isInit = false); 1058 1059 mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult); 1060 1061 LValue emitStringLiteralLValue(const StringLiteral *e); 1062 1063 mlir::LogicalResult emitSwitchBody(const clang::Stmt *s); 1064 mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s, 1065 bool buildingTopLevelCase); 1066 mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s); 1067 1068 /// Given a value and its clang type, returns the value casted to its memory 1069 /// representation. 1070 /// Note: CIR defers most of the special casting to the final lowering passes 1071 /// to conserve the high level information. 1072 mlir::Value emitToMemory(mlir::Value value, clang::QualType ty); 1073 1074 LValue emitUnaryOpLValue(const clang::UnaryOperator *e); 1075 1076 /// This method handles emission of any variable declaration 1077 /// inside a function, including static vars etc. 1078 void emitVarDecl(const clang::VarDecl &d); 1079 1080 mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s); 1081 1082 /// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is 1083 /// nonnull, if 1\p LHS is marked _Nonnull. 1084 void emitNullabilityCheck(LValue lhs, mlir::Value rhs, 1085 clang::SourceLocation loc); 1086 1087 /// An object to manage conditionally-evaluated expressions. 1088 class ConditionalEvaluation { 1089 CIRGenFunction &cgf; 1090 mlir::OpBuilder::InsertPoint insertPt; 1091 1092 public: ConditionalEvaluation(CIRGenFunction & cgf)1093 ConditionalEvaluation(CIRGenFunction &cgf) 1094 : cgf(cgf), insertPt(cgf.builder.saveInsertionPoint()) {} ConditionalEvaluation(CIRGenFunction & cgf,mlir::OpBuilder::InsertPoint ip)1095 ConditionalEvaluation(CIRGenFunction &cgf, mlir::OpBuilder::InsertPoint ip) 1096 : cgf(cgf), insertPt(ip) {} 1097 beginEvaluation()1098 void beginEvaluation() { 1099 assert(cgf.outermostConditional != this); 1100 if (!cgf.outermostConditional) 1101 cgf.outermostConditional = this; 1102 } 1103 endEvaluation()1104 void endEvaluation() { 1105 assert(cgf.outermostConditional != nullptr); 1106 if (cgf.outermostConditional == this) 1107 cgf.outermostConditional = nullptr; 1108 } 1109 1110 /// Returns the insertion point which will be executed prior to each 1111 /// evaluation of the conditional code. In LLVM OG, this method 1112 /// is called getStartingBlock. getInsertPoint()1113 mlir::OpBuilder::InsertPoint getInsertPoint() const { return insertPt; } 1114 }; 1115 1116 struct ConditionalInfo { 1117 std::optional<LValue> lhs{}, rhs{}; 1118 mlir::Value result{}; 1119 }; 1120 1121 // Return true if we're currently emitting one branch or the other of a 1122 // conditional expression. isInConditionalBranch()1123 bool isInConditionalBranch() const { return outermostConditional != nullptr; } 1124 setBeforeOutermostConditional(mlir::Value value,Address addr)1125 void setBeforeOutermostConditional(mlir::Value value, Address addr) { 1126 assert(isInConditionalBranch()); 1127 { 1128 mlir::OpBuilder::InsertionGuard guard(builder); 1129 builder.restoreInsertionPoint(outermostConditional->getInsertPoint()); 1130 builder.createStore( 1131 value.getLoc(), value, addr, 1132 mlir::IntegerAttr::get( 1133 mlir::IntegerType::get(value.getContext(), 64), 1134 (uint64_t)addr.getAlignment().getAsAlign().value())); 1135 } 1136 } 1137 1138 // Points to the outermost active conditional control. This is used so that 1139 // we know if a temporary should be destroyed conditionally. 1140 ConditionalEvaluation *outermostConditional = nullptr; 1141 1142 template <typename FuncTy> 1143 ConditionalInfo emitConditionalBlocks(const AbstractConditionalOperator *e, 1144 const FuncTy &branchGenFunc); 1145 1146 mlir::Value emitTernaryOnBoolExpr(const clang::Expr *cond, mlir::Location loc, 1147 const clang::Stmt *thenS, 1148 const clang::Stmt *elseS); 1149 1150 /// ---------------------- 1151 /// CIR build helpers 1152 /// ----------------- 1153 public: 1154 cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, 1155 const Twine &name = "tmp", 1156 mlir::Value arraySize = nullptr, 1157 bool insertIntoFnEntryBlock = false); 1158 cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, 1159 const Twine &name = "tmp", 1160 mlir::OpBuilder::InsertPoint ip = {}, 1161 mlir::Value arraySize = nullptr); 1162 Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc, 1163 const Twine &name = "tmp", 1164 mlir::Value arraySize = nullptr, 1165 Address *alloca = nullptr, 1166 mlir::OpBuilder::InsertPoint ip = {}); 1167 Address createTempAllocaWithoutCast(mlir::Type ty, CharUnits align, 1168 mlir::Location loc, 1169 const Twine &name = "tmp", 1170 mlir::Value arraySize = nullptr, 1171 mlir::OpBuilder::InsertPoint ip = {}); 1172 1173 /// Create a temporary memory object of the given type, with 1174 /// appropriate alignmen and cast it to the default address space. Returns 1175 /// the original alloca instruction by \p Alloca if it is not nullptr. 1176 Address createMemTemp(QualType t, mlir::Location loc, 1177 const Twine &name = "tmp", Address *alloca = nullptr, 1178 mlir::OpBuilder::InsertPoint ip = {}); 1179 Address createMemTemp(QualType t, CharUnits align, mlir::Location loc, 1180 const Twine &name = "tmp", Address *alloca = nullptr, 1181 mlir::OpBuilder::InsertPoint ip = {}); 1182 1183 //===--------------------------------------------------------------------===// 1184 // OpenACC Emission 1185 //===--------------------------------------------------------------------===// 1186 private: 1187 template <typename Op> 1188 Op emitOpenACCOp(mlir::Location start, OpenACCDirectiveKind dirKind, 1189 SourceLocation dirLoc, 1190 llvm::ArrayRef<const OpenACCClause *> clauses); 1191 // Function to do the basic implementation of an operation with an Associated 1192 // Statement. Models AssociatedStmtConstruct. 1193 template <typename Op, typename TermOp> 1194 mlir::LogicalResult emitOpenACCOpAssociatedStmt( 1195 mlir::Location start, mlir::Location end, OpenACCDirectiveKind dirKind, 1196 SourceLocation dirLoc, llvm::ArrayRef<const OpenACCClause *> clauses, 1197 const Stmt *associatedStmt); 1198 1199 template <typename Op, typename TermOp> 1200 mlir::LogicalResult emitOpenACCOpCombinedConstruct( 1201 mlir::Location start, mlir::Location end, OpenACCDirectiveKind dirKind, 1202 SourceLocation dirLoc, llvm::ArrayRef<const OpenACCClause *> clauses, 1203 const Stmt *loopStmt); 1204 1205 template <typename Op> 1206 void emitOpenACCClauses(Op &op, OpenACCDirectiveKind dirKind, 1207 SourceLocation dirLoc, 1208 ArrayRef<const OpenACCClause *> clauses); 1209 // The second template argument doesn't need to be a template, since it should 1210 // always be an mlir::acc::LoopOp, but as this is a template anyway, we make 1211 // it a template argument as this way we can avoid including the OpenACC MLIR 1212 // headers here. We will count on linker failures/explicit instantiation to 1213 // ensure we don't mess this up, but it is only called from 1 place, and 1214 // instantiated 3x. 1215 template <typename ComputeOp, typename LoopOp> 1216 void emitOpenACCClauses(ComputeOp &op, LoopOp &loopOp, 1217 OpenACCDirectiveKind dirKind, SourceLocation dirLoc, 1218 ArrayRef<const OpenACCClause *> clauses); 1219 1220 // The OpenACC LoopOp requires that we have auto, seq, or independent on all 1221 // LoopOp operations for the 'none' device type case. This function checks if 1222 // the LoopOp has one, else it updates it to have one. 1223 void updateLoopOpParallelism(mlir::acc::LoopOp &op, bool isOrphan, 1224 OpenACCDirectiveKind dk); 1225 1226 // The OpenACC 'cache' construct actually applies to the 'loop' if present. So 1227 // keep track of the 'loop' so that we can add the cache vars to it correctly. 1228 mlir::acc::LoopOp *activeLoopOp = nullptr; 1229 1230 struct ActiveOpenACCLoopRAII { 1231 CIRGenFunction &cgf; 1232 mlir::acc::LoopOp *oldLoopOp; 1233 ActiveOpenACCLoopRAIIActiveOpenACCLoopRAII1234 ActiveOpenACCLoopRAII(CIRGenFunction &cgf, mlir::acc::LoopOp *newOp) 1235 : cgf(cgf), oldLoopOp(cgf.activeLoopOp) { 1236 cgf.activeLoopOp = newOp; 1237 } ~ActiveOpenACCLoopRAIIActiveOpenACCLoopRAII1238 ~ActiveOpenACCLoopRAII() { cgf.activeLoopOp = oldLoopOp; } 1239 }; 1240 1241 public: 1242 // Helper type used to store the list of important information for a 'data' 1243 // clause variable, or a 'cache' variable reference. 1244 struct OpenACCDataOperandInfo { 1245 mlir::Location beginLoc; 1246 mlir::Value varValue; 1247 std::string name; 1248 llvm::SmallVector<mlir::Value> bounds; 1249 }; 1250 // Gets the collection of info required to lower and OpenACC clause or cache 1251 // construct variable reference. 1252 OpenACCDataOperandInfo getOpenACCDataOperandInfo(const Expr *e); 1253 // Helper function to emit the integer expressions as required by an OpenACC 1254 // clause/construct. 1255 mlir::Value emitOpenACCIntExpr(const Expr *intExpr); 1256 // Helper function to emit an integer constant as an mlir int type, used for 1257 // constants in OpenACC constructs/clauses. 1258 mlir::Value createOpenACCConstantInt(mlir::Location loc, unsigned width, 1259 int64_t value); 1260 1261 mlir::LogicalResult 1262 emitOpenACCComputeConstruct(const OpenACCComputeConstruct &s); 1263 mlir::LogicalResult emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s); 1264 mlir::LogicalResult 1265 emitOpenACCCombinedConstruct(const OpenACCCombinedConstruct &s); 1266 mlir::LogicalResult emitOpenACCDataConstruct(const OpenACCDataConstruct &s); 1267 mlir::LogicalResult 1268 emitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &s); 1269 mlir::LogicalResult 1270 emitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &s); 1271 mlir::LogicalResult 1272 emitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &s); 1273 mlir::LogicalResult emitOpenACCWaitConstruct(const OpenACCWaitConstruct &s); 1274 mlir::LogicalResult emitOpenACCInitConstruct(const OpenACCInitConstruct &s); 1275 mlir::LogicalResult 1276 emitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &s); 1277 mlir::LogicalResult emitOpenACCSetConstruct(const OpenACCSetConstruct &s); 1278 mlir::LogicalResult 1279 emitOpenACCUpdateConstruct(const OpenACCUpdateConstruct &s); 1280 mlir::LogicalResult 1281 emitOpenACCAtomicConstruct(const OpenACCAtomicConstruct &s); 1282 mlir::LogicalResult emitOpenACCCacheConstruct(const OpenACCCacheConstruct &s); 1283 1284 void emitOpenACCDeclare(const OpenACCDeclareDecl &d); 1285 void emitOpenACCRoutine(const OpenACCRoutineDecl &d); 1286 1287 /// Create a temporary memory object for the given aggregate type. 1288 AggValueSlot createAggTemp(QualType ty, mlir::Location loc, 1289 const Twine &name = "tmp", 1290 Address *alloca = nullptr) { 1291 assert(!cir::MissingFeatures::aggValueSlot()); 1292 return AggValueSlot::forAddr( 1293 createMemTemp(ty, loc, name, alloca), ty.getQualifiers(), 1294 AggValueSlot::IsNotDestructed, AggValueSlot::IsNotAliased, 1295 AggValueSlot::DoesNotOverlap); 1296 } 1297 1298 private: 1299 QualType getVarArgType(const Expr *arg); 1300 }; 1301 1302 } // namespace clang::CIRGen 1303 1304 #endif 1305