Skip to content

Commit 7032157

Browse files
committed
Update base for Update on "[CIR][CIRGen][Bugfix] Update unions to track all members"
This diverges from the original codegen by tracking all members of a union, instead of just the largest one. This is necessary to support type-checking at the MLIR level when accessing union members. It also preserves more information about the source code, which might be useful. Fixes #224 [ghstack-poisoned]
2 parents 02242da + 2fae9b7 commit 7032157

File tree

12 files changed

+188
-38
lines changed

12 files changed

+188
-38
lines changed

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,25 @@ def OptNoneAttr : CIRUnitAttr<"OptNone", "optnone"> {
452452
let storageType = [{ OptNoneAttr }];
453453
}
454454

455+
def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> {
456+
let summary = "Indicates a function is a global constructor.";
457+
let description = [{
458+
Describing a global constructor with an optional priority.
459+
}];
460+
let parameters = (ins "StringAttr":$name,
461+
OptionalParameter<"std::optional<int>">:$priority);
462+
let assemblyFormat = [{
463+
`<`
464+
$name
465+
(`,` $priority^)?
466+
`>`
467+
}];
468+
let builders = [
469+
AttrBuilder<(ins "StringRef":$name,
470+
CArg<"std::optional<int>", "{}">:$priority), [{
471+
return $_get($_ctxt, StringAttr::get($_ctxt, name), priority);
472+
}]>
473+
];
474+
let skipDefaultBuilders = 1;
475+
}
455476
#endif // MLIR_CIR_DIALECT_CIR_ATTRS

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "CIRGenTypeCache.h"
1414
#include "UnimplementedFeatureGuarding.h"
1515

16+
#include "clang/AST/Decl.h"
1617
#include "clang/AST/Type.h"
1718
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
1819
#include "clang/CIR/Dialect/IR/CIRDialect.h"
@@ -190,8 +191,7 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
190191
}
191192

192193
if (!ty)
193-
ty = getAnonStructTy(mlir::cir::StructType::Struct, members,
194-
/*body=*/true, packed);
194+
ty = getAnonStructTy(members, /*body=*/true, packed);
195195

196196
auto sTy = ty.dyn_cast<mlir::cir::StructType>();
197197
assert(sTy && "expected struct type");
@@ -381,10 +381,9 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
381381

382382
/// Get a CIR anonymous struct type.
383383
mlir::cir::StructType
384-
getAnonStructTy(mlir::cir::StructType::RecordKind kind,
385-
llvm::ArrayRef<mlir::Type> members, bool body,
384+
getAnonStructTy(llvm::ArrayRef<mlir::Type> members, bool body,
386385
bool packed = false, const clang::RecordDecl *ast = nullptr) {
387-
return getStructTy(kind, members, "", body, packed, ast);
386+
return getStructTy(members, "", body, packed, ast);
388387
}
389388

390389
/// Get a CIR record kind from a AST declaration tag.
@@ -405,14 +404,16 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
405404
}
406405

407406
/// Get a CIR named struct type.
408-
mlir::cir::StructType getStructTy(mlir::cir::StructType::RecordKind kind,
409-
llvm::ArrayRef<mlir::Type> members,
407+
mlir::cir::StructType getStructTy(llvm::ArrayRef<mlir::Type> members,
410408
llvm::StringRef name, bool body,
411409
bool packed, const clang::RecordDecl *ast) {
412410
const auto nameAttr = getStringAttr(name);
413411
std::optional<mlir::cir::ASTRecordDeclAttr> astAttr = std::nullopt;
414-
if (ast)
412+
auto kind = mlir::cir::StructType::RecordKind::Struct;
413+
if (ast) {
415414
astAttr = getAttr<mlir::cir::ASTRecordDeclAttr>(ast);
415+
kind = getRecordKind(ast->getTagKind());
416+
}
416417
return mlir::cir::StructType::get(getContext(), members, nameAttr, body,
417418
packed, kind, astAttr);
418419
}

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,34 +1135,37 @@ static mlir::Value buildArrayAccessOp(mlir::OpBuilder &builder,
11351135
mlir::Location arrayLocBegin,
11361136
mlir::Location arrayLocEnd,
11371137
mlir::Value arrayPtr, mlir::Type eltTy,
1138-
mlir::Value idx) {
1139-
mlir::Value basePtr =
1140-
maybeBuildArrayDecay(builder, arrayLocBegin, arrayPtr, eltTy);
1138+
mlir::Value idx, bool shouldDecay) {
1139+
mlir::Value basePtr = arrayPtr;
1140+
if (shouldDecay)
1141+
basePtr = maybeBuildArrayDecay(builder, arrayLocBegin, arrayPtr, eltTy);
11411142
mlir::Type flatPtrTy = basePtr.getType();
11421143

11431144
return builder.create<mlir::cir::PtrStrideOp>(arrayLocEnd, flatPtrTy, basePtr,
11441145
idx);
11451146
}
11461147

1147-
static mlir::Value buildArraySubscriptPtr(
1148-
CIRGenFunction &CGF, mlir::Location beginLoc, mlir::Location endLoc,
1149-
mlir::Value ptr, mlir::Type eltTy, ArrayRef<mlir::Value> indices,
1150-
bool inbounds, bool signedIndices, const llvm::Twine &name = "arrayidx") {
1148+
static mlir::Value
1149+
buildArraySubscriptPtr(CIRGenFunction &CGF, mlir::Location beginLoc,
1150+
mlir::Location endLoc, mlir::Value ptr, mlir::Type eltTy,
1151+
ArrayRef<mlir::Value> indices, bool inbounds,
1152+
bool signedIndices, bool shouldDecay,
1153+
const llvm::Twine &name = "arrayidx") {
11511154
assert(indices.size() == 1 && "cannot handle multiple indices yet");
11521155
auto idx = indices.back();
11531156
auto &CGM = CGF.getCIRGenModule();
11541157
// TODO(cir): LLVM codegen emits in bound gep check here, is there anything
11551158
// that would enhance tracking this later in CIR?
11561159
if (inbounds)
11571160
assert(!UnimplementedFeature::emitCheckedInBoundsGEP() && "NYI");
1158-
return buildArrayAccessOp(CGM.getBuilder(), beginLoc, endLoc, ptr, eltTy,
1159-
idx);
1161+
return buildArrayAccessOp(CGM.getBuilder(), beginLoc, endLoc, ptr, eltTy, idx,
1162+
shouldDecay);
11601163
}
11611164

11621165
static Address buildArraySubscriptPtr(
11631166
CIRGenFunction &CGF, mlir::Location beginLoc, mlir::Location endLoc,
11641167
Address addr, ArrayRef<mlir::Value> indices, QualType eltType,
1165-
bool inbounds, bool signedIndices, mlir::Location loc,
1168+
bool inbounds, bool signedIndices, mlir::Location loc, bool shouldDecay,
11661169
QualType *arrayType = nullptr, const Expr *Base = nullptr,
11671170
const llvm::Twine &name = "arrayidx") {
11681171
// Determine the element size of the statically-sized base. This is
@@ -1182,7 +1185,7 @@ static Address buildArraySubscriptPtr(
11821185
(!CGF.IsInPreservedAIRegion && !isPreserveAIArrayBase(CGF, Base))) {
11831186
eltPtr = buildArraySubscriptPtr(CGF, beginLoc, endLoc, addr.getPointer(),
11841187
addr.getElementType(), indices, inbounds,
1185-
signedIndices, name);
1188+
signedIndices, shouldDecay, name);
11861189
} else {
11871190
// assert(!UnimplementedFeature::generateDebugInfo() && "NYI");
11881191
// assert(indices.size() == 1 && "cannot handle multiple indices yet");
@@ -1272,7 +1275,8 @@ LValue CIRGenFunction::buildArraySubscriptExpr(const ArraySubscriptExpr *E,
12721275
*this, CGM.getLoc(Array->getBeginLoc()), CGM.getLoc(Array->getEndLoc()),
12731276
ArrayLV.getAddress(), {Idx}, E->getType(),
12741277
!getLangOpts().isSignedOverflowDefined(), SignedIndices,
1275-
CGM.getLoc(E->getExprLoc()), &arrayType, E->getBase());
1278+
CGM.getLoc(E->getExprLoc()), /*shouldDecay=*/true, &arrayType,
1279+
E->getBase());
12761280
EltBaseInfo = ArrayLV.getBaseInfo();
12771281
// TODO(cir): EltTBAAInfo
12781282
assert(!UnimplementedFeature::tbaa() && "TBAA is NYI");
@@ -1286,7 +1290,8 @@ LValue CIRGenFunction::buildArraySubscriptExpr(const ArraySubscriptExpr *E,
12861290
Addr = buildArraySubscriptPtr(
12871291
*this, CGM.getLoc(E->getBeginLoc()), CGM.getLoc(E->getEndLoc()), Addr,
12881292
Idx, E->getType(), !getLangOpts().isSignedOverflowDefined(),
1289-
SignedIndices, CGM.getLoc(E->getExprLoc()), &ptrType, E->getBase());
1293+
SignedIndices, CGM.getLoc(E->getExprLoc()), /*shouldDecay=*/false,
1294+
&ptrType, E->getBase());
12901295
}
12911296

12921297
LValue LV = LValue::makeAddr(Addr, E->getType(), EltBaseInfo);

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,8 @@ mlir::Type CIRGenTypes::convertRecordDeclType(const clang::RecordDecl *RD) {
166166

167167
// Handle forward decl / incomplete types.
168168
if (!entry) {
169-
auto recordKind = Builder.getRecordKind(RD->getTagKind());
170169
auto name = getRecordTypeName(RD, "");
171-
entry = Builder.getStructTy(recordKind, {}, name, /*body=*/false,
172-
/*packed=*/false, RD);
170+
entry = Builder.getStructTy({}, name, /*body=*/false, /*packed=*/false, RD);
173171
recordDeclTypes[key] = entry;
174172
}
175173

clang/lib/CIR/CodeGen/CIRGenVTables.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ mlir::Type CIRGenVTables::getVTableType(const VTableLayout &layout) {
5959

6060
// FIXME(cir): should VTableLayout be encoded like we do for some
6161
// AST nodes?
62-
return CGM.getBuilder().getAnonStructTy(mlir::cir::StructType::Struct, tys,
63-
/*body=*/true);
62+
return CGM.getBuilder().getAnonStructTy(tys, /*body=*/true);
6463
}
6564

6665
/// At this point in the translation unit, does it appear that can we

clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,7 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *D,
580580
builder.astRecordLayout.getSize()) {
581581
CIRRecordLowering baseBuilder(*this, D, /*Packed=*/builder.isPacked);
582582
auto baseIdentifier = getRecordTypeName(D, ".base");
583-
auto recordKind = Builder.getRecordKind(D->getTagKind());
584-
*BaseTy = Builder.getStructTy(recordKind, baseBuilder.fieldTypes,
585-
baseIdentifier,
583+
*BaseTy = Builder.getStructTy(baseBuilder.fieldTypes, baseIdentifier,
586584
/*body=*/true, /*packed=*/false, D);
587585
// TODO(cir): add something like addRecordTypeName
588586

@@ -596,8 +594,7 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *D,
596594
// Fill in the struct *after* computing the base type. Filling in the body
597595
// signifies that the type is no longer opaque and record layout is complete,
598596
// but we may need to recursively layout D while laying D out as a base type.
599-
*Ty = Builder.getStructTy(Builder.getRecordKind(D->getTagKind()),
600-
builder.fieldTypes, getRecordTypeName(D, ""),
597+
*Ty = Builder.getStructTy(builder.fieldTypes, getRecordTypeName(D, ""),
601598
/*body=*/true, /*packed=*/false, D);
602599

603600
auto RL = std::make_unique<CIRGenRecordLayout>(

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,9 +2237,9 @@ LogicalResult GetMemberOp::verify() {
22372237
if (recordTy.getMembers().size() <= getIndex())
22382238
return emitError() << "member index out of bounds";
22392239

2240-
// FIXME(cir): Member type check is disabled for classes since there is a bug
2241-
// in codegen index for classes.
2242-
if (!recordTy.isClass() &&
2240+
// FIXME(cir): Member type check is disabled for classes and incomplete types
2241+
// as the codegen for these still need to be patched.
2242+
if (!recordTy.isClass() && !recordTy.getBody() &&
22432243
recordTy.getMembers()[getIndex()] != getResultTy().getPointee())
22442244
return emitError() << "member type mismatch";
22452245

clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "PassDetail.h"
1010
#include "mlir/Dialect/Func/IR/FuncOps.h"
11+
#include "mlir/IR/BuiltinAttributes.h"
1112
#include "mlir/IR/Region.h"
1213
#include "clang/AST/ASTContext.h"
1314
#include "clang/AST/Mangle.h"
@@ -125,6 +126,8 @@ void LoweringPreparePass::lowerGlobalOp(GlobalOp op) {
125126
ctorRegion.getBlocks().clear();
126127

127128
// Add a function call to the variable initialization function.
129+
assert(!op.getAst()->getAstDecl()->getAttr<clang::InitPriorityAttr>() &&
130+
"custom initialization priority NYI");
128131
dynamicInitializers.push_back(f);
129132
}
130133
}
@@ -133,6 +136,17 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
133136
if (dynamicInitializers.empty())
134137
return;
135138

139+
SmallVector<mlir::Attribute, 4> attrs;
140+
for (auto &f : dynamicInitializers) {
141+
// TODO: handle globals with a user-specified initialzation priority.
142+
auto ctorAttr =
143+
mlir::cir::GlobalCtorAttr::get(&getContext(), f.getName());
144+
attrs.push_back(ctorAttr);
145+
}
146+
147+
theModule->setAttr("cir.globalCtors",
148+
mlir::ArrayAttr::get(&getContext(), attrs));
149+
136150
SmallString<256> fnName;
137151
// Include the filename in the symbol name. Including "sub_" matches gcc
138152
// and makes sure these symbols appear lexicographically behind the symbols
@@ -161,9 +175,9 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
161175
builder.getContext(), mlir::cir::GlobalLinkageKind::ExternalLinkage));
162176
mlir::SymbolTable::setSymbolVisibility(
163177
f, mlir::SymbolTable::Visibility::Private);
164-
mlir::NamedAttrList attrs;
178+
mlir::NamedAttrList extraAttrs;
165179
f.setExtraAttrsAttr(mlir::cir::ExtraFuncAttributesAttr::get(
166-
builder.getContext(), attrs.getDictionary(builder.getContext())));
180+
builder.getContext(), extraAttrs.getDictionary(builder.getContext())));
167181

168182
builder.setInsertionPointToStart(f.addEntryBlock());
169183
for (auto &f : dynamicInitializers) {

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "llvm/ADT/STLExtras.h"
5858
#include "llvm/ADT/Sequence.h"
5959
#include "llvm/ADT/SmallVector.h"
60+
#include "llvm/ADT/StringRef.h"
6061
#include "llvm/IR/DebugInfoMetadata.h"
6162
#include "llvm/IR/DerivedTypes.h"
6263
#include "llvm/Support/Casting.h"
@@ -1829,6 +1830,79 @@ mlir::LLVMTypeConverter prepareTypeConverter(mlir::MLIRContext *ctx) {
18291830
}
18301831
} // namespace
18311832

1833+
static void buildCtorList(mlir::ModuleOp module) {
1834+
llvm::SmallVector<std::pair<StringRef, int>, 2> globalCtors;
1835+
for (auto namedAttr : module->getAttrs()) {
1836+
if (namedAttr.getName() == "cir.globalCtors") {
1837+
for (auto attr : namedAttr.getValue().cast<mlir::ArrayAttr>()) {
1838+
assert(attr.isa<mlir::cir::GlobalCtorAttr>() &&
1839+
"must be a GlobalCtorAttr");
1840+
if (auto ctorAttr = attr.cast<mlir::cir::GlobalCtorAttr>()) {
1841+
// default priority is 65536
1842+
int priority = 65536;
1843+
if (ctorAttr.getPriority())
1844+
priority = *ctorAttr.getPriority();
1845+
globalCtors.emplace_back(ctorAttr.getName(), priority);
1846+
}
1847+
}
1848+
break;
1849+
}
1850+
}
1851+
1852+
if (globalCtors.empty())
1853+
return;
1854+
1855+
mlir::OpBuilder builder(module.getContext());
1856+
builder.setInsertionPointToEnd(&module.getBodyRegion().back());
1857+
1858+
// Create a global array llvm.global_ctors with element type of
1859+
// struct { i32, ptr, ptr }
1860+
auto CtorPFTy = mlir::LLVM::LLVMPointerType::get(builder.getContext());
1861+
llvm::SmallVector<mlir::Type> CtorStructFields;
1862+
CtorStructFields.push_back(builder.getI32Type());
1863+
CtorStructFields.push_back(CtorPFTy);
1864+
CtorStructFields.push_back(CtorPFTy);
1865+
1866+
auto CtorStructTy = mlir::LLVM::LLVMStructType::getLiteral(
1867+
builder.getContext(), CtorStructFields);
1868+
auto CtorStructArrayTy =
1869+
mlir::LLVM::LLVMArrayType::get(CtorStructTy, globalCtors.size());
1870+
1871+
auto loc = module.getLoc();
1872+
auto newGlobalOp = builder.create<mlir::LLVM::GlobalOp>(
1873+
loc, CtorStructArrayTy, true, mlir::LLVM::Linkage::Appending,
1874+
"llvm.global_ctors", mlir::Attribute());
1875+
1876+
newGlobalOp.getRegion().push_back(new mlir::Block());
1877+
builder.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
1878+
1879+
mlir::Value result = builder.create<mlir::LLVM::UndefOp>(
1880+
loc, CtorStructArrayTy);
1881+
1882+
for (uint64_t I = 0; I < globalCtors.size(); I++) {
1883+
auto fn = globalCtors[I];
1884+
mlir::Value structInit =
1885+
builder.create<mlir::LLVM::UndefOp>(loc, CtorStructTy);
1886+
mlir::Value initPriority =
1887+
builder.create<mlir::LLVM::ConstantOp>(loc, CtorStructFields[0], fn.second);
1888+
mlir::Value initFuncAddr = builder.create<mlir::LLVM::AddressOfOp>(
1889+
loc, CtorStructFields[1], fn.first);
1890+
mlir::Value initAssociate =
1891+
builder.create<mlir::LLVM::NullOp>(loc, CtorStructFields[2]);
1892+
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
1893+
initPriority, 0);
1894+
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
1895+
initFuncAddr, 1);
1896+
// TODO: handle associated data for initializers.
1897+
structInit = builder.create<mlir::LLVM::InsertValueOp>(loc, structInit,
1898+
initAssociate, 2);
1899+
result =
1900+
builder.create<mlir::LLVM::InsertValueOp>(loc, result, structInit, I);
1901+
}
1902+
1903+
builder.create<mlir::LLVM::ReturnOp>(loc, result);
1904+
}
1905+
18321906
void ConvertCIRToLLVMPass::runOnOperation() {
18331907
auto module = getOperation();
18341908

@@ -1870,6 +1944,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {
18701944

18711945
if (failed(applyPartialConversion(module, target, std::move(patterns))))
18721946
signalPassFailure();
1947+
1948+
// Emit the llvm.global_ctors array.
1949+
buildCtorList(module);
18731950
}
18741951

18751952
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {

clang/test/CIR/CodeGen/array.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,22 @@ struct S {
7171
int i;
7272
} arr[3] = {{1}};
7373
// CHECK: cir.global external @arr = #cir.const_array<[#cir.const_struct<{#cir.int<1> : !s32i}> : !ty_22S22, #cir.zero : !ty_22S22, #cir.zero : !ty_22S22]> : !cir.array<!ty_22S22 x 3>
74+
75+
void testPointerDecaySubscriptAccess(int arr[]) {
76+
// CHECK: cir.func @{{.+}}testPointerDecaySubscriptAccess
77+
arr[1];
78+
// CHECK: %[[#BASE:]] = cir.load %{{.+}} : cir.ptr <!cir.ptr<!s32i>>, !cir.ptr<!s32i>
79+
// CHECK: %[[#DIM1:]] = cir.const(#cir.int<1> : !s32i) : !s32i
80+
// CHECK: cir.ptr_stride(%[[#BASE]] : !cir.ptr<!s32i>, %[[#DIM1]] : !s32i), !cir.ptr<!s32i>
81+
}
82+
83+
void testPointerDecayedArrayMultiDimSubscriptAccess(int arr[][3]) {
84+
// CHECK: cir.func @{{.+}}testPointerDecayedArrayMultiDimSubscriptAccess
85+
arr[1][2];
86+
// CHECK: %[[#V1:]] = cir.load %{{.+}} : cir.ptr <!cir.ptr<!cir.array<!s32i x 3>>>, !cir.ptr<!cir.array<!s32i x 3>>
87+
// CHECK: %[[#V2:]] = cir.const(#cir.int<1> : !s32i) : !s32i
88+
// CHECK: %[[#V3:]] = cir.ptr_stride(%[[#V1]] : !cir.ptr<!cir.array<!s32i x 3>>, %[[#V2]] : !s32i), !cir.ptr<!cir.array<!s32i x 3>>
89+
// CHECK: %[[#V4:]] = cir.const(#cir.int<2> : !s32i) : !s32i
90+
// CHECK: %[[#V5:]] = cir.cast(array_to_ptrdecay, %[[#V3]] : !cir.ptr<!cir.array<!s32i x 3>>), !cir.ptr<!s32i>
91+
// CHECK: cir.ptr_stride(%[[#V5]] : !cir.ptr<!s32i>, %[[#V4]] : !s32i), !cir.ptr<!s32i>
92+
}

0 commit comments

Comments
 (0)