//====- LoweringHelpers.cpp - Lowering helper functions -------------------===// // // 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 file contains helper functions for lowering from CIR to LLVM or MLIR. // //===----------------------------------------------------------------------===// #include "clang/CIR/LoweringHelpers.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "clang/CIR/MissingFeatures.h" mlir::DenseElementsAttr convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr, mlir::Type type) { auto values = llvm::SmallVector{}; const auto stringAttr = mlir::cast(attr.getElts()); for (const char element : stringAttr) values.push_back({8, (uint64_t)element}); const auto arrayTy = mlir::cast(attr.getType()); if (arrayTy.getSize() != stringAttr.size()) assert(!cir::MissingFeatures::stringTypeWithDifferentArraySize()); return mlir::DenseElementsAttr::get( mlir::RankedTensorType::get({(int64_t)values.size()}, type), llvm::ArrayRef(values)); } template <> mlir::APInt getZeroInitFromType(mlir::Type ty) { assert(mlir::isa(ty) && "expected int type"); const auto intTy = mlir::cast(ty); return mlir::APInt::getZero(intTy.getWidth()); } template <> mlir::APFloat getZeroInitFromType(mlir::Type ty) { assert((mlir::isa(ty)) && "only float and double supported"); if (ty.isF32() || mlir::isa(ty)) return mlir::APFloat(0.f); if (ty.isF64() || mlir::isa(ty)) return mlir::APFloat(0.0); llvm_unreachable("NYI"); } /// \param attr the ConstArrayAttr to convert /// \param values the output parameter, the values array to fill /// \param currentDims the shpae of tensor we're going to convert to /// \param dimIndex the current dimension we're processing /// \param currentIndex the current index in the values array template void convertToDenseElementsAttrImpl( cir::ConstArrayAttr attr, llvm::SmallVectorImpl &values, const llvm::SmallVectorImpl ¤tDims, int64_t dimIndex, int64_t currentIndex) { if (auto stringAttr = mlir::dyn_cast(attr.getElts())) { if (auto arrayType = mlir::dyn_cast(attr.getType())) { for (auto element : stringAttr) { auto intAttr = cir::IntAttr::get(arrayType.getElementType(), element); values[currentIndex++] = mlir::dyn_cast(intAttr).getValue(); } return; } } dimIndex++; std::size_t elementsSizeInCurrentDim = 1; for (std::size_t i = dimIndex; i < currentDims.size(); i++) elementsSizeInCurrentDim *= currentDims[i]; auto arrayAttr = mlir::cast(attr.getElts()); for (auto eltAttr : arrayAttr) { if (auto valueAttr = mlir::dyn_cast(eltAttr)) { values[currentIndex++] = valueAttr.getValue(); continue; } if (auto subArrayAttr = mlir::dyn_cast(eltAttr)) { convertToDenseElementsAttrImpl(subArrayAttr, values, currentDims, dimIndex, currentIndex); currentIndex += elementsSizeInCurrentDim; continue; } if (mlir::isa(eltAttr)) { currentIndex += elementsSizeInCurrentDim; continue; } llvm_unreachable("unknown element in ConstArrayAttr"); } } template mlir::DenseElementsAttr convertToDenseElementsAttr( cir::ConstArrayAttr attr, const llvm::SmallVectorImpl &dims, mlir::Type elementType, mlir::Type convertedElementType) { unsigned vectorSize = 1; for (auto dim : dims) vectorSize *= dim; auto values = llvm::SmallVector( vectorSize, getZeroInitFromType(elementType)); convertToDenseElementsAttrImpl(attr, values, dims, /*currentDim=*/0, /*initialIndex=*/0); return mlir::DenseElementsAttr::get( mlir::RankedTensorType::get(dims, convertedElementType), llvm::ArrayRef(values)); } std::optional lowerConstArrayAttr(cir::ConstArrayAttr constArr, const mlir::TypeConverter *converter) { // Ensure ConstArrayAttr has a type. const auto typedConstArr = mlir::cast(constArr); // Ensure ConstArrayAttr type is a ArrayType. const auto cirArrayType = mlir::cast(typedConstArr.getType()); // Is a ConstArrayAttr with an cir::ArrayType: fetch element type. mlir::Type type = cirArrayType; auto dims = llvm::SmallVector{}; while (auto arrayType = mlir::dyn_cast(type)) { dims.push_back(arrayType.getSize()); type = arrayType.getElementType(); } if (mlir::isa(constArr.getElts())) return convertStringAttrToDenseElementsAttr(constArr, converter->convertType(type)); if (mlir::isa(type)) return convertToDenseElementsAttr( constArr, dims, type, converter->convertType(type)); if (mlir::isa(type)) return convertToDenseElementsAttr( constArr, dims, type, converter->convertType(type)); return std::nullopt; } mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ, const llvm::APInt &val) { return bld.create(loc, typ, val); } mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ, unsigned val) { return bld.create(loc, typ, val); } mlir::Value createShL(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { if (!rhs) return lhs; mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); return bld.create(lhs.getLoc(), lhs, rhsVal); } mlir::Value createAShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { if (!rhs) return lhs; mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); return bld.create(lhs.getLoc(), lhs, rhsVal); } mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs, const llvm::APInt &rhs) { mlir::Value rhsVal = getConstAPInt(bld, lhs.getLoc(), lhs.getType(), rhs); return bld.create(lhs.getLoc(), lhs, rhsVal); } mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) { if (!rhs) return lhs; mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs); return bld.create(lhs.getLoc(), lhs, rhsVal); }