Skip to content

[CIR] Derived-to-base conversions #937

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 1 commit into from
Oct 5, 2024

Conversation

dkolsen-pgi
Copy link
Collaborator

Implement derived-to-base address conversions for non-virtual base classes. The code gen for this situation was only implemented when the offset was zero, and it simply created a cir.base_class_addr op for which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the cir.base_class_addr operation: the byte offset of the necessary adjustment, and a boolean flag indicating whether the source operand may be null. The offset is easy to compute in the front end while the entire path of intermediate classes is still available. It would be difficult for the back end to recompute the offset. So it is best to store it in the operation. The null-pointer check is best done late in the lowering process. But whether or not the null-pointer check is needed is only known by the front end; the back end can't figure that out. So that flag needs to be stored in the operation.

CIRGenFunction::getAddressOfBaseClass was largely rewritten. The code path no longer matches the equivalent function in the LLVM IR code gen, because the generated ClangIR is quite different from the generated LLVM IR.

cir.base_class_addr is lowered to LLVM IR as a getelementptr operation. If a null-pointer check is needed, then that is wrapped in a select operation.

When generating code for a constructor or destructor, an incorrect cir.ptr_stride op was used to convert the pointer to a base class. The code was assuming that the operand of cir.ptr_stride was measured in bytes; the operand is the number elements, not the number of bytes. So the base class constructor was being called on the wrong chunk of memory. Fix this by using a cir.base_class_addr op instead of cir.ptr_stride in this scenario.

The use of cir.ptr_stride in ApplyNonVirtualAndVirtualOffset had the same problem. Continue using cir.ptr_stride here, but temporarily convert the pointer to type char* so the pointer is adjusted correctly.

Adjust the expected results of three existing tests in response to these changes.

Add two new tests, one code gen and one lowering, to cover the case where a base class is at a non-zero offset.

Implement derived-to-base address conversions for non-virtual base
classes.  The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the byte
offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null.  The offset is easy to compute
in the front end while the entire path of intermediate classes is still
available.  It would be difficult for the back end to recompute the
offset.  So it is best to store it in the operation.  The null-pointer
check is best done late in the lowering process.  But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out.  So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten.  The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation.  If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class.
The code was assuming that the operand of `cir.ptr_stride` was measured
in bytes; the operand is the number elements, not the number of bytes.
So the base class constructor was being called on the wrong chunk of
memory.  Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem.  Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
@smeenai
Copy link
Collaborator

smeenai commented Oct 4, 2024

Ah, we've been discussing this in #379. This is great, I'll take a look soon :) CC @Lancern as well.

@smeenai
Copy link
Collaborator

smeenai commented Oct 4, 2024

We're discussing the design of this in #379; it probably makes sense to keep the design discussion there, and then come back to this PR once that's done.

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 great David, thanks for the detailed description, design sounds good to me too.

I was gonna comment on the LoweringPrepare but the operation is so simple to lower ( just like we do for memberop and others) and it's not worth the trouble. Having this in lowering prepare might also make it harder to guarantee LLVM similarity with OG's in this particular case.

```mlir
TBD
%3 = cir.base_class_addr (%1 : !cir.ptr<!ty_Derived> nonnull) [0] -> !cir.ptr<!ty_Base>
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the nice doc!

@bcardosolopes bcardosolopes merged commit cc7d1d3 into llvm:main Oct 5, 2024
7 checks passed
smeenai pushed a commit to smeenai/clangir that referenced this pull request Oct 9, 2024
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
smeenai pushed a commit to smeenai/clangir that referenced this pull request Oct 9, 2024
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
smeenai pushed a commit to smeenai/clangir that referenced this pull request Oct 9, 2024
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
keryell pushed a commit to keryell/clangir that referenced this pull request Oct 19, 2024
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
lanza pushed a commit that referenced this pull request Nov 5, 2024
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
lanza pushed a commit that referenced this pull request Mar 18, 2025
Implement derived-to-base address conversions for non-virtual base
classes. The code gen for this situation was only implemented when the
offset was zero, and it simply created a `cir.base_class_addr` op for
which no lowering or other transformation existed.

Conversion to a virtual base class is not yet implemented.

Two new fields are added to the `cir.base_class_addr` operation: the
byte offset of the necessary adjustment, and a boolean flag indicating
whether the source operand may be null. The offset is easy to compute in
the front end while the entire path of intermediate classes is still
available. It would be difficult for the back end to recompute the
offset. So it is best to store it in the operation. The null-pointer
check is best done late in the lowering process. But whether or not the
null-pointer check is needed is only known by the front end; the back
end can't figure that out. So that flag needs to be stored in the
operation.

`CIRGenFunction::getAddressOfBaseClass` was largely rewritten. The code
path no longer matches the equivalent function in the LLVM IR code gen,
because the generated ClangIR is quite different from the generated LLVM
IR.

`cir.base_class_addr` is lowered to LLVM IR as a `getelementptr`
operation. If a null-pointer check is needed, then that is wrapped in a
`select` operation.

When generating code for a constructor or destructor, an incorrect
`cir.ptr_stride` op was used to convert the pointer to a base class. The
code was assuming that the operand of `cir.ptr_stride` was measured in
bytes; the operand is the number elements, not the number of bytes. So
the base class constructor was being called on the wrong chunk of
memory. Fix this by using a `cir.base_class_addr` op instead of
`cir.ptr_stride` in this scenario.

The use of `cir.ptr_stride` in `ApplyNonVirtualAndVirtualOffset` had the
same problem. Continue using `cir.ptr_stride` here, but temporarily
convert the pointer to type `char*` so the pointer is adjusted
correctly.

Adjust the expected results of three existing tests in response to these
changes.

Add two new tests, one code gen and one lowering, to cover the case
where a base class is at a non-zero offset.
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