ULP Advisor > Rule 9.1 Use pass by reference for large variables

ULPAdvisorBanner.PNG

ULP Advisor - Rule Table

ULP 1.1 Ensure LPM usage
ULP 2.1 Leverage timer module for delay loops
ULP 3.1 Use ISRs instead of flag polling
ULP 4.1 Terminate unused GPIOs
ULP 5.1 Avoid processing-intensive operations: modulo, divide.
ULP 5.2 Avoid processing-intensive operations: floating point
ULP 5.3 Avoid processing-intensive operations: (s)printf()
ULP 6.1 Avoid multiplication on devices without hardware multiplier
ULP 6.2 Use MATHLIB for complex math operations
ULP 6.3 Use Low Energy Accelerator (LEA) software library
ULP 7.1 Use local instead of global variables where possible
ULP 8.1 Use 'static' & 'const' modifiers for local variables
ULP 9.1 Use pass by reference for large variables
ULP 10.1 Minimize function calls from within ISRs
ULP 11.1 Use lower bits for loop program control flow
ULP 11.2 Use lower bits for port bit-banging
ULP 12.1 Use DMA for large memcpy() calls
ULP 12.1b Use DMA for potentially large memcpy() calls
ULP 12.2 Use DMA for repetitive transfer
ULP 13.1 Count down in loops
ULP 14.1 Use unsigned variables for indexing
ULP 15.1 Use bit-masks instead of bit-fields

Let us know what you think! Feedback, suggestions & comments
are welcome @ ULPAdvisorFeedback@list.ti.com

What it means

C function parameters can be passed by value (e.g. int value) or by reference (e.g. int *value). When passing by value, the compiler needs to generate code to copy the variables' values into the general-purpose registers and the stack. The registers have faster access time but are limited in number hence they are used for the first small variables. For larger variables such as structures or unions, the stack located in RAM is required to store the additional data. Copying of the data structures requires additional code execution. When passing by reference, the function only needs to copy the addresses of the variables, limiting the overall data-copying instructions to the number of the parameters of the function. This greatly reduces the number of instructions being executed each time the function is invoked.

Notice that in C, arrays are by default pointers and hence technically are already passed by reference.

Risks, Severity

Passing large variables such as structures & unions can generate additional code executions for the function, depending on the size of the data being passed. The impact increases significantly if the function is frequently invoked.

Why it is happening

At least one function in the project passes a structure or union by value.

Remedy

If the size of the structure or union is significant, change the function parameter passing method to pass by reference.

Code Example

  /*-------------ULP 9.1-------------------------------------------------
  * 
  * Detect structures or unions being used as function parameter
  * 
  * NOTICE that arrays are automatically treated as pointers so this rule
  * should not raise the flag for passing array parameters
  *
  *-------------ULP9.1-------------------------------------------------*/
 #include "msp430.h"
 typedef struct  
 {
   unsigned char variable1;
   int variable2; 
   char variable3[3];
 } structOne;
 
 structOne  structVariable, *structPointer;
 typedef union 
 {
   int variable1;
   char variable2;
   char variable5[5];    
 } unionOne;
 
 unionOne unionVariable, *unionPointer;
 char    array[30];
 //----------------------------------------------------------
 //--------- STRUCTURE EXAMPLE      -------------------------
 //----------------------------------------------------------
 void ULP9_1_BadExample1(structOne structVariableParam)
 {
   if (structVariableParam.variable2 > 0)
   P1DIR |= BIT0;
 }
 
 void ULP9_1_GoodExample1(structOne* structVariablePointer)
 {
   structVariablePointer->variable2 = 0xBEEF;
   if (structVariablePointer->variable2 > structVariablePointer->variable1)
     P1DIR ^= BIT0;
 }
 //----------------------------------------------------------
 //--------- UNION EXAMPLE      -----------------------------
 //----------------------------------------------------------
 void ULP9_1_BadExample2(unionOne unionVariableParam)
 {
   unionVariableParam.variable1 = 0xBEEF;
 }
 
 void ULP9_1_GoodExample2(unionOne* unionVariablePointer)
 {
   unionVariablePointer->variable1 = 0xBEEF;
 }
 
 //----------------------------------------------------------
 //--------- ARRAY EXAMPLE      -----------------------------
 //----------------------------------------------------------
 void ULP9_1_GoodExample3(char array[30])
 {
   array[0] = 1;
 }
 
 void ULP9_1_Examples(void)
 {
   ULP9_1_BadExample1(structVariable);
   ULP9_1_BadExample2(unionVariable);
 
 
   //-------Good examples-----------------
   ULP9_1_GoodExample1(&structVariable);
 
   structPointer = &structVariable;  
   ULP9_1_GoodExample1(structPointer);
   
   ULP9_1_GoodExample2(&unionVariable);
   
   unionPointer = &unionVariable;
   ULP9_1_GoodExample2(unionPointer);
   
   ULP9_1_GoodExample3(array);
 }
 
 void main(void)
 {
   WDTCTL = WDTPW + WDTHOLD;     // Hold watchdog timer
   ULP9_1_Examples();
   
 }


See the rest of the code examples for all MSP430 devices here!

More Resources

Want to squeeze a few more nanoAmps out of your application? Leverage the e2e (Engineer-to-Engineer) online community to get all of your ULP questions answered! Or, if you are an Ultra-Low Power pro, give back to the community with your expertise.

Go to MSP430's e2e online forum! 

If you are posting on the forums in relation to this rule, try using the tag "ULP_9.1"

E2e.jpg For technical support please post your questions at http://e2e.ti.com. Please post only comments about the article Compiler/diagnostic messages/MSP430/1537 here.