Evaluation of offsetof() macro

Hi!

LLVM has a class, ConstantExpr, that is very handy for compile-time evaluation of const expressions. Unfortunately I cannot find any methods in it that would be helpful in evaluation of expressions similar to this: (uintptr_t)(&((TYPE)0).FIELD), which is basically the implementation of the offsetof(TYPE, FIELD) macro. Specifically, there seem to be no provisions for dereferencing a pointer.

Does LLVM have any facilities (that I missed), that would help language front-ends in dealing with this sort of expressions?
Obviously, clang does it somehow, but so far I was not able to locate the relevant bit of code. Any pointers would be appreciated!

Vadim

Hi!
LLVM has a class, ConstantExpr, that is very handy for compile-time
evaluation of const expressions. Unfortunately I cannot find any methods
in it that would be helpful in evaluation of expressions similar to this:
(uintptr_t)(&(*(TYPE*)0).FIELD), which is basically the implementation of
the offsetof(TYPE, FIELD) macro.

I think the closest entity for this sort of thing is LLVM's
ConstantExpr::getOffsetOf.

Specifically, there seem to be no provisions for dereferencing a pointer.

Does LLVM have any facilities (that I missed), that would help language
front-ends in dealing with this sort of expressions?
Obviously, clang does it somehow, but so far I was not able to locate the
relevant bit of code. Any pointers would be appreciated!

Clang handles record types in a very abstract way, it doesn't rely on LLVM
IR at any level. An ASTRecordLayout is built for a record type and the
ASTRecordLayout::getFieldIndex method is used to determine the offset for a
particular field.

Hi!
LLVM has a class, ConstantExpr, that is very handy for compile-time
evaluation of const expressions. Unfortunately I cannot find any methods
in it that would be helpful in evaluation of expressions similar to this:
(uintptr_t)(&(*(TYPE*)0).FIELD), which is basically the implementation of
the offsetof(TYPE, FIELD) macro.

I think the closest entity for this sort of thing is LLVM's
ConstantExpr::getOffsetOf.

Certainly, but I think this requires either making `offsetof` a first-class
operation in the source language, or handling the folding of <pointer

-<field select>-<get-address-of> combo in the front-end.

Specifically, there seem to be no provisions for dereferencing a pointer.

Does LLVM have any facilities (that I missed), that would help language
front-ends in dealing with this sort of expressions?
Obviously, clang does it somehow, but so far I was not able to locate the
relevant bit of code. Any pointers would be appreciated!

Clang handles record types in a very abstract way, it doesn't rely on LLVM
IR at any level. An ASTRecordLayout is built for a record type and the
ASTRecordLayout::getFieldIndex method is used to determine the offset for a
particular field.

So it handles all const expression evaluation in the front-end?

Yes, clang has it's own constant expression evaluator which understands the
rules of C++.

Let's take an example.
The expression (long)&x/(long)&y divides two globals by each other. This
expression is lowered to the following LLVM IR Constant:
i64 sdiv (i64 ptrtoint (i32* @x to i64), i64 ptrtoint (i32* @y to i64))

This Constant is a ConstantExpr but certainly not indicative of something
that would be 'constexpr' in C++.

So it handles all const expression evaluation in the front-end?

Yes, clang has it's own constant expression evaluator which understands
the rules of C++.

Let's take an example.
The expression (long)&x/(long)&y divides two globals by each other. This
expression is lowered to the following LLVM IR Constant:
i64 sdiv (i64 ptrtoint (i32* @x to i64), i64 ptrtoint (i32* @y to i64))

This Constant is a ConstantExpr but certainly not indicative of something
that would be 'constexpr' in C++.

My goal is to be able to use the result in constexpr contexts (like
declaring an array, whose size expression involves offsetof()). Please
correct me if this is wrong, but I think this means that the expression
must be evaluated before any IR is emitted.

Do you start from offsetof() or the expanded form? For various reasons,
it is normally defined to use __builtin_offsetof, since the problems you
have run into also stop the "legacy" C version from being appropoiate
for C++ as it doesn't create an ICE.

Joerg

Do you start from offsetof() or the expanded form? For various reasons,
it is normally defined to use __builtin_offsetof, since the problems you
have run into also stop the "legacy" C version from being appropoiate
for C++ as it doesn't create an ICE.

I start with a macro, but I was considering expanding it to pointer
arithmetic, to avoid creating special operators such as
__builtin_offsetof. Would that be considered a bad idea?

You found the problems with dealing with pointer arithmetic already.
Dealing with the (existing) builtin is much easier. It also helps to
give some diagnostics for illegal use, e.g. non-POD arguments in C++
mode.

Joerg