1 //====- LoweringHelpers.cpp - Lowering helper functions -------------------===// 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 // This file contains helper functions for lowering from CIR to LLVM or MLIR. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/CIR/LoweringHelpers.h" 14 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 15 #include "clang/CIR/MissingFeatures.h" 16 17 mlir::DenseElementsAttr 18 convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr, 19 mlir::Type type) { 20 auto values = llvm::SmallVector<mlir::APInt, 8>{}; 21 const auto stringAttr = mlir::cast<mlir::StringAttr>(attr.getElts()); 22 23 for (const char element : stringAttr) 24 values.push_back({8, (uint64_t)element}); 25 26 const auto arrayTy = mlir::cast<cir::ArrayType>(attr.getType()); 27 if (arrayTy.getSize() != stringAttr.size()) 28 assert(!cir::MissingFeatures::stringTypeWithDifferentArraySize()); 29 30 return mlir::DenseElementsAttr::get( 31 mlir::RankedTensorType::get({(int64_t)values.size()}, type), 32 llvm::ArrayRef(values)); 33 } 34 35 template <> mlir::APInt getZeroInitFromType(mlir::Type ty) { 36 assert(mlir::isa<cir::IntType>(ty) && "expected int type"); 37 const auto intTy = mlir::cast<cir::IntType>(ty); 38 return mlir::APInt::getZero(intTy.getWidth()); 39 } 40 41 template <> mlir::APFloat getZeroInitFromType(mlir::Type ty) { 42 assert((mlir::isa<cir::SingleType, cir::DoubleType>(ty)) && 43 "only float and double supported"); 44 45 if (ty.isF32() || mlir::isa<cir::SingleType>(ty)) 46 return mlir::APFloat(0.f); 47 48 if (ty.isF64() || mlir::isa<cir::DoubleType>(ty)) 49 return mlir::APFloat(0.0); 50 51 llvm_unreachable("NYI"); 52 } 53 54 /// \param attr the ConstArrayAttr to convert 55 /// \param values the output parameter, the values array to fill 56 /// \param currentDims the shpae of tensor we're going to convert to 57 /// \param dimIndex the current dimension we're processing 58 /// \param currentIndex the current index in the values array 59 template <typename AttrTy, typename StorageTy> 60 void convertToDenseElementsAttrImpl( 61 cir::ConstArrayAttr attr, llvm::SmallVectorImpl<StorageTy> &values, 62 const llvm::SmallVectorImpl<int64_t> ¤tDims, int64_t dimIndex, 63 int64_t currentIndex) { 64 if (auto stringAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) { 65 if (auto arrayType = mlir::dyn_cast<cir::ArrayType>(attr.getType())) { 66 for (auto element : stringAttr) { 67 auto intAttr = cir::IntAttr::get(arrayType.getElementType(), element); 68 values[currentIndex++] = mlir::dyn_cast<AttrTy>(intAttr).getValue(); 69 } 70 return; 71 } 72 } 73 74 dimIndex++; 75 std::size_t elementsSizeInCurrentDim = 1; 76 for (std::size_t i = dimIndex; i < currentDims.size(); i++) 77 elementsSizeInCurrentDim *= currentDims[i]; 78 79 auto arrayAttr = mlir::cast<mlir::ArrayAttr>(attr.getElts()); 80 for (auto eltAttr : arrayAttr) { 81 if (auto valueAttr = mlir::dyn_cast<AttrTy>(eltAttr)) { 82 values[currentIndex++] = valueAttr.getValue(); 83 continue; 84 } 85 86 if (auto subArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(eltAttr)) { 87 convertToDenseElementsAttrImpl<AttrTy>(subArrayAttr, values, currentDims, 88 dimIndex, currentIndex); 89 currentIndex += elementsSizeInCurrentDim; 90 continue; 91 } 92 93 if (mlir::isa<cir::ZeroAttr, cir::UndefAttr>(eltAttr)) { 94 currentIndex += elementsSizeInCurrentDim; 95 continue; 96 } 97 98 llvm_unreachable("unknown element in ConstArrayAttr"); 99 } 100 } 101 102 template <typename AttrTy, typename StorageTy> 103 mlir::DenseElementsAttr convertToDenseElementsAttr( 104 cir::ConstArrayAttr attr, const llvm::SmallVectorImpl<int64_t> &dims, 105 mlir::Type elementType, mlir::Type convertedElementType) { 106 unsigned vectorSize = 1; 107 for (auto dim : dims) 108 vectorSize *= dim; 109 auto values = llvm::SmallVector<StorageTy, 8>( 110 vectorSize, getZeroInitFromType<StorageTy>(elementType)); 111 convertToDenseElementsAttrImpl<AttrTy>(attr, values, dims, /*currentDim=*/0, 112 /*initialIndex=*/0); 113 return mlir::DenseElementsAttr::get( 114 mlir::RankedTensorType::get(dims, convertedElementType), 115 llvm::ArrayRef(values)); 116 } 117 118 std::optional<mlir::Attribute> 119 lowerConstArrayAttr(cir::ConstArrayAttr constArr, 120 const mlir::TypeConverter *converter) { 121 // Ensure ConstArrayAttr has a type. 122 const auto typedConstArr = mlir::cast<mlir::TypedAttr>(constArr); 123 124 // Ensure ConstArrayAttr type is a ArrayType. 125 const auto cirArrayType = mlir::cast<cir::ArrayType>(typedConstArr.getType()); 126 127 // Is a ConstArrayAttr with an cir::ArrayType: fetch element type. 128 mlir::Type type = cirArrayType; 129 auto dims = llvm::SmallVector<int64_t, 2>{}; 130 while (auto arrayType = mlir::dyn_cast<cir::ArrayType>(type)) { 131 dims.push_back(arrayType.getSize()); 132 type = arrayType.getElementType(); 133 } 134 135 if (mlir::isa<mlir::StringAttr>(constArr.getElts())) 136 return convertStringAttrToDenseElementsAttr(constArr, 137 converter->convertType(type)); 138 if (mlir::isa<cir::IntType>(type)) 139 return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>( 140 constArr, dims, type, converter->convertType(type)); 141 142 if (mlir::isa<cir::FPTypeInterface>(type)) 143 return convertToDenseElementsAttr<cir::FPAttr, mlir::APFloat>( 144 constArr, dims, type, converter->convertType(type)); 145 146 return std::nullopt; 147 } 148 149 mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc, 150 mlir::Type typ, const llvm::APInt &val) { 151 return bld.create<mlir::LLVM::ConstantOp>(loc, typ, val); 152 } 153 154 mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ, 155 unsigned val) { 156 return bld.create<mlir::LLVM::ConstantOp>(loc, typ, val); 157 } 158 159 mlir::Value createShL(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { 160 if (!rhs) 161 return lhs; 162 mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); 163 return bld.create<mlir::LLVM::ShlOp>(lhs.getLoc(), lhs, rhsVal); 164 } 165 166 mlir::Value createAShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { 167 if (!rhs) 168 return lhs; 169 mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); 170 return bld.create<mlir::LLVM::AShrOp>(lhs.getLoc(), lhs, rhsVal); 171 } 172 173 mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs, 174 const llvm::APInt &rhs) { 175 mlir::Value rhsVal = getConstAPInt(bld, lhs.getLoc(), lhs.getType(), rhs); 176 return bld.create<mlir::LLVM::AndOp>(lhs.getLoc(), lhs, rhsVal); 177 } 178 179 mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { 180 if (!rhs) 181 return lhs; 182 mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); 183 return bld.create<mlir::LLVM::LShrOp>(lhs.getLoc(), lhs, rhsVal); 184 } 185