clang 24.0.0git
CIRGenBuilder.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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#include "CIRGenBuilder.h"
10#include "mlir/IR/BuiltinAttributes.h"
12#include "llvm/ADT/ArrayRef.h"
13#include "llvm/ADT/TypeSwitch.h"
14
15using namespace clang::CIRGen;
16
17mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc,
18 mlir::Value arrayPtr,
19 mlir::Type eltTy) {
20 const auto arrayPtrTy = mlir::cast<cir::PointerType>(arrayPtr.getType());
21 const auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
22
23 if (arrayTy) {
24 const cir::PointerType flatPtrTy =
25 getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace());
26 return cir::CastOp::create(*this, loc, flatPtrTy,
27 cir::CastKind::array_to_ptrdecay, arrayPtr);
28 }
29
30 assert(arrayPtrTy.getPointee() == eltTy &&
31 "flat pointee type must match original array element type");
32 return arrayPtr;
33}
34
35mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin,
36 mlir::Location arrayLocEnd,
37 mlir::Value arrayPtr,
38 mlir::Type eltTy, mlir::Value idx,
39 bool shouldDecay) {
40 auto arrayPtrTy = mlir::dyn_cast<cir::PointerType>(arrayPtr.getType());
41 assert(arrayPtrTy && "expected pointer type");
42 // If the array pointer is not decayed, emit a GetElementOp.
43 auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
44
45 assert(mlir::isa<cir::IntType>(idx.getType()) &&
47 mlir::cast<cir::IntType>(idx.getType()).getWidth()));
48
49 if (shouldDecay && arrayTy && arrayTy == eltTy) {
50 auto eltPtrTy =
51 getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace());
52 return cir::GetElementOp::create(*this, arrayLocEnd, eltPtrTy, arrayPtr,
53 idx);
54 }
55
56 // If we don't have sufficient type information, emit a PtrStrideOp.
57 mlir::Value basePtr = arrayPtr;
58 if (shouldDecay)
59 basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy);
60 const mlir::Type flatPtrTy = basePtr.getType();
61 return cir::PtrStrideOp::create(*this, arrayLocEnd, flatPtrTy, basePtr, idx);
62}
63
64cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc,
65 llvm::APSInt intVal) {
66 bool isSigned = intVal.isSigned();
67 unsigned width = intVal.getBitWidth();
68 cir::IntType t = isSigned ? getSIntNTy(width) : getUIntNTy(width);
69 return getConstInt(loc, t,
70 isSigned ? intVal.getSExtValue() : intVal.getZExtValue());
71}
72
73cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc,
74 llvm::APInt intVal,
75 bool isUnsigned) {
76 return getConstInt(loc, llvm::APSInt(intVal, isUnsigned));
77}
78
79cir::ConstantOp CIRGenBuilderTy::getConstInt(mlir::Location loc, mlir::Type t,
80 uint64_t c) {
81 assert(mlir::isa<cir::IntType>(t) && "expected cir::IntType");
82 return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(t, c));
83}
84
85cir::ConstantOp
86clang::CIRGen::CIRGenBuilderTy::getConstFP(mlir::Location loc, mlir::Type t,
87 llvm::APFloat fpVal) {
88 assert(mlir::isa<cir::FPTypeInterface>(t) && "expected floating point type");
89 return cir::ConstantOp::create(*this, loc, cir::FPAttr::get(t, fpVal));
90}
91
93 int64_t offset, mlir::Type ty, cir::CIRDataLayout layout,
95 if (!offset)
96 return true;
97
98 // Compute floor-division and a non-negative remainder. A negative flat
99 // offset (e.g. from a pointer one element before the start of an array)
100 // must translate to a negative array index with a non-negative remainder
101 // so that the recursive call can descend into the element type without
102 // a negative offset flowing into the record case below.
103 auto getIndexAndNewOffset =
104 [](int64_t offset, int64_t eltSize) -> std::pair<int64_t, int64_t> {
105 int64_t divRet = offset / eltSize;
106 int64_t modRet = offset % eltSize;
107 if (modRet < 0) {
108 divRet -= 1;
109 modRet += eltSize;
110 }
111 return {divRet, modRet};
112 };
113
114 mlir::Type subType =
115 llvm::TypeSwitch<mlir::Type, mlir::Type>(ty)
116 .Case<cir::ArrayType>([&](auto arrayTy) {
117 int64_t eltSize = layout.getTypeAllocSize(arrayTy.getElementType());
118 const auto [index, newOffset] =
119 getIndexAndNewOffset(offset, eltSize);
120 indices.push_back(index);
121 offset = newOffset;
122 return arrayTy.getElementType();
123 })
124 .Case<cir::RecordType>([&](auto recordTy) -> mlir::Type {
125 // A record can only be entered from its start. An offset before
126 // the record, or at or past its end, designates an address outside
127 // of the object, which no member index can reach.
128 if (offset < 0)
129 return {};
130 ArrayRef<mlir::Type> elts = recordTy.getMembers();
131 int64_t pos = 0;
132 for (size_t i = 0; i < elts.size(); ++i) {
133 int64_t eltSize =
134 (int64_t)layout.getTypeAllocSize(elts[i]).getFixedValue();
135 unsigned alignMask = layout.getABITypeAlign(elts[i]).value() - 1;
136 if (recordTy.getPacked())
137 alignMask = 0;
138 // Union's fields have the same offset, so no need to change pos
139 // here, we just need to find eltSize that is greater then the
140 // required offset. The same is true for the similar union type
141 // check below
142 if (!recordTy.isUnion())
143 pos = (pos + alignMask) & ~alignMask;
144 if (offset < pos + eltSize) {
145 indices.push_back(i);
146 offset -= pos;
147 return elts[i];
148 }
149 // No need to update pos here, see the comment above.
150 if (!recordTy.isUnion())
151 pos += eltSize;
152 }
153 return {};
154 })
155 .Case<cir::IntType>([&](cir::IntType intTy) -> mlir::Type {
156 // Integer element type: the offset is a flat element count.
157 // This covers pointer arithmetic through a plain integer base,
158 // e.g. a char* GlobalViewAttr whose pointee type is !s8i rather
159 // than an array — the GEP is getelementptr i8, ptr @sym, i64 N.
160 int64_t eltSize =
161 (int64_t)layout.getTypeAllocSize(intTy).getFixedValue();
162 assert(eltSize > 0 && "element size must be positive");
163 const auto [index, newOffset] =
164 getIndexAndNewOffset(offset, eltSize);
165 // An integer has no subelements, so an offset into the middle of
166 // one can't be indexed.
167 if (newOffset)
168 return {};
169 indices.push_back(index);
170 offset = newOffset;
171 return intTy;
172 })
173 .Default([](mlir::Type) -> mlir::Type { return {}; });
174
175 if (!subType)
176 return false;
177
178 return computeGlobalViewIndicesFromFlatOffset(offset, subType, layout,
179 indices);
180}
181
183 const cir::CIRDataLayout &layout, mlir::Type ty,
184 llvm::ArrayRef<int64_t> indices) {
185 int64_t offset = 0;
186 for (int64_t idx : indices) {
187 if (auto recordTy = dyn_cast<cir::RecordType>(ty)) {
188 offset += recordTy.getElementOffset(layout.layout, idx);
189 assert(idx < (int64_t)recordTy.getMembers().size());
190 ty = recordTy.getMembers()[idx];
191 } else if (auto arrayTy = dyn_cast<cir::ArrayType>(ty)) {
192 ty = arrayTy.getElementType();
193 offset += layout.getTypeAllocSize(ty) * idx;
194 } else if (mlir::isa<cir::IntType>(ty)) {
195 // Integer element type: the index is a flat element count.
196 offset += (int64_t)layout.getTypeAllocSize(ty).getFixedValue() * idx;
197 } else {
198 llvm_unreachable("unexpected type");
199 }
200 }
201 return offset;
202}
203
205 mlir::ArrayAttr arrayAttr, cir::RecordType recordTy) {
206 // Return zero or anonymous constant record.
207 const bool isZero = llvm::all_of(
208 arrayAttr, [&](mlir::Attribute a) { return isNullValue(a); });
209 if (isZero)
210 return cir::ZeroAttr::get(recordTy);
211 return cir::ConstRecordAttr::get(recordTy, arrayAttr);
212}
213
214// This can't be defined in Address.h because that file is included by
215// CIRGenBuilder.h
217 mlir::Type elemTy) const {
221
222 return Address(builder.createPtrBitcast(getBasePointer(), elemTy), elemTy,
223 getAlignment());
224}
static bool isUnsigned(SValBuilder &SVB, NonLoc Value)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::DataLayout layout
llvm::TypeSize getTypeAllocSize(mlir::Type ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
llvm::Align getABITypeAlign(mlir::Type ty) const
C++ view class that accepts both !cir.struct and !cir.union types.
Definition CIRTypes.h:149
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
Definition Address.h:138
mlir::Value getBasePointer() const
Definition Address.h:103
Address(std::nullptr_t)
Definition Address.h:46
cir::IntType getSIntNTy(int n)
mlir::Attribute getConstRecordOrZeroAttr(mlir::ArrayAttr arrayAttr, cir::RecordType recordTy)
mlir::Value maybeBuildArrayDecay(mlir::Location loc, mlir::Value arrayPtr, mlir::Type eltTy)
Returns a decayed pointer to the first element of the array pointed to by arrayPtr.
cir::ConstantOp getConstFP(mlir::Location loc, mlir::Type t, llvm::APFloat fpVal)
uint64_t computeOffsetFromGlobalViewIndices(const cir::CIRDataLayout &layout, mlir::Type ty, llvm::ArrayRef< int64_t > indices)
bool isNullValue(mlir::Attribute attr) const
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::IntType getUIntNTy(int n)
mlir::Value getArrayElement(mlir::Location arrayLocBegin, mlir::Location arrayLocEnd, mlir::Value arrayPtr, mlir::Type eltTy, mlir::Value idx, bool shouldDecay)
Create a cir.ptr_stride operation to get access to an array element.
bool computeGlobalViewIndicesFromFlatOffset(int64_t offset, mlir::Type ty, cir::CIRDataLayout layout, llvm::SmallVectorImpl< int64_t > &indices)
bool isValidFundamentalIntWidth(unsigned width)
@ Default
Set to the current date and time.
static bool addressPointerAuthInfo()
static bool addressOffset()
static bool addressIsKnownNonNull()