xywang
xywang

Reputation: 951

getelementptr has -1 as the first index operand

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

Answers (2)

xywang
xywang

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

Michael Haidl
Michael Haidl

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

Related Questions