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