Forum: Compiler & IDEs ARM-GCC: Unsigned-Integer-Overflow


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

gibt es eine Möglichkeit (z.B. ein Intrinsic, das ich nicht gefunden 
habe), dem ARM-GCC beizubringen, einen Überlauf einer Addition mit 
Unsigned Integer einfach über das Carry-Bit zu machen, ohne Overhead zu 
erzeugen?

Quasi das hier in minimaleffizient:
1
// Globals
2
uint32_t v = UINT32_MAX/10;
3
4
void ISR_HIGH_FREQU(void)
5
{
6
    static uint32_t a = 0;
7
8
    if( a > UINT32_MAX - v )
9
        do_some_fast_operation_with_nebeneffekt();
10
    
11
    a+= v;
12
}

Viele Grüße
W.T.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wenn der eine Takt wirklich so wichtig ist ginge es mit Inline Assembly:
1
#include <stdint.h>
2
#include <limits.h>
3
4
void do_some_fast_operation_with_nebeneffekt (void);
5
6
uint32_t v = UINT32_MAX/10;
7
8
void test1 (void) {
9
  static uint32_t a = 0;
10
  uint32_t* ap = &a;
11
  uint32_t* vp = &v;
12
  __asm__ volatile (  "ldr r0, [%[ap]]\n"
13
            "ldr r1, [%[vp]]\n"
14
            "adds r0, r1\n"
15
            "it cs\n"
16
            "blcs do_some_fast_operation_with_nebeneffekt\n"
17
            : 
18
            : [ap] "r" (ap), [vp] "r" (vp)
19
            : "r0", "r1", "r2", "r3", "lr", "r12", "cc", "memory");
20
  
21
  a += v;
22
}
23
24
void test2 (void) {
25
  static uint32_t a = 0;
26
    if( a > UINT32_MAX - v )
27
        do_some_fast_operation_with_nebeneffekt();
28
29
    a += v;
30
}

ergibt
1
00000000 <test1>:
2
   0:  b530        push  {r4, r5, lr}
3
   2:  4c06        ldr  r4, [pc, #24]  ; (1c <test1+0x1c>)
4
   4:  4d06        ldr  r5, [pc, #24]  ; (20 <test1+0x20>)
5
   6:  6820        ldr  r0, [r4, #0]
6
   8:  6829        ldr  r1, [r5, #0]
7
   a:  1840        adds  r0, r0, r1
8
   c:  bf28        it  cs
9
   e:  f7ff fffe   blcs  0 <do_some_fast_operation_with_nebeneffekt>
10
  12:  6823        ldr  r3, [r4, #0]
11
  14:  682a        ldr  r2, [r5, #0]
12
  16:  4413        add  r3, r2
13
  18:  6023        str  r3, [r4, #0]
14
  1a:  bd30        pop  {r4, r5, pc}
15
  ...
16
17
00000024 <test2>:
18
  24:  b538        push  {r3, r4, r5, lr}
19
  26:  4d07        ldr  r5, [pc, #28]  ; (44 <test2+0x20>)
20
  28:  4c07        ldr  r4, [pc, #28]  ; (48 <test2+0x24>)
21
  2a:  682a        ldr  r2, [r5, #0]
22
  2c:  6863        ldr  r3, [r4, #4]
23
  2e:  43d1        mvns  r1, r2
24
  30:  4299        cmp  r1, r3
25
  32:  d203        bcs.n  3c <test2+0x18>
26
  34:  f7ff fffe   bl  0 <do_some_fast_operation_with_nebeneffekt>
27
  38:  682a        ldr  r2, [r5, #0]
28
  3a:  6863        ldr  r3, [r4, #4]
29
  3c:  4413        add  r3, r2
30
  3e:  6063        str  r3, [r4, #4]
31
  40:  bd38        pop  {r3, r4, r5, pc}
32
  42:  bf00        nop
33
  ...

Allerdings richtet der GCC den Stack bei test1 nicht korrekt aus; wenn 
do_some_fast_operation_with_nebeneffekt ein 8-Byte-Alignment braucht 
gibt es einen Absturz. Habe auch nicht herausgefunden wie man dem GCC 
beibringt dass ein Inline-Assembler-Block einen Funktionsaufruf enthält 
und daher Alignment nötig ist...

von Walter T. (nicolas)


Lesenswert?

Niklas G. schrieb:
> Wenn der eine Takt wirklich so wichtig ist

Hallo Namensvetter,

ich zähle jetzt zwei Takte Unterschied - aber nein: So wichtig, dass der 
Mehraufwand für Assembler gerechtfertigt wäre, sind mir diese zwei Takte 
nicht. Zumindest nicht heute. Mich interessiert nur die Möglichkeit.

Und ich will noch nicht so recht wahrhaben, dass der nicht-seltene 
Anwendungsfall "Überlauferkennung" von den Compilerbauern einfach so 
links liegen gelassen wurde.

Viele Grüße
W.T.

von temp (Gast)


Lesenswert?

meinst du sowas:
1
 ... 
2
  __asm volatile 
3
    (
4
    // Load loop count to register
5
    " mov r3, %[loops]\n"
6
    " .align 4\n"
7
    "loop: sub r3,#1   \n" 
8
    "      bne loop  \n\n"
9
    : // No output registers
10
    : [loops] "r" (CyclestoLoops) // Input registers
11
    : "r3" // clobbered registers
12
      );
13
 ...

Ich hatte mal das Problem, dass sich eine Delay() Funktion (ja man 
braucht so was ohne Timer hin und wieder doch mal) ständig anderes 
verhielt. Das ging soweit, dass eine Programmänderung an einer ganz 
anderen Stelle auf einmal die Laufzeiten der Delay-Funktion grob 
veränderten. (Alle ohne jeden Interrupt oder DMA dazwischen). Am Ende 
stellt sich raus, dass das wohl mit dem Flash Waitstates und Cachings zu 
tun hatte, denn es war davon abhängig an welchen Adressen im Flash am 
Ende der Codeschnipsel oben landete. Das align 4 hat mein Problem 
jedenfalls gelöst.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> meinst du sowas:

Nein, ich meinte das Alignment des Stack Pointers ("SP"). Bloß was für 
Füll-Bytes produziert der Assembler an der Stelle? Die werden ja vom 
Prozessor als Instruktionen interpretiert...

von Oliver S. (oliverso)


Lesenswert?

Walter T. schrieb:
> Und ich will noch nicht so recht wahrhaben, dass der nicht-seltene
> Anwendungsfall "Überlauferkennung" von den Compilerbauern einfach so
> links liegen gelassen wurde.

https://godbolt.org/z/K1DpyW

So ganz links liegen gelassen haben die das wohl doch nicht.

Oliver

: Bearbeitet durch User
von Luther B. (luther-blissett)


Lesenswert?


von Walter T. (nicolas)


Lesenswert?


Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.