|
We have covered the C calling convention and the compiler generated code in the previous
article. This article will focus on the code generation for:
The following example shows the code generation for a simple while loop. Also
note that the function shown below does not generate the LINK and UNLK
instructions as this function does not have local variables. Since A6 is not
used as a frame pointer, parameter access is carried out by directly taking
offsets from the stack pointer (A7).
| Code
Generation for While Loop |
void copy_string(const char *source, char *destination)
{
* Save registers on stack so that they can be used in this function
MOVEM.L A1-A2, -(A7)
* Move destination to address register A1 (Direct offset from A7)
MOVEA.L 16(A7), A1
* Move source to address register A2 (Direct offset from A7)
MOVEA.L 12(A7), A2
while(*destination++ = *source++);
* Define the label L1 for beginning of loop
* Copy the byte from source to destination and increment pointers
L1 MOVE.B (A2)+, (A1)+
* Branch if not equal to zero. If the value moved to the destination
* is not zero, branch to L1 (i.e. stay in the while loop)
* Exit while loop as soon as a zero is moved into the destination
BNE.S L1
}
* Restore the old values of A1 and A2 by popping them off the stack
MOVEM.L (A7)+, A1-A2
* Return back to caller
RTS
|
Code generation for the for loop is covered in the example given below.
| Code
Generation for For Loop |
for (i=0; i < 100; i++)
{
. . .
}
* Data Register D2 is used to implement i.
* Set D2 to zero (i=0)
CLR.L D2
L1
. . .
* Increment i for (i++)
ADDQ.L #1, D2
* Check for the for loop exit condition ( i < 100)
CMPI.L #100, D2
* Branch to the beginning of for loop if less than flag is set
BLT.S L1
|
The code generation for C structure access is covered here. The example shows
the filling of a message structure. This function does not have LINK and UNLK as
the local variable p_msg has been assigned to a register, so no space needs to
be allocated for local variables on the stack.
| Code
Generation for Structure Access |
typedef struct
{
UChar type;
UChar sub_type;
UShort source_id;
} MessageHeader;
typedef struct
{
MessageHeader header;
UChar status;
UChar reason;
UShort padding;
} StatusMessage;
void send_status_message()
{
* Save Address Register A1 on stack. Register A1 will be used for p_msg
MOVEA.L A1, -(A7)
StatusMessage *p_msg;
p_msg = maloc(sizeof(StatusMessage));
* Push the size of StatusMessage on the stack
* The instruction below is a special instruction of pushing effective address.
* Here it is used as a quick mechanism of pushing a constant on the stack
PEA.L 8
* Call maloc
JSR _maloc
* Pop the parameter off the stack
ADDQ.L #4, A7
* _maloc returns in D0, this value is copied to A1
MOVE.L D0, A1
p_msg->header.type = STATUS_MESSAGE;
* Type is at offset 0 in the structure
MOVE.B #100, (A1)
p_msg->header.sub_type = 0;
* Clear sub_type at offset 1
CLR.B 1(A1)
p_msg->header.source_id = TASK_ID;
* source_id is at offset 2 and involves a word access
MOVE.W #0x0A22, 2(A1)
p_msg->status = SUCCESS;
* Status field is at offset 4
MOVE.B #1, 4(A1)
p_msg->reason = NOTHING;
* Reason field is at offset 5
MOVE.L #1, 5(A1)
send_message(STATUS_TASK_ID, p_msg);
* Push p_msg on to the stack
MOVE.L A1, -(A7)
* Push STATUS_TASK_ID on to the stack
MOVE.L #0x0B23, -(A7)
* Invoke send_message
JSR _send_message
* Pop the parameters off the stack
ADDQ.L #8, A7
}
* Restore Address Register A1
MOVEA.L (A7)+, A1
RTS
|
The code below shows an instance of array indexing. The generated code is
very inefficient because it leads to a multiply by structure size. This overhead
can also be reduced by making the size of the structure a power of 2, i.e. 2, 4,
8, 16 etc. In such cases the compiler would replace the multiply with a shift
instruction.
| Code
Generation for Array Indexing |
typedef struct
{
Ulong a;
Ushort b;
} ABStructure;
for (i=0; i < 100; i++)
{
abstructure[i].x = 0;
. . .
}
* Code for i = 0, D2 is used for i
CLR.W D2
* Move index i into D3
L1 MOVE.W D2, D3
* Multiply index with size of ABStructure to determine the offset for the indexed
* structure
MULS.W #6, D3
* Base address of abstructure is in A5, add the offset in D3 to obtain the address
* of the indexed structure entry and set it to zero
CLR.L (A5, D3)
. . .
* i++
ADDQ.W #1, D2
* For loop comparison (i < 100)
CMPI.W #100, D2
* If less than 100, branch to loop start at L1
BLT.S L1
|
Most compilers will optimize the above code by directly incrementing the
pointer in a loop. The optimized code and the generated assembly code are shown
below. This optimization really speeds up array indexing in a loop as
multiply/shifts are avoided.
| Code
Generation for Array Indexing (Optimized) |
// Effective C Code
ABStructure *ptr = &abstructure[0];
for (i=0; i < 100; i++)
{
ptr->x = 0;
. . .
ptr++;
}
* Store the base address of the array in Address Register A5
LEA.L _abstructure, A5
* Code for i = 0, D2 is used for i
CLR.W D2
* Code corresponding to ptr->x = 0;
L1 CLR.L (A5)
. . .
* Code corresponding to ptr++
* Add size of ABStructure to address in A5 (ptr)
ADDQ.W #6, A5
* i++
ADDQ.W #1, D2
* For loop comparison (i < 100)
CMPI.W #100, D2
* If less than 100, branch to loop start at L1
BLT.S L1
|
|