Skip to content

[CIR] Upstream zero init for global variables #133100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::ConstantOp>(loc, attr.getType(), attr);
}

mlir::TypedAttr getConstNullPtrAttr(mlir::Type t) {
assert(mlir::isa<cir::PointerType>(t) && "expected cir.ptr");
return getConstPtrAttr(t, 0);
}

mlir::TypedAttr getZeroAttr(mlir::Type t) {
return cir::ZeroAttr::get(getContext(), t);
}

mlir::TypedAttr getZeroInitAttr(mlir::Type ty) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update this function in the incubator to add the missing types @andykaylor

if (mlir::isa<cir::IntType>(ty))
return cir::IntAttr::get(ty, 0);
if (cir::isAnyFloatingPointType(ty))
return cir::FPAttr::getZero(ty);
if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty))
return getZeroAttr(arrTy);
if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty))
return getConstNullPtrAttr(ptrTy);
if (mlir::isa<cir::BoolType>(ty)) {
return getCIRBoolAttr(false);
}
llvm_unreachable("Zero initializer for given type is NYI");
}

cir::ConstantOp getBool(bool state, mlir::Location loc) {
return create<cir::ConstantOp>(loc, getBoolTy(), getCIRBoolAttr(state));
}
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,20 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
// certain constant expressions is implemented for now.
const VarDecl *initDecl;
const Expr *initExpr = vd->getAnyInitializer(initDecl);
mlir::Attribute initializer;
if (initExpr) {
mlir::Attribute initializer;
if (APValue *value = initDecl->evaluateValue()) {
ConstantEmitter emitter(*this);
initializer = emitter.tryEmitPrivateForMemory(*value, astTy);
} else {
errorNYI(initExpr->getSourceRange(), "non-constant initializer");
}
varOp.setInitialValueAttr(initializer);
} else {
initializer = builder.getZeroInitAttr(convertType(astTy));
}

varOp.setInitialValueAttr(initializer);

// Set CIR's linkage type as appropriate.
cir::GlobalLinkageKind linkage =
getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);
Expand Down
8 changes: 4 additions & 4 deletions clang/test/CIR/CodeGen/array.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s

int a[10];
// CHECK: cir.global external @a : !cir.array<!s32i x 10>
// CHECK: cir.global external @a = #cir.zero : !cir.array<!s32i x 10>

int aa[10][5];
// CHECK: cir.global external @aa : !cir.array<!cir.array<!s32i x 5> x 10>
// CHECK: cir.global external @aa = #cir.zero : !cir.array<!cir.array<!s32i x 5> x 10>

extern int b[10];
// CHECK: cir.global external @b : !cir.array<!s32i x 10>
// CHECK: cir.global external @b = #cir.zero : !cir.array<!s32i x 10>

extern int bb[10][5];
// CHECK: cir.global external @bb : !cir.array<!cir.array<!s32i x 5> x 10>
// CHECK: cir.global external @bb = #cir.zero : !cir.array<!cir.array<!s32i x 5> x 10>

int c[10] = {};
// CHECK: cir.global external @c = #cir.zero : !cir.array<!s32i x 10>
Expand Down
8 changes: 4 additions & 4 deletions clang/test/CIR/Lowering/array.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - 2>&1 | FileCheck %s

int a[10];
// CHECK: @a = external dso_local global [10 x i32]
// CHECK: @a = dso_local global [10 x i32] zeroinitializer

int aa[10][5];
// CHECK: @aa = external dso_local global [10 x [5 x i32]]
// CHECK: @aa = dso_local global [10 x [5 x i32]] zeroinitializer

extern int b[10];
// CHECK: @b = external dso_local global [10 x i32]
// CHECK: @b = dso_local global [10 x i32] zeroinitializer

extern int bb[10][5];
// CHECK: @bb = external dso_local global [10 x [5 x i32]]
// CHECK: @bb = dso_local global [10 x [5 x i32]] zeroinitializer

int c[10] = {};
// CHECK: @c = dso_local global [10 x i32] zeroinitializer
Expand Down
58 changes: 28 additions & 30 deletions clang/test/CIR/Lowering/global-var-simple.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
// Global variables of intergal types
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s

// Note: Currently unsupported features include default zero-initialization
// and alignment. The fact that "external" is only printed for globals
// without an initializer is a quirk of the LLVM AsmWriter.
// Note: Currently unsupported features include alignment..

char c;
// CHECK: @c = external dso_local global i8
// CHECK: @c = dso_local global i8 0

signed char sc;
// CHECK: @sc = external dso_local global i8
// CHECK: @sc = dso_local global i8 0

unsigned char uc;
// CHECK: @uc = external dso_local global i8
// CHECK: @uc = dso_local global i8 0

short ss;
// CHECK: @ss = external dso_local global i16
// CHECK: @ss = dso_local global i16 0

unsigned short us = 100;
// CHECK: @us = dso_local global i16 100
Expand All @@ -24,82 +22,82 @@ int si = 42;
// CHECK: @si = dso_local global i32 42

unsigned ui;
// CHECK: @ui = external dso_local global i32
// CHECK: @ui = dso_local global i32 0

long sl;
// CHECK: @sl = external dso_local global i64
// CHECK: @sl = dso_local global i64 0

unsigned long ul;
// CHECK: @ul = external dso_local global i64
// CHECK: @ul = dso_local global i64 0

long long sll;
// CHECK: @sll = external dso_local global i64
// CHECK: @sll = dso_local global i64 0

unsigned long long ull = 123456;
// CHECK: @ull = dso_local global i64 123456

__int128 s128;
// CHECK: @s128 = external dso_local global i128
// CHECK: @s128 = dso_local global i128 0

unsigned __int128 u128;
// CHECK: @u128 = external dso_local global i128
// CHECK: @u128 = dso_local global i128 0

wchar_t wc;
// CHECK: @wc = external dso_local global i32
// CHECK: @wc = dso_local global i32 0

char8_t c8;
// CHECK: @c8 = external dso_local global i8
// CHECK: @c8 = dso_local global i8 0

char16_t c16;
// CHECK: @c16 = external dso_local global i16
// CHECK: @c16 = dso_local global i16 0

char32_t c32;
// CHECK: @c32 = external dso_local global i32
// CHECK: @c32 = dso_local global i32 0

_BitInt(20) sb20;
// CHECK: @sb20 = external dso_local global i20
// CHECK: @sb20 = dso_local global i20 0

unsigned _BitInt(48) ub48;
// CHECK: @ub48 = external dso_local global i48
// CHECK: @ub48 = dso_local global i48 0

bool boolfalse = false;
// CHECK: @boolfalse = dso_local global i8 0

_Float16 f16;
// CHECK: @f16 = external dso_local global half
// CHECK: @f16 = dso_local global half

__bf16 bf16;
// CHECK: @bf16 = external dso_local global bfloat
// CHECK: @bf16 = dso_local global bfloat

float f;
// CHECK: @f = external dso_local global float
// CHECK: @f = dso_local global float 0.000000e+00

double d = 1.25;
// CHECK: @d = dso_local global double 1.250000e+00

long double ld;
// CHECK: @ld = external dso_local global x86_fp80
// CHECK: @ld = dso_local global x86_fp80 0xK00

__float128 f128;
// CHECK: @f128 = external dso_local global fp128
// CHECK: @f128 = dso_local global fp128 0xL00

void *vp;
// CHECK: @vp = external dso_local global ptr{{$}}
// CHECK: @vp = dso_local global ptr null

int *ip = 0;
// CHECK: @ip = dso_local global ptr null

double *dp;
// CHECK: @dp = external dso_local global ptr{{$}}
// CHECK: @dp = dso_local global ptr null

char **cpp;
// CHECK: @cpp = external dso_local global ptr{{$}}
// CHECK: @cpp = dso_local global ptr null

void (*fp)();
// CHECK: @fp = external dso_local global ptr{{$}}
// CHECK: @fp = dso_local global ptr null

int (*fpii)(int) = 0;
// CHECK: @fpii = dso_local global ptr null

void (*fpvar)(int, ...);
// CHECK: @fpvar = external dso_local global ptr{{$}}
// CHECK: @fpvar = dso_local global ptr null
2 changes: 1 addition & 1 deletion clang/test/CIR/Lowering/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

int a;

// CHECK: @a = external dso_local global i32
// CHECK: @a = dso_local global i32 0

int b = 2;

Expand Down
52 changes: 26 additions & 26 deletions clang/test/CIR/global-var-simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s

char c;
// CHECK: cir.global external @c : !s8i
// CHECK: cir.global external @c = #cir.int<0> : !s8i

signed char sc;
// CHECK: cir.global external @sc : !s8i
// CHECK: cir.global external @sc = #cir.int<0> : !s8i

unsigned char uc;
// CHECK: cir.global external @uc : !u8i
// CHECK: cir.global external @uc = #cir.int<0> : !u8i

short ss;
// CHECK: cir.global external @ss : !s16i
// CHECK: cir.global external @ss = #cir.int<0> : !s16i

unsigned short us = 100;
// CHECK: cir.global external @us = #cir.int<100> : !u16i
Expand All @@ -20,82 +20,82 @@ int si = 42;
// CHECK: cir.global external @si = #cir.int<42> : !s32i

unsigned ui;
// CHECK: cir.global external @ui : !u32i
// CHECK: cir.global external @ui = #cir.int<0> : !u32i

long sl;
// CHECK: cir.global external @sl : !s64i
// CHECK: cir.global external @sl = #cir.int<0> : !s64i

unsigned long ul;
// CHECK: cir.global external @ul : !u64i
// CHECK: cir.global external @ul = #cir.int<0> : !u64i

long long sll;
// CHECK: cir.global external @sll : !s64i
// CHECK: cir.global external @sll = #cir.int<0> : !s64i

unsigned long long ull = 123456;
// CHECK: cir.global external @ull = #cir.int<123456> : !u64i

__int128 s128;
// CHECK: cir.global external @s128 : !s128i
// CHECK: cir.global external @s128 = #cir.int<0> : !s128i

unsigned __int128 u128;
// CHECK: cir.global external @u128 : !u128i
// CHECK: cir.global external @u128 = #cir.int<0> : !u128i

wchar_t wc;
// CHECK: cir.global external @wc : !s32i
// CHECK: cir.global external @wc = #cir.int<0> : !s32i

char8_t c8;
// CHECK: cir.global external @c8 : !u8i
// CHECK: cir.global external @c8 = #cir.int<0> : !u8i

char16_t c16;
// CHECK: cir.global external @c16 : !u16i
// CHECK: cir.global external @c16 = #cir.int<0> : !u16i

char32_t c32;
// CHECK: cir.global external @c32 : !u32i
// CHECK: cir.global external @c32 = #cir.int<0> : !u32i

_BitInt(20) sb20;
// CHECK: cir.global external @sb20 : !cir.int<s, 20>
// CHECK: cir.global external @sb20 = #cir.int<0> : !cir.int<s, 20>

unsigned _BitInt(48) ub48;
// CHECK: cir.global external @ub48 : !cir.int<u, 48>
// CHECK: cir.global external @ub48 = #cir.int<0> : !cir.int<u, 48>

bool boolfalse = false;
// CHECK: cir.global external @boolfalse = #false

_Float16 f16;
// CHECK: cir.global external @f16 : !cir.f16
// CHECK: cir.global external @f16 = #cir.fp<0.000000e+00> : !cir.f16

__bf16 bf16;
// CHECK: cir.global external @bf16 : !cir.bf16
// CHECK: cir.global external @bf16 = #cir.fp<0.000000e+00> : !cir.bf16

float f;
// CHECK: cir.global external @f : !cir.float
// CHECK: cir.global external @f = #cir.fp<0.000000e+00> : !cir.float

double d = 1.25;
// CHECK: cir.global external @d = #cir.fp<1.250000e+00> : !cir.double

long double ld;
// CHECK: cir.global external @ld : !cir.long_double<!cir.f80>
// CHECK: cir.global external @ld = #cir.fp<0.000000e+00> : !cir.long_double<!cir.f80>

__float128 f128;
// CHECK: cir.global external @f128 : !cir.f128
// CHECK: cir.global external @f128 = #cir.fp<0.000000e+00> : !cir.f128

void *vp;
// CHECK: cir.global external @vp : !cir.ptr<!void>
// CHECK: cir.global external @vp = #cir.ptr<null> : !cir.ptr<!void>

int *ip = 0;
// CHECK: cir.global external @ip = #cir.ptr<null> : !cir.ptr<!s32i>

double *dp;
// CHECK: cir.global external @dp : !cir.ptr<!cir.double>
// CHECK: cir.global external @dp = #cir.ptr<null> : !cir.ptr<!cir.double>

char **cpp;
// CHECK: cir.global external @cpp : !cir.ptr<!cir.ptr<!s8i>>
// CHECK: cir.global external @cpp = #cir.ptr<null> : !cir.ptr<!cir.ptr<!s8i>>

void (*fp)();
// CHECK: cir.global external @fp : !cir.ptr<!cir.func<()>>
// CHECK: cir.global external @fp = #cir.ptr<null> : !cir.ptr<!cir.func<()>>

int (*fpii)(int) = 0;
// CHECK: cir.global external @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<(!s32i) -> !s32i>>

void (*fpvar)(int, ...);
// CHECK: cir.global external @fpvar : !cir.ptr<!cir.func<(!s32i, ...)>>
// CHECK: cir.global external @fpvar = #cir.ptr<null> : !cir.ptr<!cir.func<(!s32i, ...)>>