llvm / clangir

A new (MLIR based) high-level IR for clang.
https://clangir.org
Other
387 stars 100 forks source link

[CIR] Derived-to-base conversions #937

Closed dkolsen-pgi closed 1 month ago

dkolsen-pgi commented 1 month ago

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 commented 1 month ago

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

smeenai commented 1 month ago

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.