| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This contains code to emit Expr nodes as CIR code. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Address.h" |
| #include "CIRGenFunction.h" |
| #include "CIRGenValue.h" |
| #include "mlir/IR/BuiltinAttributes.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/CIR/Dialect/IR/CIRDialect.h" |
| #include "clang/CIR/MissingFeatures.h" |
| |
| using namespace clang; |
| using namespace clang::CIRGen; |
| using namespace cir; |
| |
| void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst, |
| bool isInit) { |
| if (!dst.isSimple()) { |
| cgm.errorNYI(dst.getPointer().getLoc(), |
| "emitStoreThroughLValue: non-simple lvalue"); |
| return; |
| } |
| |
| assert(!cir::MissingFeatures::opLoadStoreObjC()); |
| |
| assert(src.isScalar() && "Can't emit an aggregate store with this method"); |
| emitStoreOfScalar(src.getScalarVal(), dst, isInit); |
| } |
| |
| void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr, |
| bool isVolatile, QualType ty, |
| bool isInit, bool isNontemporal) { |
| assert(!cir::MissingFeatures::opLoadStoreThreadLocal()); |
| |
| if (ty->getAs<clang::VectorType>()) { |
| cgm.errorNYI(addr.getPointer().getLoc(), "emitStoreOfScalar vector type"); |
| return; |
| } |
| |
| value = emitToMemory(value, ty); |
| |
| assert(!cir::MissingFeatures::opLoadStoreAtomic()); |
| |
| // Update the alloca with more info on initialization. |
| assert(addr.getPointer() && "expected pointer to exist"); |
| auto srcAlloca = |
| dyn_cast_or_null<cir::AllocaOp>(addr.getPointer().getDefiningOp()); |
| if (currVarDecl && srcAlloca) { |
| const VarDecl *vd = currVarDecl; |
| assert(vd && "VarDecl expected"); |
| if (vd->hasInit()) |
| srcAlloca.setInitAttr(mlir::UnitAttr::get(&getMLIRContext())); |
| } |
| |
| assert(currSrcLoc && "must pass in source location"); |
| builder.createStore(*currSrcLoc, value, addr.getPointer() /*, isVolatile*/); |
| |
| if (isNontemporal) { |
| cgm.errorNYI(addr.getPointer().getLoc(), "emitStoreOfScalar nontemporal"); |
| return; |
| } |
| |
| assert(!cir::MissingFeatures::opTBAA()); |
| } |
| |
| mlir::Value CIRGenFunction::emitToMemory(mlir::Value value, QualType ty) { |
| // Bool has a different representation in memory than in registers, |
| // but in ClangIR, it is simply represented as a cir.bool value. |
| // This function is here as a placeholder for possible future changes. |
| return value; |
| } |
| |
| void CIRGenFunction::emitStoreOfScalar(mlir::Value value, LValue lvalue, |
| bool isInit) { |
| if (lvalue.getType()->isConstantMatrixType()) { |
| assert(0 && "NYI: emitStoreOfScalar constant matrix type"); |
| return; |
| } |
| |
| emitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(), |
| lvalue.getType(), isInit, /*isNontemporal=*/false); |
| } |
| |
| mlir::Value CIRGenFunction::emitLoadOfScalar(LValue lvalue, |
| SourceLocation loc) { |
| assert(!cir::MissingFeatures::opLoadStoreThreadLocal()); |
| assert(!cir::MissingFeatures::opLoadEmitScalarRangeCheck()); |
| assert(!cir::MissingFeatures::opLoadBooleanRepresentation()); |
| |
| Address addr = lvalue.getAddress(); |
| mlir::Type eltTy = addr.getElementType(); |
| |
| mlir::Value ptr = addr.getPointer(); |
| if (mlir::isa<cir::VoidType>(eltTy)) |
| cgm.errorNYI(loc, "emitLoadOfScalar: void type"); |
| |
| mlir::Value loadOp = builder.CIRBaseBuilderTy::createLoad( |
| getLoc(loc), ptr, false /*isVolatile*/); |
| |
| return loadOp; |
| } |
| |
| /// Given an expression that represents a value lvalue, this |
| /// method emits the address of the lvalue, then loads the result as an rvalue, |
| /// returning the rvalue. |
| RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) { |
| assert(!lv.getType()->isFunctionType()); |
| assert(!(lv.getType()->isConstantMatrixType()) && "not implemented"); |
| |
| if (lv.isSimple()) |
| return RValue::get(emitLoadOfScalar(lv, loc)); |
| |
| cgm.errorNYI(loc, "emitLoadOfLValue"); |
| return RValue::get(nullptr); |
| } |
| |
| LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { |
| const NamedDecl *nd = e->getDecl(); |
| QualType ty = e->getType(); |
| |
| assert(e->isNonOdrUse() != NOUR_Unevaluated && |
| "should not emit an unevaluated operand"); |
| |
| if (const auto *vd = dyn_cast<VarDecl>(nd)) { |
| // Checks for omitted feature handling |
| assert(!cir::MissingFeatures::opAllocaStaticLocal()); |
| assert(!cir::MissingFeatures::opAllocaNonGC()); |
| assert(!cir::MissingFeatures::opAllocaImpreciseLifetime()); |
| assert(!cir::MissingFeatures::opAllocaTLS()); |
| assert(!cir::MissingFeatures::opAllocaOpenMPThreadPrivate()); |
| assert(!cir::MissingFeatures::opAllocaEscapeByReference()); |
| |
| // Check if this is a global variable |
| if (vd->hasLinkage() || vd->isStaticDataMember()) |
| cgm.errorNYI(vd->getSourceRange(), "emitDeclRefLValue: global variable"); |
| |
| Address addr = Address::invalid(); |
| |
| // The variable should generally be present in the local decl map. |
| auto iter = LocalDeclMap.find(vd); |
| if (iter != LocalDeclMap.end()) { |
| addr = iter->second; |
| } else { |
| // Otherwise, it might be static local we haven't emitted yet for some |
| // reason; most likely, because it's in an outer function. |
| cgm.errorNYI(vd->getSourceRange(), "emitDeclRefLValue: static local"); |
| } |
| |
| return LValue::makeAddr(addr, ty); |
| } |
| |
| cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type"); |
| return LValue(); |
| } |
| |
| mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty, |
| mlir::Location loc, |
| CharUnits alignment) { |
| mlir::Block *entryBlock = getCurFunctionEntryBlock(); |
| |
| // CIR uses its own alloca address space rather than follow the target data |
| // layout like original CodeGen. The data layout awareness should be done in |
| // the lowering pass instead. |
| assert(!cir::MissingFeatures::addressSpace()); |
| cir::PointerType localVarPtrTy = builder.getPointerTo(ty); |
| mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment); |
| |
| mlir::Value addr; |
| { |
| mlir::OpBuilder::InsertionGuard guard(builder); |
| builder.restoreInsertionPoint(builder.getBestAllocaInsertPoint(entryBlock)); |
| addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy, |
| /*var type*/ ty, name, alignIntAttr); |
| assert(!cir::MissingFeatures::astVarDeclInterface()); |
| } |
| return addr; |
| } |
| |
| /// This creates an alloca and inserts it at the current insertion point of the |
| /// builder. |
| Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align, |
| mlir::Location loc, |
| const Twine &name) { |
| mlir::Value alloca = emitAlloca(name.str(), ty, loc, align); |
| return Address(alloca, ty, align); |
| } |