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
|
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "CIRGenBuilder.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/TypeSwitch.h"
using namespace clang::CIRGen;
mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc,
mlir::Value arrayPtr,
mlir::Type eltTy) {
const auto arrayPtrTy = mlir::cast<cir::PointerType>(arrayPtr.getType());
const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
if (arrayTy) {
const cir::PointerType flatPtrTy = getPointerTo(arrayTy.getElementType());
return create<cir::CastOp>(loc, flatPtrTy, cir::CastKind::array_to_ptrdecay,
arrayPtr);
}
assert(arrayPtrTy.getPointee() == eltTy &&
"flat pointee type must match original array element type");
return arrayPtr;
}
mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin,
mlir::Location arrayLocEnd,
mlir::Value arrayPtr,
mlir::Type eltTy, mlir::Value idx,
bool shouldDecay) {
mlir::Value basePtr = arrayPtr;
if (shouldDecay)
basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy);
const mlir::Type flatPtrTy = basePtr.getType();
return create<cir::PtrStrideOp>(arrayLocEnd, flatPtrTy, basePtr, idx);
}
cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc,
llvm::APSInt intVal) {
bool isSigned = intVal.isSigned();
unsigned width = intVal.getBitWidth();
cir::IntType t = isSigned ? getSIntNTy(width) : getUIntNTy(width);
return getConstInt(loc, t,
isSigned ? intVal.getSExtValue() : intVal.getZExtValue());
}
cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc,
llvm::APInt intVal) {
return getConstInt(loc, llvm::APSInt(intVal));
}
cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, mlir::Type t,
uint64_t c) {
assert(mlir::isa<cir::IntType>(t) && "expected cir::IntType");
return create<cir::ConstantOp>(loc, cir::IntAttr::get(t, c));
}
cir::ConstantOp
clang::CIRGen::CIRGenBuilderTy::getConstFP(mlir::Location loc, mlir::Type t,
llvm::APFloat fpVal) {
assert(mlir::isa<cir::FPTypeInterface>(t) && "expected floating point type");
return create<cir::ConstantOp>(loc, cir::FPAttr::get(t, fpVal));
}
void CIRGenBuilderTy::computeGlobalViewIndicesFromFlatOffset(
int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
llvm::SmallVectorImpl<int64_t> &indices) {
if (!offset)
return;
auto getIndexAndNewOffset =
[](int64_t offset, int64_t eltSize) -> std::pair<int64_t, int64_t> {
int64_t divRet = offset / eltSize;
if (divRet < 0)
divRet -= 1; // make sure offset is positive
int64_t modRet = offset - (divRet * eltSize);
return {divRet, modRet};
};
mlir::Type subType =
llvm::TypeSwitch<mlir::Type, mlir::Type>(ty)
.Case<cir::ArrayType>([&](auto arrayTy) {
int64_t eltSize = layout.getTypeAllocSize(arrayTy.getElementType());
const auto [index, newOffset] =
getIndexAndNewOffset(offset, eltSize);
indices.push_back(index);
offset = newOffset;
return arrayTy.getElementType();
})
.Case<cir::RecordType>([&](auto recordTy) {
ArrayRef<mlir::Type> elts = recordTy.getMembers();
int64_t pos = 0;
for (size_t i = 0; i < elts.size(); ++i) {
int64_t eltSize =
(int64_t)layout.getTypeAllocSize(elts[i]).getFixedValue();
unsigned alignMask = layout.getABITypeAlign(elts[i]).value() - 1;
if (recordTy.getPacked())
alignMask = 0;
// Union's fields have the same offset, so no need to change pos
// here, we just need to find eltSize that is greater then the
// required offset. The same is true for the similar union type
// check below
if (!recordTy.isUnion())
pos = (pos + alignMask) & ~alignMask;
assert(offset >= 0);
if (offset < pos + eltSize) {
indices.push_back(i);
offset -= pos;
return elts[i];
}
// No need to update pos here, see the comment above.
if (!recordTy.isUnion())
pos += eltSize;
}
llvm_unreachable("offset was not found within the record");
})
.Default([](mlir::Type otherTy) {
llvm_unreachable("unexpected type");
return otherTy; // Even though this is unreachable, we need to
// return a type to satisfy the return type of the
// lambda.
});
assert(subType);
computeGlobalViewIndicesFromFlatOffset(offset, subType, layout, indices);
}
cir::RecordType clang::CIRGen::CIRGenBuilderTy::getCompleteRecordType(
mlir::ArrayAttr fields, bool packed, bool padded, llvm::StringRef name) {
assert(!cir::MissingFeatures::astRecordDeclAttr());
llvm::SmallVector<mlir::Type> members;
members.reserve(fields.size());
llvm::transform(fields, std::back_inserter(members),
[](mlir::Attribute attr) {
return mlir::cast<mlir::TypedAttr>(attr).getType();
});
if (name.empty())
return getAnonRecordTy(members, packed, padded);
return getCompleteNamedRecordType(members, packed, padded, name);
}
mlir::Attribute clang::CIRGen::CIRGenBuilderTy::getConstRecordOrZeroAttr(
mlir::ArrayAttr arrayAttr, bool packed, bool padded, mlir::Type type) {
auto recordTy = mlir::cast_or_null<cir::RecordType>(type);
// Record type not specified: create anon record type from members.
if (!recordTy) {
recordTy = getCompleteRecordType(arrayAttr, packed, padded);
}
// Return zero or anonymous constant record.
const bool isZero = llvm::all_of(
arrayAttr, [&](mlir::Attribute a) { return isNullValue(a); });
if (isZero)
return cir::ZeroAttr::get(recordTy);
return cir::ConstRecordAttr::get(recordTy, arrayAttr);
}
// This can't be defined in Address.h because that file is included by
// CIRGenBuilder.h
Address Address::withElementType(CIRGenBuilderTy &builder,
mlir::Type elemTy) const {
assert(!cir::MissingFeatures::addressOffset());
assert(!cir::MissingFeatures::addressIsKnownNonNull());
assert(!cir::MissingFeatures::addressPointerAuthInfo());
return Address(builder.createPtrBitcast(getBasePointer(), elemTy), elemTy,
getAlignment());
}
|