Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 35024d3

Browse files
committedDec 12, 2024
[CIR][CodeGen] Static local variables
Pull Request: #1224
1 parent 92ae283 commit 35024d3

17 files changed

+899
-47
lines changed
 

‎clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class StructLayout;
2828
class CIRDataLayout {
2929
bool bigEndian = false;
3030

31+
unsigned defaultGlobalsAddrSpace = 0;
32+
3133
/// Primitive type alignment data. This is sorted by type and bit
3234
/// width during construction.
3335
llvm::DataLayout::PrimitiveSpec StructAlignment;
@@ -106,6 +108,10 @@ class CIRDataLayout {
106108
cir::IntType::get(Ty.getContext(), getPointerTypeSizeInBits(Ty), false);
107109
return IntTy;
108110
}
111+
112+
unsigned getDefaultGlobalsAddressSpace() const {
113+
return defaultGlobalsAddrSpace;
114+
}
109115
};
110116

111117
/// Used to lazily calculate structure layout information for a target machine,

‎clang/include/clang/CIR/Dialect/IR/CIROps.td

+4-1
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,7 @@ def GlobalOp : CIR_Op<"global",
24182418
UnitAttr:$comdat,
24192419
UnitAttr:$constant,
24202420
UnitAttr:$dsolocal,
2421+
UnitAttr:$static_local,
24212422
OptionalAttr<I64Attr>:$alignment,
24222423
OptionalAttr<ASTVarDeclInterface>:$ast,
24232424
OptionalAttr<StrAttr>:$section,
@@ -2503,7 +2504,9 @@ def GetGlobalOp : CIR_Op<"get_global",
25032504
```
25042505
}];
25052506

2506-
let arguments = (ins FlatSymbolRefAttr:$name, UnitAttr:$tls);
2507+
let arguments = (ins FlatSymbolRefAttr:$name,
2508+
UnitAttr:$tls,
2509+
UnitAttr:$static_local);
25072510
let results = (outs Res<CIR_PointerType, "", []>:$addr);
25082511

25092512
let assemblyFormat = [{

‎clang/include/clang/CIR/Interfaces/ASTAttrInterfaces.td

+32
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,42 @@ let cppNamespace = "::cir" in {
6464
MangleCtx->mangleDynamicInitializer($_attr.getAst(), Out);
6565
}]
6666
>,
67+
InterfaceMethod<"", "void", "mangleStaticGuardVariable", (ins "llvm::raw_ostream&":$Out), [{}],
68+
/*defaultImplementation=*/ [{
69+
std::unique_ptr<clang::MangleContext> mangleCtx(
70+
$_attr.getAst()->getASTContext().createMangleContext());
71+
mangleCtx->mangleStaticGuardVariable($_attr.getAst(), Out);
72+
}]
73+
>,
6774
InterfaceMethod<"", "clang::VarDecl::TLSKind", "getTLSKind", (ins), [{}],
6875
/*defaultImplementation=*/ [{
6976
return $_attr.getAst()->getTLSKind();
7077
}]
78+
>,
79+
InterfaceMethod<"", "bool", "isInline", (ins), [{}],
80+
/*defaultImplementation=*/ [{
81+
return $_attr.getAst()->isInline();
82+
}]
83+
>,
84+
InterfaceMethod<"", "clang::TemplateSpecializationKind", "getTemplateSpecializationKind", (ins), [{}],
85+
/*defaultImplementation=*/ [{
86+
return $_attr.getAst()->getTemplateSpecializationKind();
87+
}]
88+
>,
89+
InterfaceMethod<"", "bool", "isLocalVarDecl", (ins), [{}],
90+
/*defaultImplementation=*/ [{
91+
return $_attr.getAst()->isLocalVarDecl();
92+
}]
93+
>,
94+
InterfaceMethod<"", "clang::SourceLocation", "getLocation", (ins), [{}],
95+
/*defaultImplementation=*/ [{
96+
return $_attr.getAst()->getLocation();
97+
}]
98+
>,
99+
InterfaceMethod<"", "const clang::VarDecl *", "getRawDecl", (ins), [{}],
100+
/*defaultImplementation=*/ [{
101+
return $_attr.getAst();
102+
}]
71103
>
72104
];
73105
}

‎clang/include/clang/CIR/MissingFeatures.h

+7
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ struct MissingFeatures {
118118
static bool setFunctionAttributes() { return false; }
119119
static bool attributeBuiltin() { return false; }
120120
static bool attributeNoBuiltin() { return false; }
121+
static bool functionIndexAttribute() { return false; }
122+
static bool noUnwindAttribute() { return false; }
121123
static bool parameterAttributes() { return false; }
122124
static bool minLegalVectorWidthAttr() { return false; }
123125
static bool vscaleRangeAttr() { return false; }
@@ -151,6 +153,7 @@ struct MissingFeatures {
151153

152154
// Folding methods.
153155
static bool foldBinOpFMF() { return false; }
156+
static bool folder() { return false; }
154157

155158
// Fast math.
156159
static bool fastMathGuard() { return false; }
@@ -454,6 +457,10 @@ struct MissingFeatures {
454457
static bool mustProgress() { return false; }
455458

456459
static bool skipTempCopy() { return false; }
460+
461+
static bool addressSpaceInGlobalVar() { return false; }
462+
463+
static bool useARMGuardVarABI() { return false; }
457464
};
458465

459466
} // namespace cir

‎clang/lib/CIR/CodeGen/Address.h

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class Address {
3333
mlir::Type ElementType;
3434
clang::CharUnits Alignment;
3535

36+
/// Offset from the base pointer. This is non-null only when the base pointer
37+
/// is signed.
38+
mlir::Attribute offset = nullptr;
39+
3640
protected:
3741
Address(std::nullptr_t) : ElementType(nullptr) {}
3842

@@ -134,6 +138,8 @@ class Address {
134138
return *this;
135139
}
136140

141+
bool hasOffset() const { return bool(offset); }
142+
137143
/// Get the operation which defines this address.
138144
mlir::Operation *getDefiningOp() const {
139145
if (!isValid())

‎clang/lib/CIR/CodeGen/CIRGenBuilder.h

+30
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "clang/CIR/Dialect/IR/FPEnv.h"
2626

2727
#include "mlir/IR/Attributes.h"
28+
#include "mlir/IR/Block.h"
2829
#include "mlir/IR/Builders.h"
2930
#include "mlir/IR/BuiltinAttributes.h"
3031
#include "mlir/IR/BuiltinOps.h"
@@ -817,6 +818,35 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
817818
return Address{createImagPtr(loc, addr.getPointer()), addr.getAlignment()};
818819
}
819820

821+
/// Return a boolean value testing if \p arg == 0.
822+
mlir::Value createIsNull(mlir::Location loc, mlir::Value arg,
823+
const llvm::Twine &name = "") {
824+
return createICmpEQ(loc, arg, getNullValue(arg.getType(), loc), name);
825+
}
826+
827+
/// Return a boolean value testing if \p arg != 0.
828+
mlir::Value createIsNotNull(mlir::Location loc, mlir::Value arg,
829+
const llvm::Twine &name = "") {
830+
return createICmpNE(loc, arg, getNullValue(arg.getType(), loc), name);
831+
}
832+
833+
mlir::Value createICmpEQ(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
834+
const llvm::Twine &name = "") {
835+
return createICmp(loc, cir::CmpOpKind::eq, lhs, rhs, name);
836+
}
837+
mlir::Value createICmpNE(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
838+
const llvm::Twine &name = "") {
839+
return createICmp(loc, cir::CmpOpKind::ne, lhs, rhs, name);
840+
}
841+
842+
mlir::Value createICmp(mlir::Location loc, cir::CmpOpKind kind,
843+
mlir::Value lhs, mlir::Value rhs,
844+
const llvm::Twine &name = "") {
845+
if (cir::MissingFeatures::folder())
846+
llvm_unreachable("NYI");
847+
return createCompare(loc, kind, lhs, rhs);
848+
}
849+
820850
/// Cast the element type of the given address to a different type,
821851
/// preserving information like the alignment.
822852
Address createElementBitCast(mlir::Location loc, Address addr,

‎clang/lib/CIR/CodeGen/CIRGenCXXABI.h

+13
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ class CIRGenCXXABI {
172172
bool ForVirtualBase, bool Delegating,
173173
Address This, QualType ThisTy) = 0;
174174

175+
/*************************** Static local guards ****************************/
176+
177+
/// Emits the guarded initializer and destructor setup for the given
178+
/// variable, given that it couldn't be emitted as a constant.
179+
/// If \p PerformInit is false, the initialization has been folded to a
180+
/// constant and should not be performed.
181+
///
182+
/// The variable may be:
183+
/// - a static local variable
184+
/// - a static data member of a class template instantiation
185+
virtual void emitGuardedInit(CIRGenFunction &cgf, const VarDecl &varDecl,
186+
cir::GlobalOp globalOp, bool performInit) = 0;
187+
175188
/// Emit code to force the execution of a destructor during global
176189
/// teardown. The default implementation of this uses atexit.
177190
///

‎clang/lib/CIR/CodeGen/CIRGenCall.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212
//===----------------------------------------------------------------------===//
1313

14+
#include "CIRGenCall.h"
1415
#include "CIRGenBuilder.h"
1516
#include "CIRGenCXXABI.h"
1617
#include "CIRGenFunction.h"
@@ -19,8 +20,10 @@
1920
#include "TargetInfo.h"
2021

2122
#include "clang/AST/Attr.h"
23+
#include "clang/AST/Attrs.inc"
2224
#include "clang/AST/DeclCXX.h"
2325
#include "clang/AST/GlobalDecl.h"
26+
#include "clang/CIR/ABIArgInfo.h"
2427
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2528
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2629
#include "clang/CIR/FnInfoOpts.h"
@@ -31,6 +34,7 @@
3134
#include "mlir/IR/Builders.h"
3235
#include "mlir/IR/BuiltinOps.h"
3336
#include "mlir/IR/BuiltinTypes.h"
37+
#include "mlir/IR/Location.h"
3438
#include "mlir/IR/SymbolTable.h"
3539
#include "mlir/IR/Types.h"
3640
#include "clang/CIR/MissingFeatures.h"
@@ -938,6 +942,14 @@ mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc,
938942
return call->getResult(0);
939943
}
940944

945+
mlir::Value
946+
CIRGenFunction::emitNounwindRuntimeCall(mlir::Location loc, cir::FuncOp callee,
947+
ArrayRef<mlir::Value> args) {
948+
mlir::Value call = emitRuntimeCall(loc, callee, args);
949+
assert(!cir::MissingFeatures::noUnwindAttribute());
950+
return call;
951+
}
952+
941953
void CIRGenFunction::emitCallArg(CallArgList &args, const Expr *E,
942954
QualType type) {
943955
// TODO: Add the DisableDebugLocationUpdates helper

‎clang/lib/CIR/CodeGen/CIRGenDecl.cpp

+57-29
Original file line numberDiff line numberDiff line change
@@ -539,70 +539,98 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &D,
539539
/// Add the initializer for 'D' to the global variable that has already been
540540
/// created for it. If the initializer has a different type than GV does, this
541541
/// may free GV and return a different one. Otherwise it just returns GV.
542-
cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl(
543-
const VarDecl &D, cir::GlobalOp GV, cir::GetGlobalOp GVAddr) {
542+
cir::GlobalOp
543+
CIRGenFunction::addInitializerToStaticVarDecl(const VarDecl &varDecl,
544+
cir::GlobalOp globalOp,
545+
cir::GetGlobalOp getGlobalOp) {
544546
ConstantEmitter emitter(*this);
545-
mlir::TypedAttr Init =
546-
mlir::dyn_cast<mlir::TypedAttr>(emitter.tryEmitForInitializer(D));
547-
assert(Init && "Expected typed attribute");
547+
mlir::Attribute init = emitter.tryEmitForInitializer(varDecl);
548548

549549
// If constant emission failed, then this should be a C++ static
550550
// initializer.
551-
if (!Init) {
551+
if (!init) {
552552
if (!getLangOpts().CPlusPlus)
553-
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
554-
else if (D.hasFlexibleArrayInit(getContext()))
555-
CGM.ErrorUnsupported(D.getInit(), "flexible array initializer");
553+
CGM.ErrorUnsupported(varDecl.getInit(), "constant l-value expression");
554+
else if (varDecl.hasFlexibleArrayInit(getContext()))
555+
CGM.ErrorUnsupported(varDecl.getInit(), "flexible array initializer");
556556
else {
557557
// Since we have a static initializer, this global variable can't
558558
// be constant.
559-
GV.setConstant(false);
560-
llvm_unreachable("C++ guarded init it NYI");
559+
globalOp.setConstant(false);
560+
561+
emitCXXGuardedInit(varDecl, globalOp, /*performInit*/ true);
562+
getGlobalOp.setStaticLocal(true);
561563
}
562-
return GV;
564+
return globalOp;
563565
}
564566

567+
auto typedInit = mlir::cast<mlir::TypedAttr>(init);
568+
565569
#ifndef NDEBUG
566-
CharUnits VarSize = CGM.getASTContext().getTypeSizeInChars(D.getType()) +
567-
D.getFlexibleArrayInitChars(getContext());
568-
CharUnits CstSize = CharUnits::fromQuantity(
569-
CGM.getDataLayout().getTypeAllocSize(Init.getType()));
570-
assert(VarSize == CstSize && "Emitted constant has unexpected size");
570+
CharUnits varSize =
571+
CGM.getASTContext().getTypeSizeInChars(varDecl.getType()) +
572+
varDecl.getFlexibleArrayInitChars(getContext());
573+
CharUnits cstSize = CharUnits::fromQuantity(
574+
CGM.getDataLayout().getTypeAllocSize(typedInit.getType()));
575+
assert(varSize == cstSize && "Emitted constant has unexpected size");
571576
#endif
572577

573578
// The initializer may differ in type from the global. Rewrite
574579
// the global to match the initializer. (We have to do this
575580
// because some types, like unions, can't be completely represented
576581
// in the LLVM type system.)
577-
if (GV.getSymType() != Init.getType()) {
578-
GV.setSymType(Init.getType());
582+
// NOTE(CIR): This was removed in OG since opaque pointers made it trivial. We
583+
// need it since we still have typed pointers.
584+
if (globalOp.getSymType() != typedInit.getType()) {
585+
globalOp.setSymType(typedInit.getType());
586+
587+
cir::GlobalOp oldGlobalOp = globalOp;
588+
globalOp =
589+
builder.createGlobal(CGM.getModule(), getLoc(varDecl.getSourceRange()),
590+
oldGlobalOp.getName(), typedInit.getType(),
591+
oldGlobalOp.getConstant(), globalOp.getLinkage());
592+
// FIXME(cir): OG codegen inserts new GV before old one, we probably don't
593+
// need that?
594+
globalOp.setVisibility(oldGlobalOp.getVisibility());
595+
globalOp.setGlobalVisibilityAttr(oldGlobalOp.getGlobalVisibilityAttr());
596+
globalOp.setInitialValueAttr(init);
597+
globalOp.setTlsModelAttr(oldGlobalOp.getTlsModelAttr());
598+
globalOp.setDSOLocal(oldGlobalOp.getDsolocal());
599+
assert(!cir::MissingFeatures::setComdat());
600+
assert(!cir::MissingFeatures::addressSpaceInGlobalVar());
579601

580602
// Normally this should be done with a call to CGM.replaceGlobal(OldGV, GV),
581603
// but since at this point the current block hasn't been really attached,
582604
// there's no visibility into the GetGlobalOp corresponding to this Global.
583605
// Given those constraints, thread in the GetGlobalOp and update it
584606
// directly.
585-
GVAddr.getAddr().setType(
586-
getBuilder().getPointerTo(Init.getType(), GV.getAddrSpaceAttr()));
607+
getGlobalOp.getAddr().setType(getBuilder().getPointerTo(
608+
typedInit.getType(), globalOp.getAddrSpaceAttr()));
609+
610+
// Replace all uses of the old global with the new global
611+
oldGlobalOp->replaceAllUsesWith(globalOp);
612+
613+
// Erase the old global, since it is no longer used.
614+
oldGlobalOp->erase();
587615
}
588616

589-
bool NeedsDtor =
590-
D.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
617+
bool needsDtor =
618+
varDecl.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
591619

592-
GV.setConstant(
593-
CGM.isTypeConstant(D.getType(), /*ExcludeCtor=*/true, !NeedsDtor));
594-
GV.setInitialValueAttr(Init);
620+
globalOp.setConstant(
621+
CGM.isTypeConstant(varDecl.getType(), /*ExcludeCtor=*/true, !needsDtor));
622+
globalOp.setInitialValueAttr(init);
595623

596-
emitter.finalize(GV);
624+
emitter.finalize(globalOp);
597625

598-
if (NeedsDtor) {
626+
if (needsDtor) {
599627
// We have a constant initializer, but a nontrivial destructor. We still
600628
// need to perform a guarded "initialization" in order to register the
601629
// destructor.
602630
llvm_unreachable("C++ guarded init is NYI");
603631
}
604632

605-
return GV;
633+
return globalOp;
606634
}
607635

608636
void CIRGenFunction::emitStaticVarDecl(const VarDecl &D,

‎clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "CIRGenCXXABI.h"
1314
#include "CIRGenFunction.h"
1415
#include "CIRGenModule.h"
1516
#include "TargetInfo.h"
@@ -51,3 +52,25 @@ void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *D,
5152

5253
emitCXXGlobalVarDeclInit(D, Addr, PerformInit);
5354
}
55+
56+
void CIRGenFunction::emitCXXGuardedInit(const VarDecl &varDecl,
57+
cir::GlobalOp globalOp,
58+
bool performInit) {
59+
// If we've been asked to forbid guard variables, emit an error now. This
60+
// diagnostic is hard-coded for Darwin's use case; we can find better phrasing
61+
// if someone else needs it.
62+
if (CGM.getCodeGenOpts().ForbidGuardVariables)
63+
llvm_unreachable("NYI");
64+
65+
CGM.getCXXABI().emitGuardedInit(*this, varDecl, globalOp, performInit);
66+
}
67+
68+
void CIRGenFunction::emitCXXGlobalVarDeclInit(const VarDecl &varDecl,
69+
cir::GlobalOp globalOp,
70+
bool performInit) {
71+
// TODO(CIR): We diverge from CodeGen here via having this in CIRGenModule
72+
// instead. This is necessary due to the way we are constructing global inits
73+
// at the moment. With LoweringPrepare being moved to CIRGen we should
74+
// refactor this to live here.
75+
llvm_unreachable("NYI");
76+
}

0 commit comments

Comments
 (0)
Please sign in to comment.