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