-
Notifications
You must be signed in to change notification settings - Fork 100
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
Conversation
There was a problem hiding this 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).
There is a roundtrip test in static.cpp, i.e, 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? |
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,
I believe so! You can also add them incrementally before codegen support if you prefer. |
There was a problem hiding this 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.
There was a problem hiding this 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!
void GlobalOp::getSuccessorRegions(std::optional<unsigned> index, | ||
ArrayRef<Attribute> operands, | ||
SmallVectorImpl<RegionSuccessor> ®ions) { | ||
// The `then` and the `else` region branch back to the parent operation. |
There was a problem hiding this comment.
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
Are there plans to extend this with arbitrary global initializers e.g.
? |
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. |
…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.
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.
…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.
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.
…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.
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.
…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.
…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.
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.
…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.
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.
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.
…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.
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.
…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.
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.
…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.
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.
…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.
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.
…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.
…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.
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.
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.
…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.
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.
…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.
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.
…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.
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
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.
So on CIR, we have something like:
The destructor support will also be in a separate change.