I want to understand clearly how pre and post increment ops work.

Code:
int main()
{
  x = 1;
  x *= x ++ + ++ x;
 printf("\n %d \n ",x);
}
The highlighted expression above can be seen as follows:

x op1 x op2 op3 op4 x

The C Operator Precedence Chart gives the following order of precedence:

op4 followed by op2 followed by op3 followed op1 (?)
... which means the following happens:

1. 2 is returned to the expression after op4 happens. Now, the value of x in memory becomes 2 (?)

2. 2 is returned to the expression after op2 happens. Now the value of x in memory becomes 3 (?)

3. 4 is returned to the expression after op3 happens. No change to x.

4. op1 evaluates to 3 * 4 which means x becomes 12.

But the output of the program is 8. Which means that in step 4, op1 still reads the value of x as 2 not 3 ? why?