Shop OBEX P1 Docs P2 Docs Learn Events
_COGMEM Automatic Variables — Parallax Forums

_COGMEM Automatic Variables

KyeKye Posts: 2,200
edited 2015-01-02 17:51 in Propeller 1
Is it possible to have lots of _COGMEM automatic variables? I tried defining a bunch of _COGMEM variables outside of a _NAKED main function and I see that code was generated to store to these variables in the asm output. However, it looks like the compiler just stores to the variables and then keeps using its own local or stack variable for computation. My goal was to have it use the _COGMEM variable instead of using the stack.

Can you extend the register space using _COGMEM variables or does the compiler only benefit from those variables when they have initialized data? The compiler is wasting a huge amount of time loading and storing data to the stack versus just having a copy of the variable stored in cogram.

Comments

  • ersmithersmith Posts: 6,053
    edited 2014-12-29 09:46
    You can have as many COGMEM variables as will fit, but they aren't automatic variables (in either the technical C sense of variables declared local to a function, or in the sense of variables used automatically by the compiler). You have to mention them explicitly in expressions in order to make the compiler use them.

    If any kind of optimization is enabled then the compiler will keep variables in its own registers (r0-r15) as much as possible, and only spill them out to the stack when it runs out of room. The stack only gets used if you forget to include -O (or -Os, or some other -O variant) on the command line, or if you have a really huge number of local variables. In the latter case it might be worth splitting your function up into smaller, simpler pieces.
  • KyeKye Posts: 2,200
    edited 2014-12-29 14:02
    With -Os on cogmem variables are not used at all. The compiler will store a value in them once on init and then keep the variable in a register. I have a lot of static variables in a function I have to deal with and I was trying to use cogmem to keep stuff from being put on the stack. Breaking the code into functions won't help.
  • KyeKye Posts: 2,200
    edited 2014-12-29 16:48
    Okay, I've figured out something that works about as optimal as you can get.

    1. GCC refuses to uses cogmem variables equivalently as registers and will try to cache everything in its stack. This makes cogmem variables useless. The compiler will do one store to them for init purposes and that's it.
    2. If GCC runs out of register space it pushes registers onto the stack. This will waste all your code space in cogmode if this happens due to all the register thrashing going on. Instead of storing a variable back in cogmem it will push it to the stack.
    3. If you declare the cogmem variable as volatile then gcc can't cache it in its registers/overflow_stack and will have to move the value in and out of registers. While this method uses up two more moves than normal it saves the pushes and pops to and from the stack. I suppose this is the best you can get.

    The https://code.google.com/p/propgcc/wiki/PropGccInDepth article says not to declare your cogmem variable as volatile. You must instead do the opposite for performance/space gain.
  • ersmithersmith Posts: 6,053
    edited 2014-12-29 19:39
    Kye wrote: »
    With -Os on cogmem variables are not used at all. The compiler will store a value in them once on init and then keep the variable in a register. I have a lot of static variables in a function I have to deal with and I was trying to use cogmem to keep stuff from being put on the stack. Breaking the code into functions won't help.

    Could you post some sample code? That's not the behavior I'm seeing, but I'm using pretty simple functions. For example:
    #include <propeller.h>
    
    _COGMEM int scale;
    _COGMEM int offset;
    
    int myfunc(int x)
    {
        return (x<<scale) + offset;
    }
    
    produces:
    	.text
    	.balign	4
    	.global	_myfunc
    _myfunc
    	shl	r0, _scale
    	add	r0, _offset
    	mov	pc,lr
    	.section .kernel,"aw",@progbits
    _offset
    	long	0
    _scale
    	long	0
    
    which looks correct to me, and there's no stack or compiler registers involved (other than the parameter x).
  • ersmithersmith Posts: 6,053
    edited 2014-12-29 19:47
    Ah, I think I see the problem -- gcc thinks that COGMEM variables are more expensive to access than registers, so while it's happy to use them for single operations, if they appear inside a loop then it wants to use registers instead. I'll see if I can fix that.
  • KyeKye Posts: 2,200
    edited 2014-12-30 12:08
    Still working on the code... Will post soon.
  • KyeKye Posts: 2,200
    edited 2014-12-30 18:43
    Attached is my code. I compile with "propeller-elf-gcc.exe -Os -ffunction-sections -fdata-sections -m32bit-doubles -mfcache -std=c99 -mcog -r -xc"

    Right now, the code should be able to complete the inner loop in less than 500 clock cycles (I counted ~470). I needed this code to be that fast so that it doesn't miss quadrature encoder samples. If you make the cogmem variables non volatile you'll see the horror with all the stack pushes and pops.
  • ersmithersmith Posts: 6,053
    edited 2015-01-02 17:51
    Thanks for posting the example, Kye. Using "volatile" with _COGMEM is a good work-around for now. Fixing gcc to treat _COGMEM as equal to a register looks like it will take a while. For simple things everything is fine, but once the code gets complicated or involves loops the optimizer tries to keep the values in registers, and that's turning out to be hard to change :-(.
Sign In or Register to comment.