Skip to content

Using Pointer for Compact Code

April 30, 2014

This article show the impact between using pointer to access structure element and direct access to structure/object element in terms of code size generation.  I will test the code by building it on x86 and Arm cortex-M0 MCU.

Below is the original source code before modifying it into pointer access.

This function performing task delay reduction and change task state to ready. As the function name imply, it is called at 1 milliseconds interval. The object use below is Task[] that keep track of run time state of system task.

void TimerInt1mSEC_TaskTick(void)
{
     STaskNum task_num; 
     TaskSysTick++;
     for(task_num=0;task_num<MAX_TASK;task_num++)
     {
         if(Task[task_num].State == TASK_STOP)
         {
             if(Task[task_num].Delay)
             {
                 Task[task_num].Delay--;
                 if(!Task[task_num].Delay)
                     Task[task_num].State = TASK_GO;
             }
         } 
         //for calling init function during first power up
         if(Task[task_num].State == TASK_INIT_STOP)
         {
             if(Task[task_num].Delay)
             {
                 Task[task_num].Delay--;
                 if(!Task[task_num].Delay)
                     Task[task_num].State = TASK_INIT_GO;
             }
         }
    }
}

Below are the output when building the original source (accessing structure as global variable). The total size of the function is 0xCD (205Bytes). This code is build under x86 system.

00000000 <TimerInt1mSEC_TaskTick>:
 0: 55 push %ebp
 1: 89 e5 mov %esp,%ebp
 3: 83 ec 10 sub $0x10,%esp
 6: a1 00 00 00 00 mov 0x0,%eax
 b: 83 c0 01 add $0x1,%eax
 e: a3 00 00 00 00 mov %eax,0x0
 13: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
 1a: e9 a3 00 00 00 jmp c2 <TimerInt1mSEC_TaskTick+0xc2>
 1f: 8b 45 fc mov -0x4(%ebp),%eax
 22: 8b 04 c5 00 00 00 00 mov 0x0(,%eax,8),%eax
 29: 85 c0 test %eax,%eax
 2b: 75 41 jne 6e <TimerInt1mSEC_TaskTick+0x6e>
 2d: 8b 45 fc mov -0x4(%ebp),%eax
 30: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 37: 85 c0 test %eax,%eax
 39: 74 33 je 6e <TimerInt1mSEC_TaskTick+0x6e>
 3b: 8b 45 fc mov -0x4(%ebp),%eax
 3e: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 45: 8d 50 ff lea -0x1(%eax),%edx
 48: 8b 45 fc mov -0x4(%ebp),%eax
 4b: 89 14 c5 04 00 00 00 mov %edx,0x4(,%eax,8)
 52: 8b 45 fc mov -0x4(%ebp),%eax
 55: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 5c: 85 c0 test %eax,%eax
 5e: 75 0e jne 6e <TimerInt1mSEC_TaskTick+0x6e>
 60: 8b 45 fc mov -0x4(%ebp),%eax
 63: c7 04 c5 00 00 00 00 movl $0x1,0x0(,%eax,8)
 6a: 01 00 00 00 
 6e: 8b 45 fc mov -0x4(%ebp),%eax
 71: 8b 04 c5 00 00 00 00 mov 0x0(,%eax,8),%eax
 78: 83 f8 03 cmp $0x3,%eax
 7b: 75 41 jne be <TimerInt1mSEC_TaskTick+0xbe>
 7d: 8b 45 fc mov -0x4(%ebp),%eax
 80: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 87: 85 c0 test %eax,%eax
 89: 74 33 je be <TimerInt1mSEC_TaskTick+0xbe>
 8b: 8b 45 fc mov -0x4(%ebp),%eax
 8e: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 95: 8d 50 ff lea -0x1(%eax),%edx
 98: 8b 45 fc mov -0x4(%ebp),%eax
 9b: 89 14 c5 04 00 00 00 mov %edx,0x4(,%eax,8)
 a2: 8b 45 fc mov -0x4(%ebp),%eax
 a5: 8b 04 c5 04 00 00 00 mov 0x4(,%eax,8),%eax
 ac: 85 c0 test %eax,%eax
 ae: 75 0e jne be <TimerInt1mSEC_TaskTick+0xbe>
 b0: 8b 45 fc mov -0x4(%ebp),%eax
 b3: c7 04 c5 00 00 00 00 movl $0x4,0x0(,%eax,8)
 ba: 04 00 00 00 
 be: 83 45 fc 01 addl $0x1,-0x4(%ebp)
 c2: 83 7d fc 08 cmpl $0x8,-0x4(%ebp)
 c6: 0f 86 53 ff ff ff jbe 1f <TimerInt1mSEC_TaskTick+0x1f>
 cc: c9 leave 
 cd: c3 ret

Below is modified version where pointer is used extensively. And the size has been reduce to 0x9D (157) Bytes. This enable a reduction of 23% in code size.

00000000 <TimerInt1mSEC_TaskTick>:
 0: 55 push %ebp
 1: 89 e5 mov %esp,%ebp
 3: 83 ec 10 sub $0x10,%esp
 6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
 d: a1 00 00 00 00 mov 0x0,%eax
 12: 83 c0 01 add $0x1,%eax
 15: a3 00 00 00 00 mov %eax,0x0
 1a: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%ebp)
 21: eb 73 jmp 96 <TimerInt1mSEC_TaskTick+0x96>
 23: 8b 45 fc mov -0x4(%ebp),%eax
 26: 8b 00 mov (%eax),%eax
 28: 85 c0 test %eax,%eax
 2a: 75 2c jne 58 <TimerInt1mSEC_TaskTick+0x58>
 2c: 8b 45 fc mov -0x4(%ebp),%eax
 2f: 8b 40 04 mov 0x4(%eax),%eax
 32: 85 c0 test %eax,%eax
 34: 74 22 je 58 <TimerInt1mSEC_TaskTick+0x58>
 36: 8b 45 fc mov -0x4(%ebp),%eax
 39: 8b 40 04 mov 0x4(%eax),%eax
 3c: 8d 50 ff lea -0x1(%eax),%edx
 3f: 8b 45 fc mov -0x4(%ebp),%eax
 42: 89 50 04 mov %edx,0x4(%eax)
 45: 8b 45 fc mov -0x4(%ebp),%eax
 48: 8b 40 04 mov 0x4(%eax),%eax
 4b: 85 c0 test %eax,%eax
 4d: 75 09 jne 58 <TimerInt1mSEC_TaskTick+0x58>
 4f: 8b 45 fc mov -0x4(%ebp),%eax
 52: c7 00 01 00 00 00 movl $0x1,(%eax)
 58: 8b 45 fc mov -0x4(%ebp),%eax
 5b: 8b 00 mov (%eax),%eax
 5d: 83 f8 03 cmp $0x3,%eax
 60: 75 2c jne 8e <TimerInt1mSEC_TaskTick+0x8e>
 62: 8b 45 fc mov -0x4(%ebp),%eax
 65: 8b 40 04 mov 0x4(%eax),%eax
 68: 85 c0 test %eax,%eax
 6a: 74 22 je 8e <TimerInt1mSEC_TaskTick+0x8e>
 6c: 8b 45 fc mov -0x4(%ebp),%eax
 6f: 8b 40 04 mov 0x4(%eax),%eax
 72: 8d 50 ff lea -0x1(%eax),%edx
 75: 8b 45 fc mov -0x4(%ebp),%eax
 78: 89 50 04 mov %edx,0x4(%eax)
 7b: 8b 45 fc mov -0x4(%ebp),%eax
 7e: 8b 40 04 mov 0x4(%eax),%eax
 81: 85 c0 test %eax,%eax
 83: 75 09 jne 8e <TimerInt1mSEC_TaskTick+0x8e>
 85: 8b 45 fc mov -0x4(%ebp),%eax
 88: c7 00 04 00 00 00 movl $0x4,(%eax)
 8e: 83 45 f8 01 addl $0x1,-0x8(%ebp)
 92: 83 45 fc 08 addl $0x8,-0x4(%ebp)
 96: 83 7d f8 08 cmpl $0x8,-0x8(%ebp)
 9a: 76 87 jbe 23 <TimerInt1mSEC_TaskTick+0x23>
 9c: c9 leave 
 9d: c3 ret

Now lets compare build on Arm cortex-M0. Before using pointer, the size is 0xDE.

00000000 <TimerInt1mSEC_TaskTick>:
 0: b580 push {r7, lr}
 2: b082 sub sp, #8
 4: af00 add r7, sp, #0
 6: 4b36 ldr r3, [pc, #216] (e0 <TimerInt1mSEC_TaskTick+0xe0>)
 8: 681b ldr r3, [r3, #0]
 a: 1c5a adds r2, r3, #1
 c: 4b34 ldr r3, [pc, #208] (e0 <TimerInt1mSEC_TaskTick+0xe0>)
 e: 601a str r2, [r3, #0]
 10: 1dfb adds r3, r7, #7
 12: 2200 movs r2, #0
 14: 701a strb r2, [r3, #0]
 16: e05c b.n d2 <TimerInt1mSEC_TaskTick+0xd2>
 18: 1dfb adds r3, r7, #7
 1a: 781a ldrb r2, [r3, #0]
 1c: 4b31 ldr r3, [pc, #196] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 1e: 00d2 lsls r2, r2, #3
 20: 5cd3 ldrb r3, [r2, r3]
 22: 2b00 cmp r3, #0
 24: d124 bne.n 70 <TimerInt1mSEC_TaskTick+0x70>
 26: 1dfb adds r3, r7, #7
 28: 781b ldrb r3, [r3, #0]
 2a: 4a2e ldr r2, [pc, #184] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 2c: 00db lsls r3, r3, #3
 2e: 18d3 adds r3, r2, r3
 30: 3304 adds r3, #4
 32: 681b ldr r3, [r3, #0]
 34: 2b00 cmp r3, #0
 36: d01b beq.n 70 <TimerInt1mSEC_TaskTick+0x70>
 38: 1dfb adds r3, r7, #7
 3a: 781b ldrb r3, [r3, #0]
 3c: 4929 ldr r1, [pc, #164] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 3e: 00da lsls r2, r3, #3
 40: 188a adds r2, r1, r2
 42: 3204 adds r2, #4
 44: 6812 ldr r2, [r2, #0]
 46: 3a01 subs r2, #1
 48: 4926 ldr r1, [pc, #152] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 4a: 00db lsls r3, r3, #3
 4c: 18cb adds r3, r1, r3
 4e: 3304 adds r3, #4
 50: 601a str r2, [r3, #0]
 52: 1dfb adds r3, r7, #7
 54: 781b ldrb r3, [r3, #0]
 56: 4a23 ldr r2, [pc, #140] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 58: 00db lsls r3, r3, #3
 5a: 18d3 adds r3, r2, r3
 5c: 3304 adds r3, #4
 5e: 681b ldr r3, [r3, #0]
 60: 2b00 cmp r3, #0
 62: d105 bne.n 70 <TimerInt1mSEC_TaskTick+0x70>
 64: 1dfb adds r3, r7, #7
 66: 781a ldrb r2, [r3, #0]
 68: 4b1e ldr r3, [pc, #120] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 6a: 00d2 lsls r2, r2, #3
 6c: 2101 movs r1, #1
 6e: 54d1 strb r1, [r2, r3]
 70: 1dfb adds r3, r7, #7
 72: 781a ldrb r2, [r3, #0]
 74: 4b1b ldr r3, [pc, #108] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 76: 00d2 lsls r2, r2, #3
 78: 5cd3 ldrb r3, [r2, r3]
 7a: 2b03 cmp r3, #3
 7c: d124 bne.n c8 <TimerInt1mSEC_TaskTick+0xc8>
 7e: 1dfb adds r3, r7, #7
 80: 781b ldrb r3, [r3, #0]
 82: 4a18 ldr r2, [pc, #96] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 84: 00db lsls r3, r3, #3
 86: 18d3 adds r3, r2, r3
 88: 3304 adds r3, #4
 8a: 681b ldr r3, [r3, #0]
 8c: 2b00 cmp r3, #0
 8e: d01b beq.n c8 <TimerInt1mSEC_TaskTick+0xc8>
 90: 1dfb adds r3, r7, #7
 92: 781b ldrb r3, [r3, #0]
 94: 4913 ldr r1, [pc, #76] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 96: 00da lsls r2, r3, #3
 98: 188a adds r2, r1, r2
 9a: 3204 adds r2, #4
 9c: 6812 ldr r2, [r2, #0]
 9e: 3a01 subs r2, #1
 a0: 4910 ldr r1, [pc, #64] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 a2: 00db lsls r3, r3, #3
 a4: 18cb adds r3, r1, r3
 a6: 3304 adds r3, #4
 a8: 601a str r2, [r3, #0]
 aa: 1dfb adds r3, r7, #7
 ac: 781b ldrb r3, [r3, #0]
 ae: 4a0d ldr r2, [pc, #52] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 b0: 00db lsls r3, r3, #3
 b2: 18d3 adds r3, r2, r3
 b4: 3304 adds r3, #4
 b6: 681b ldr r3, [r3, #0]
 b8: 2b00 cmp r3, #0
 ba: d105 bne.n c8 <TimerInt1mSEC_TaskTick+0xc8>
 bc: 1dfb adds r3, r7, #7
 be: 781a ldrb r2, [r3, #0]
 c0: 4b08 ldr r3, [pc, #32] (e4 <TimerInt1mSEC_TaskTick+0xe4>)
 c2: 00d2 lsls r2, r2, #3
 c4: 2104 movs r1, #4
 c6: 54d1 strb r1, [r2, r3]
 c8: 1dfb adds r3, r7, #7
 ca: 1dfa adds r2, r7, #7
 cc: 7812 ldrb r2, [r2, #0]
 ce: 3201 adds r2, #1
 d0: 701a strb r2, [r3, #0]
 d2: 1dfb adds r3, r7, #7
 d4: 781b ldrb r3, [r3, #0]
 d6: 2b05 cmp r3, #5
 d8: d99e bls.n 18 <TimerInt1mSEC_TaskTick+0x18>
 da: 46bd mov sp, r7
 dc: b002 add sp, #8
 de: bd80 pop {r7, pc}

And below is the size after using pointer. Size reduction from 222Bytes to 138, that is 37% reduction in total.

00000000 <TimerInt1mSEC_TaskTick>:
 0: b580 push {r7, lr}
 2: b082 sub sp, #8
 4: af00 add r7, sp, #0
 6: 4b21 ldr r3, [pc, #132] (8c <TimerInt1mSEC_TaskTick+0x8c>)
 8: 603b str r3, [r7, #0]
 a: 4b21 ldr r3, [pc, #132] (90 <TimerInt1mSEC_TaskTick+0x90>)
 c: 681b ldr r3, [r3, #0]
 e: 1c5a adds r2, r3, #1
 10: 4b1f ldr r3, [pc, #124] (90 <TimerInt1mSEC_TaskTick+0x90>)
 12: 601a str r2, [r3, #0]
 14: 1dfb adds r3, r7, #7
 16: 2200 movs r2, #0
 18: 701a strb r2, [r3, #0]
 1a: e02f b.n 7c <TimerInt1mSEC_TaskTick+0x7c>
 1c: 683b ldr r3, [r7, #0]
 1e: 781b ldrb r3, [r3, #0]
 20: 2b00 cmp r3, #0
 22: d10f bne.n 44 <TimerInt1mSEC_TaskTick+0x44>
 24: 683b ldr r3, [r7, #0]
 26: 685b ldr r3, [r3, #4]
 28: 2b00 cmp r3, #0
 2a: d00b beq.n 44 <TimerInt1mSEC_TaskTick+0x44>
 2c: 683b ldr r3, [r7, #0]
 2e: 685b ldr r3, [r3, #4]
 30: 1e5a subs r2, r3, #1
 32: 683b ldr r3, [r7, #0]
 34: 605a str r2, [r3, #4]
 36: 683b ldr r3, [r7, #0]
 38: 685b ldr r3, [r3, #4]
 3a: 2b00 cmp r3, #0
 3c: d102 bne.n 44 <TimerInt1mSEC_TaskTick+0x44>
 3e: 683b ldr r3, [r7, #0]
 40: 2201 movs r2, #1
 42: 701a strb r2, [r3, #0]
 44: 683b ldr r3, [r7, #0]
 46: 781b ldrb r3, [r3, #0]
 48: 2b03 cmp r3, #3
 4a: d10f bne.n 6c <TimerInt1mSEC_TaskTick+0x6c>
 4c: 683b ldr r3, [r7, #0]
 4e: 685b ldr r3, [r3, #4]
 50: 2b00 cmp r3, #0
 52: d00b beq.n 6c <TimerInt1mSEC_TaskTick+0x6c>
 54: 683b ldr r3, [r7, #0]
 56: 685b ldr r3, [r3, #4]
 58: 1e5a subs r2, r3, #1
 5a: 683b ldr r3, [r7, #0]
 5c: 605a str r2, [r3, #4]
 5e: 683b ldr r3, [r7, #0]
 60: 685b ldr r3, [r3, #4]
 62: 2b00 cmp r3, #0
 64: d102 bne.n 6c <TimerInt1mSEC_TaskTick+0x6c>
 66: 683b ldr r3, [r7, #0]
 68: 2204 movs r2, #4
 6a: 701a strb r2, [r3, #0]
 6c: 1dfb adds r3, r7, #7
 6e: 1dfa adds r2, r7, #7
 70: 7812 ldrb r2, [r2, #0]
 72: 3201 adds r2, #1
 74: 701a strb r2, [r3, #0]
 76: 683b ldr r3, [r7, #0]
 78: 3308 adds r3, #8
 7a: 603b str r3, [r7, #0]
 7c: 1dfb adds r3, r7, #7
 7e: 781b ldrb r3, [r3, #0]
 80: 2b05 cmp r3, #5
 82: d9cb bls.n 1c <TimerInt1mSEC_TaskTick+0x1c>
 84: 46bd mov sp, r7
 86: b002 add sp, #8
 88: bd80 pop {r7, pc}
 8a: 46c0 nop (mov r8, r8)

Conclusion of the above, using pointer rather than structure will produce a more compact, faster execution code (assuming shorter code taking less time to execute).

Advertisements

From → Embedded System

One Comment

Trackbacks & Pingbacks

  1. Better Firmware Faster | tkcheng

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: