Hi,

when debugging a program that makes heavy use of function pointers I
noticed that the CALL instruction is sometimes generated with a wrong
offset if the function pointer is stored on the stack.

The following piece of C code can be used to reproduce the problem. It
must be compiled with -ansi -Os with a recent (i.e. not older than about
6 months) mspgcc-3.2.3 version.
/*-------------------------------------------------------------------*/
#define RETTYPE int
#if 0
int vararg_func(int a, ...) { return 0; }
#else
#define vararg_func(a,b,c) do { }  while(0)
#endif

RETTYPE call_target(int a) { }
void twoarg(int a, int b) { }
void threearg(int a, int b, int c) { }
void fourarg(int a, int b, int c, int d) { }
volatile int global;

void indirect_call(int x1, int x2, int x3, RETTYPE (*funcptr)(int)) {
  /* volatile access to create pressure on register allocator*/
  int a = global, b = global, c = global, d = global, e = global;
  int f = global, g = global;

  threearg(a, b, c);
  threearg(d, e, f);
  fourarg(a, b, c, g);
  vararg_func(a, b, c);

  funcptr(x1);
}
int main(void) {
  indirect_call(0, 0, 0, call_target);
  puts("We survived");
}
/*-------------------------------------------------------------------*/

The problem is also dependent on the return type of the function
pointer: Calls of return type void are always generated wrong. The
following table lists the setting of the #defines in the beginning of
the example program and generated parameter for the call instruction:

define  return type     expected      output from mspgcc
#if 0      void          2(r1)             @r1
#if 1      void          8(r1)            6(r1)
#if 0      int           2(r1)             @r1
#if 1      int           8(r1)            8(r1)

I have no clue how gcc backends work, but after skimming over the code I
think I found the right things to change. The attached patch should fix
the problem, at least the code for my specific application is generated
correctly with this patch, but I can't guarantee for any unexpected side
effects.

Regards,
Klaus.
diff -Naur msp430_orig/msp430.c msp430/msp430.c
--- msp430_orig/msp430.c	2009-03-22 12:37:31.000000000 +0100
+++ msp430/msp430.c	2009-05-02 16:35:08.000000000 +0200
@@ -1411,6 +1411,9 @@
 	}
       else if (GET_CODE (addr) == REG)
 	{			/* for X(Rn) */
+	  /* shift if the indirect pointer register is the stack pointer */
+	  if ((code >= 'M' && code <= 'N') && (REGNO (addr)) == 1)
+	    shift = code - 'M';
 	  if (shift || !source_reg)
 	    {
 	      if (shift)
diff -Naur msp430_orig/msp430.md msp430/msp430.md
--- msp430_orig/msp430.md	2006-01-30 09:47:05.000000000 +0100
+++ msp430/msp430.md	2009-05-02 15:32:38.000000000 +0200
@@ -356,7 +356,7 @@
   [(call (mem:HI (match_operand:HI 0 "general_operand" "r,P,mi"))
          (match_operand:HI 1 "general_operand" "X,X,X"))]
 ""
-"call\\t%0"
+"call\\t%N0"
 [ (set_attr "length" "1,1,2")
    (set_attr "cc" "clobber")])
 

Reply via email to