Rheatey Bash
Rheatey Bash

Reputation: 847

Understanding the Optimization of C code on ARM platform using GCC Compiler

I am doing c programming on ARM where memory footprint and speed both have a very tight constraint. I am using the GSL-2.1 library which has almost all functions in double but my hardware doesn't have floating point on hardware so it is all doing in software. Therefore, it produces extra code size as well as reduces the speed of execution. My processor has 180KB SRAM and 1MB Flash. Now I want to improve speed as well as memory footprint so I looked into the IDE compiler settings and got following settings.

enter image description here

I have read some thread regarding optimization level on GCC but still here is some more settings which I did not get quite well. Can you please elaborate each settings wrt to GCC for ARM Cortex-M processors.

Update: I have randomly checked/unchecked some boxes I did not get any difference in code size.

Upvotes: 0

Views: 1171

Answers (1)

supercat
supercat

Reputation: 81115

When using gcc to write code for embedded systems, it is important to note that unlike many embedded-systems compilers which allow storage may be written as one type and read as another, and will treat integer overflow in at least somewhat predictable fashion, code which relies upon such behaviors is apt to break when compiled with gcc unless compiled using -fno-strict-aliasing and -fwrapv flags. For example, while the authors of the C Standard would have expected that the function

// Assume usmall is an unsigned value half the size of unsigned int
unsigned multiply(usmall x, usmall y) { return x*y; }

should be safe on two's-complement hardware platforms with silent wraparound on overflow, they didn't require compilers to implement it that way (I think they probably didn't expect that anyone who was writing a compiler for such a platform would be so obtuse as to do otherwise unless emulating some other platform). When compiled with gcc, however, that function may have unexpected side-effects.

Likewise, on many compilers, given e.g.

struct widget_header {uint16_t length; uint8_t type_id;};
struct acme_widget {uint16_t length; uint8_t type_id; uint8_t dat[5];};
struct beta_widget {uint16_t length; uint8_t type_id; uint32_t foo;};

a pointer to any of those types could be cast to widget_header; code could then look at the type_id field and cast to a more specific type. Such techniques will not always work on gcc, however; even if a union declaration containing all three types is in scope, gcc will assume that an access to a field of one of those types cannot possibly modify the corresponding field in any other.

A more concrete example to show how gcc treats aliasing:

    struct s1 { int x; };
    struct s2 { int x; };
    union { struct s1 v1; struct s2 v2; } u;

    static int peek(void *p)
    {
      struct s1 *p1 = (struct s1*)p;
      return *(int*)&p1->x;
    }

    static void setToFive(void *p)
    {
      struct s2 *p2 = (struct s2*)p;
      *(int*)(&p2->x) = 5;
    }

    static int test1a(void *p, void *q)
    {
      struct s1 *p1 = (struct s1*)p;
      if (peek(p)!=23) return 0;
      setToFive(q);
      return peek(p);
    }

    int test1(void)
    {
      struct s2 v2 = {23};
      u.v2 = v2;
      return test1a(&u.v1, &u.v2);
    }

ARM gcc 4.8.2 generates

test1:
        movw    r3, #:lower16:u
        movt    r3, #:upper16:u
        movs    r2, #5
        movs    r0, #23
        str     r2, [r3]
        bx      lr

which stores a 5 into "u" and then returns 23 (assuming that the second call to peek will return the same value as the first one, notwithstanding all of the pointer typecasts which should give a pretty clear indication to the compiler that something might possibly be aliased somewhere).

Upvotes: 1

Related Questions