xref: /freebsd/contrib/llvm-project/clang/lib/CIR/Lowering/LoweringHelpers.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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
convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,mlir::Type type)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 
getZeroInitFromType(mlir::Type ty)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 
getZeroInitFromType(mlir::Type ty)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>
convertToDenseElementsAttrImpl(cir::ConstArrayAttr attr,llvm::SmallVectorImpl<StorageTy> & values,const llvm::SmallVectorImpl<int64_t> & currentDims,int64_t dimIndex,int64_t currentIndex)60 void convertToDenseElementsAttrImpl(
61     cir::ConstArrayAttr attr, llvm::SmallVectorImpl<StorageTy> &values,
62     const llvm::SmallVectorImpl<int64_t> &currentDims, 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>
convertToDenseElementsAttr(cir::ConstArrayAttr attr,const llvm::SmallVectorImpl<int64_t> & dims,mlir::Type elementType,mlir::Type convertedElementType)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>
lowerConstArrayAttr(cir::ConstArrayAttr constArr,const mlir::TypeConverter * converter)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 
getConstAPInt(mlir::OpBuilder & bld,mlir::Location loc,mlir::Type typ,const llvm::APInt & val)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 
getConst(mlir::OpBuilder & bld,mlir::Location loc,mlir::Type typ,unsigned val)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 
createShL(mlir::OpBuilder & bld,mlir::Value lhs,unsigned rhs)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 
createAShR(mlir::OpBuilder & bld,mlir::Value lhs,unsigned rhs)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 
createAnd(mlir::OpBuilder & bld,mlir::Value lhs,const llvm::APInt & rhs)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 
createLShR(mlir::OpBuilder & bld,mlir::Value lhs,unsigned rhs)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