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 "clang/CIR/MissingFeatures.h"
15
16mlir::DenseElementsAttr
17convertStringAttrToDenseElementsAttr(cir::ConstArrayAttr attr,
18 mlir::Type type) {
19 auto values = llvm::SmallVector<mlir::APInt, 8>{};
20 const auto stringAttr = mlir::cast<mlir::StringAttr>(attr.getElts());
21
22 for (const char element : stringAttr)
23 values.push_back({8, (uint64_t)element});
24
25 const auto arrayTy = mlir::cast<cir::ArrayType>(attr.getType());
26 if (arrayTy.getSize() != stringAttr.size())
27 assert(!cir::MissingFeatures::stringTypeWithDifferentArraySize());
28
29 return mlir::DenseElementsAttr::get(
30 mlir::RankedTensorType::get({(int64_t)values.size()}, type),
31 llvm::ArrayRef(values));
32}
33
34template <> mlir::APInt getZeroInitFromType(mlir::Type ty) {
35 assert(mlir::isa<cir::IntType>(ty) && "expected int type");
36 const auto intTy = mlir::cast<cir::IntType>(ty);
37 return mlir::APInt::getZero(intTy.getWidth());
38}
39
40template <> mlir::APFloat getZeroInitFromType(mlir::Type ty) {
41 assert((mlir::isa<cir::SingleType, cir::DoubleType>(ty)) &&
42 "only float and double supported");
43
44 if (ty.isF32() || mlir::isa<cir::SingleType>(ty))
45 return mlir::APFloat(0.f);
46
47 if (ty.isF64() || mlir::isa<cir::DoubleType>(ty))
48 return mlir::APFloat(0.0);
49
50 llvm_unreachable("NYI");
51}
52
53/// \param attr the ConstArrayAttr to convert
54/// \param values the output parameter, the values array to fill
55/// \param currentDims the shpae of tensor we're going to convert to
56/// \param dimIndex the current dimension we're processing
57/// \param currentIndex the current index in the values array
58template <typename AttrTy, typename StorageTy>
59void convertToDenseElementsAttrImpl(
60 cir::ConstArrayAttr attr, llvm::SmallVectorImpl<StorageTy> &values,
61 const llvm::SmallVectorImpl<int64_t> &currentDims, int64_t dimIndex,
62 int64_t currentIndex) {
63 if (auto stringAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) {
64 if (auto arrayType = mlir::dyn_cast<cir::ArrayType>(attr.getType())) {
65 for (auto element : stringAttr) {
66 auto intAttr = cir::IntAttr::get(arrayType.getElementType(), element);
67 values[currentIndex++] = mlir::dyn_cast<AttrTy>(intAttr).getValue();
68 }
69 return;
70 }
71 }
72
73 dimIndex++;
74 std::size_t elementsSizeInCurrentDim = 1;
75 for (std::size_t i = dimIndex; i < currentDims.size(); i++)
76 elementsSizeInCurrentDim *= currentDims[i];
77
78 auto arrayAttr = mlir::cast<mlir::ArrayAttr>(attr.getElts());
79 for (auto eltAttr : arrayAttr) {
80 if (auto valueAttr = mlir::dyn_cast<AttrTy>(eltAttr)) {
81 values[currentIndex++] = valueAttr.getValue();
82 continue;
83 }
84
85 if (auto subArrayAttr = mlir::dyn_cast<cir::ConstArrayAttr>(eltAttr)) {
86 convertToDenseElementsAttrImpl<AttrTy>(subArrayAttr, values, currentDims,
87 dimIndex, currentIndex);
88 currentIndex += elementsSizeInCurrentDim;
89 continue;
90 }
91
92 if (mlir::isa<cir::ZeroAttr, cir::UndefAttr>(eltAttr)) {
93 currentIndex += elementsSizeInCurrentDim;
94 continue;
95 }
96
97 llvm_unreachable("unknown element in ConstArrayAttr");
98 }
99}
100
101template <typename AttrTy, typename StorageTy>
102mlir::DenseElementsAttr convertToDenseElementsAttr(
103 cir::ConstArrayAttr attr, const llvm::SmallVectorImpl<int64_t> &dims,
104 mlir::Type elementType, mlir::Type convertedElementType) {
105 unsigned vectorSize = 1;
106 for (auto dim : dims)
107 vectorSize *= dim;
108 auto values = llvm::SmallVector<StorageTy, 8>(
109 vectorSize, getZeroInitFromType<StorageTy>(elementType));
110 convertToDenseElementsAttrImpl<AttrTy>(attr, values, dims, /*currentDim=*/0,
111 /*initialIndex=*/0);
112 return mlir::DenseElementsAttr::get(
113 mlir::RankedTensorType::get(dims, convertedElementType),
114 llvm::ArrayRef(values));
115}
116
117std::optional<mlir::Attribute>
118lowerConstArrayAttr(cir::ConstArrayAttr constArr,
119 const mlir::TypeConverter *converter) {
120 // Ensure ConstArrayAttr has a type.
121 const auto typedConstArr = mlir::cast<mlir::TypedAttr>(constArr);
122
123 // Ensure ConstArrayAttr type is a ArrayType.
124 const auto cirArrayType = mlir::cast<cir::ArrayType>(typedConstArr.getType());
125
126 // Is a ConstArrayAttr with an cir::ArrayType: fetch element type.
127 mlir::Type type = cirArrayType;
128 auto dims = llvm::SmallVector<int64_t, 2>{};
129 while (auto arrayType = mlir::dyn_cast<cir::ArrayType>(type)) {
130 dims.push_back(Elt: arrayType.getSize());
131 type = arrayType.getElementType();
132 }
133
134 if (mlir::isa<mlir::StringAttr>(constArr.getElts()))
135 return convertStringAttrToDenseElementsAttr(constArr,
136 converter->convertType(type));
137 if (mlir::isa<cir::IntType>(type))
138 return convertToDenseElementsAttr<cir::IntAttr, mlir::APInt>(
139 constArr, dims, type, converter->convertType(type));
140
141 if (mlir::isa<cir::CIRFPTypeInterface>(type))
142 return convertToDenseElementsAttr<cir::FPAttr, mlir::APFloat>(
143 constArr, dims, type, converter->convertType(type));
144
145 return std::nullopt;
146}
147

source code of clang/lib/CIR/Lowering/LoweringHelpers.cpp