Reputation: 951
I'm reading the IR of nginx generated by Clang. In function ngx_event_expire_timers
, there are some getelementptr
instructions with i64 -1
as first index operand. For example,
%handler = getelementptr inbounds %struct.ngx_rbtree_node_s, %struct.ngx_rbtree_node_s* %node.addr.0.i, i64 -1, i32 2
I know the first index operand will be used as an offset to the first operand. But what does a negative offset mean?
Upvotes: 2
Views: 385
Reputation: 951
Considering what is doing inside nginx source code, the semantics of the getelementptr instruction is interesting. It's the result of two lines of C source code:
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
ev->handler(ev);
node
is of type ngx_rbtree_node_t
, which is a member of ev
's type ngx_event_t
. That is like:
struct ngx_event_t {
....
struct ngx_rbtree_node_t time;
....
};
struct ngx_event_t *ev;
struct ngx_rbtree_node_t *node;
timer
is the name of struct ngx_event_t
member where node
should point to.
|<- ngx_rbtree_node_t ->|
|<- ngx_event_t ->|
------------------------------------------------------
| (some data) | "time" | (some data)
------------------------------------------------------
^ ^
ev node
The graph above shows the layout of an instance of ngx_event_t
. The result of offsetof(ngx_event_t, time)
is 40. That means the some data
before time
is of 40 bytes. And the size of ngx_rbtree_node_t
is also 40 bytes, by coincidence. So the i64 -1
in the first index oprand of getelementptr instruction computes the base address of the ngx_event_t
containing node
, which is 40 bytes ahead of node
.
handler
is another member of ngx_event_t
, which is 16 bytes behind the base of ngx_event_t
. By (another) coincidence, the third member of ngx_rbtree_node_t
is also 16 bytes behind the base address of ngx_rbtree_node_t
. So the i32 2
in getelementptr instruction will add 16 bytes to ev
, to get the address of handler
.
Note that the 16 bytes is computed from the layout of ngx_rbtree_node_t
, but not ngx_event_t
. Clang must have done some computations to ensure the correctness of the getelementptr instruction. Before use the value of %handler
, there is a bitcast instruction which casts %handler
to a function pointer type.
What Clang has done breaks the type transformation process defined in C source code. But the result is the exactly same.
Upvotes: 0
Reputation: 5482
The GEP instruction is perfectly fine with negative indices. In this case you have something like:
node arr[100];
node* ptr = arr[50];
if ( (ptr-1)->value == ptr->value)
// then ...
GEP with negative indices just calculate the offset to the base pointer into the other direction. There is nothing wrong with it.
Upvotes: 1