185 lines · cpp
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-exception6//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 17mlir::DenseElementsAttr18convertStringAttrToDenseElementsAttr(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 35template <> 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 41template <> 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 convert55/// \param values the output parameter, the values array to fill56/// \param currentDims the shpae of tensor we're going to convert to57/// \param dimIndex the current dimension we're processing58/// \param currentIndex the current index in the values array59template <typename AttrTy, typename StorageTy>60void 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 102template <typename AttrTy, typename StorageTy>103mlir::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 118std::optional<mlir::Attribute>119lowerConstArrayAttr(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 149mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc,150 mlir::Type typ, const llvm::APInt &val) {151 return mlir::LLVM::ConstantOp::create(bld, loc, typ, val);152}153 154mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ,155 unsigned val) {156 return mlir::LLVM::ConstantOp::create(bld, loc, typ, val);157}158 159mlir::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 mlir::LLVM::ShlOp::create(bld, lhs.getLoc(), lhs, rhsVal);164}165 166mlir::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 mlir::LLVM::AShrOp::create(bld, lhs.getLoc(), lhs, rhsVal);171}172 173mlir::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 mlir::LLVM::AndOp::create(bld, lhs.getLoc(), lhs, rhsVal);177}178 179mlir::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 mlir::LLVM::LShrOp::create(bld, lhs.getLoc(), lhs, rhsVal);184}185