Skip to content
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

[CIR][CodeGen] Emit globals with constructor initializer #197

Merged
merged 2 commits into from
Aug 7, 2023

Conversation

htyu
Copy link
Contributor

@htyu htyu commented Jul 31, 2023

This change does the CIR generation for globals initialized by a constructor call. It currently only covers C++ to CIR generation. The corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);

Unlike what the default Clang codegen generates LLVM that detaches the initialization code from the global var definition (like below), we are taking a different approach that keeps them together, which we think will make the later dataflow analysis/transform easier.

@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}

So on CIR, we have something like:

  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}

The destructor support will also be in a separate change.

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

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

I'm very excited for this, thanks for putting the work and starting this in incremental way. Overall the approach looks great.

Some missing bits:

  • Please add a testcase for roundtriping parsing/printing CIR ctor inits (like others in clang/test/CIR/IR.
  • I know you mentioned dtor support coming next, but if all the CIR parts for dtors are already part of this patch, please include simple parsing/printing support for it too (codegen could naturally come in later patches, not a problem).

@sitio-couto did some initial support for simple global inits in #176, probably a good idea to rebase this PR on top of his work sooner (#176 is already approved and should land soon).

clang/include/clang/CIR/Dialect/IR/CIROps.td Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp Outdated Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp Outdated Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp Outdated Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp Outdated Show resolved Hide resolved
clang/lib/CIR/CodeGen/CIRGenFunction.cpp Outdated Show resolved Hide resolved
@htyu
Copy link
Contributor Author

htyu commented Aug 3, 2023

  • Please add a testcase for roundtriping parsing/printing CIR ctor inits (like others in clang/test/CIR/IR.

There is a roundtrip test in static.cpp, i.e, // RUN: cir-opt %t.cir -o - | FileCheck %s -check-prefix=CIR. Would you like to move it to clang/test/CIR/IR?

As for the dtor parsing/printing support, I can add it here but I don't have a good way to test it. Would a separate change make more sense?

@bcardosolopes
Copy link
Member

There is a roundtrip test in static.cpp, i.e, // RUN: cir-opt %t.cir -o - | FileCheck %s -check-prefix=CIR. Would you like to move it to clang/test/CIR/IR?

You can leave the roundtrip test there (definitely doesn't hurt!), but we need cir-to-cir ones that are independent of codegen, doesn't need to be anything fancy, just one that proves parsing/printing, globals.cir could be a good place for it.

As for the dtor parsing/printing support, I can add it here but I don't have a good way to test it. Would a separate change make more sense?

I believe so! You can also add them incrementally before codegen support if you prefer.

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

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

Thanks for applying updates! Can you mark the conversations as resolved as you fix the requested bits? It makes follow up reviews easier.

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

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

This is pretty cool Hongtao, LGTM with a few remaining minor nitpicks!

clang/lib/CIR/CodeGen/CIRGenCXX.cpp Show resolved Hide resolved
void GlobalOp::getSuccessorRegions(std::optional<unsigned> index,
ArrayRef<Attribute> operands,
SmallVectorImpl<RegionSuccessor> &regions) {
// The `then` and the `else` region branch back to the parent operation.
Copy link
Member

Choose a reason for hiding this comment

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

Please update the comment with what's relevant for this specific operation

@htyu htyu merged commit 8728826 into llvm:main Aug 7, 2023
@yugr
Copy link
Member

yugr commented Aug 9, 2023

Are there plans to extend this with arbitrary global initializers e.g.

int foo();
int c = foo();

?

@htyu
Copy link
Contributor Author

htyu commented Aug 9, 2023

Are there plans to extend this with arbitrary global initializers e.g.

int foo();
int c = foo();

?

Yes. It'll be handled in the same way, i.e, with initialization code placed in the ctor block.

I'm currently working on the LLVM lowering which should support arbitrary initialization code.

htyu added a commit that referenced this pull request Aug 16, 2023
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Oct 27, 2023
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Oct 27, 2023
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Dec 20, 2023
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Dec 20, 2023
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Jan 29, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Jan 29, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit to lanza/llvm-project that referenced this pull request Feb 8, 2024
…zers (llvm#235)

As a follow up to llvm/clangir#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Mar 23, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Mar 23, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
eZWALT pushed a commit to eZWALT/clangir that referenced this pull request Mar 24, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
eZWALT pushed a commit to eZWALT/clangir that referenced this pull request Mar 24, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
eZWALT pushed a commit to eZWALT/clangir that referenced this pull request Mar 24, 2024
…zers (llvm#235)

As a follow up to llvm#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
eZWALT pushed a commit to eZWALT/clangir that referenced this pull request Apr 29, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
eZWALT pushed a commit to eZWALT/clangir that referenced this pull request Apr 29, 2024
…zers (llvm#235)

As a follow up to llvm#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Apr 29, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
pysuxing pushed a commit to pysuxing/llvm-project that referenced this pull request Jul 17, 2024
…zers (llvm#235)

As a follow up to llvm/clangir#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
bruteforceboy pushed a commit to bruteforceboy/clangir that referenced this pull request Oct 2, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
Hugobros3 pushed a commit to shady-gang/clangir that referenced this pull request Oct 2, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
Hugobros3 pushed a commit to shady-gang/clangir that referenced this pull request Oct 2, 2024
…zers (llvm#235)

As a follow up to llvm#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
keryell pushed a commit to keryell/clangir that referenced this pull request Oct 19, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
keryell pushed a commit to keryell/clangir that referenced this pull request Oct 19, 2024
…zers (llvm#235)

As a follow up to llvm#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
lanza pushed a commit that referenced this pull request Nov 5, 2024
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) #3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
lanza pushed a commit that referenced this pull request Nov 5, 2024
…zers (#235)

As a follow up to #197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```

There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants