xref: /freebsd/contrib/llvm-project/clang/lib/CIR/Lowering/LoweringHelpers.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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> &currentDims, 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