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 // Generic OpenACC lowering functions not Stmt, Decl, or clause specific. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CIRGenFunction.h" 14 #include "mlir/Dialect/Arith/IR/Arith.h" 15 #include "mlir/Dialect/OpenACC/OpenACC.h" 16 #include "clang/AST/ExprCXX.h" 17 18 using namespace clang; 19 using namespace clang::CIRGen; 20 21 namespace { 22 mlir::Value createBound(CIRGenFunction &cgf, CIRGen::CIRGenBuilderTy &builder, 23 mlir::Location boundLoc, mlir::Value lowerBound, 24 mlir::Value upperBound, mlir::Value extent) { 25 // Arrays always have a start-idx of 0. 26 mlir::Value startIdx = cgf.createOpenACCConstantInt(boundLoc, 64, 0); 27 // Stride is always 1 in C/C++. 28 mlir::Value stride = cgf.createOpenACCConstantInt(boundLoc, 64, 1); 29 30 auto bound = 31 builder.create<mlir::acc::DataBoundsOp>(boundLoc, lowerBound, upperBound); 32 bound.getStartIdxMutable().assign(startIdx); 33 if (extent) 34 bound.getExtentMutable().assign(extent); 35 bound.getStrideMutable().assign(stride); 36 37 return bound; 38 } 39 } // namespace 40 41 mlir::Value CIRGenFunction::emitOpenACCIntExpr(const Expr *intExpr) { 42 mlir::Value expr = emitScalarExpr(intExpr); 43 mlir::Location exprLoc = cgm.getLoc(intExpr->getBeginLoc()); 44 45 mlir::IntegerType targetType = mlir::IntegerType::get( 46 &getMLIRContext(), getContext().getIntWidth(intExpr->getType()), 47 intExpr->getType()->isSignedIntegerOrEnumerationType() 48 ? mlir::IntegerType::SignednessSemantics::Signed 49 : mlir::IntegerType::SignednessSemantics::Unsigned); 50 51 auto conversionOp = builder.create<mlir::UnrealizedConversionCastOp>( 52 exprLoc, targetType, expr); 53 return conversionOp.getResult(0); 54 } 55 56 mlir::Value CIRGenFunction::createOpenACCConstantInt(mlir::Location loc, 57 unsigned width, 58 int64_t value) { 59 mlir::IntegerType ty = 60 mlir::IntegerType::get(&getMLIRContext(), width, 61 mlir::IntegerType::SignednessSemantics::Signless); 62 auto constOp = builder.create<mlir::arith::ConstantOp>( 63 loc, builder.getIntegerAttr(ty, value)); 64 65 return constOp.getResult(); 66 } 67 68 CIRGenFunction::OpenACCDataOperandInfo 69 CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { 70 const Expr *curVarExpr = e->IgnoreParenImpCasts(); 71 72 mlir::Location exprLoc = cgm.getLoc(curVarExpr->getBeginLoc()); 73 llvm::SmallVector<mlir::Value> bounds; 74 75 std::string exprString; 76 llvm::raw_string_ostream os(exprString); 77 e->printPretty(os, nullptr, getContext().getPrintingPolicy()); 78 79 while (isa<ArraySectionExpr, ArraySubscriptExpr>(curVarExpr)) { 80 mlir::Location boundLoc = cgm.getLoc(curVarExpr->getBeginLoc()); 81 mlir::Value lowerBound; 82 mlir::Value upperBound; 83 mlir::Value extent; 84 85 if (const auto *section = dyn_cast<ArraySectionExpr>(curVarExpr)) { 86 if (const Expr *lb = section->getLowerBound()) 87 lowerBound = emitOpenACCIntExpr(lb); 88 else 89 lowerBound = createOpenACCConstantInt(boundLoc, 64, 0); 90 91 if (const Expr *len = section->getLength()) { 92 extent = emitOpenACCIntExpr(len); 93 } else { 94 QualType baseTy = ArraySectionExpr::getBaseOriginalType( 95 section->getBase()->IgnoreParenImpCasts()); 96 // We know this is the case as implicit lengths are only allowed for 97 // array types with a constant size, or a dependent size. AND since 98 // we are codegen we know we're not dependent. 99 auto *arrayTy = getContext().getAsConstantArrayType(baseTy); 100 // Rather than trying to calculate the extent based on the 101 // lower-bound, we can just emit this as an upper bound. 102 upperBound = createOpenACCConstantInt(boundLoc, 64, 103 arrayTy->getLimitedSize() - 1); 104 } 105 106 curVarExpr = section->getBase()->IgnoreParenImpCasts(); 107 } else { 108 const auto *subscript = cast<ArraySubscriptExpr>(curVarExpr); 109 110 lowerBound = emitOpenACCIntExpr(subscript->getIdx()); 111 // Length of an array index is always 1. 112 extent = createOpenACCConstantInt(boundLoc, 64, 1); 113 curVarExpr = subscript->getBase()->IgnoreParenImpCasts(); 114 } 115 116 bounds.push_back(createBound(*this, this->builder, boundLoc, lowerBound, 117 upperBound, extent)); 118 } 119 120 if (const auto *memExpr = dyn_cast<MemberExpr>(curVarExpr)) 121 return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString, 122 std::move(bounds)}; 123 124 // Sema has made sure that only 4 types of things can get here, array 125 // subscript, array section, member expr, or DRE to a var decl (or the 126 // former 3 wrapping a var-decl), so we should be able to assume this is 127 // right. 128 const auto *dre = cast<DeclRefExpr>(curVarExpr); 129 return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString, 130 std::move(bounds)}; 131 } 132