Forum: Compiler & IDEs Verwendung __eabi_fsub verbieten


von René B. (Gast)


Lesenswert?

Hallo alle zusammen,

ich habe mal eine Frage zum GCC Version 4.8.2.
Mein Projekt soll auf einem LPC1114 von NXP laufen. Dieser ist laut 
Datenblatt etwas begrenzt, was die Flashgröße angeht.

Ziel ist es in dem Projekt, mathematische Berechnungsfunktionen, 
gegenüber zu stellen und die Rechenleistung und Codegröße zu evaluieren.
1.) tabellarische Approximation
2.) Berechnung mittels Festkommaarithmetik
3.) float Berechnung

Der LPC1114 besitz keine Floating Point Unit. Deshalb wird hier auch der 
halbe eabi Code eingebunden.

Nun zur Frage. Zu statischen Codeanalyse verwende ich Lint.

/* definition of coeffs */
float C0 = -100.530000;
float C1 =    1.134300;
float C2 =   -1.235646;
float C3 =   12.023300E-3;
...

result = (C0 + ((val * (C1 + val * (C2 + val .... )) /
                (1 + val * (C6 + val * (C7 + ....)

Compiliert wird das ganze mit der Option O2.
Da die Koeffizienten außerhalb des Moduls nicht verwendet werden und 
sich nicht ändern fordert Lint hier z.B.

static const float C0 = -100.530000

Gebe ich Lint hier nach, wächst die Codegröße, da nun komischerweise die 
__eabi_fsub noch zusätzlich verwendet wird. Ohne "static const" begnügt 
er sich mit __eabi_fmul und __eabi_fadd.
Wie zwinge ich den GCC nun ausschließlich die __eabi_fadd + __eabi_fmul 
zu verwenden. Und wie kann man gleichzeitig Lint ruhig stellen ohne die 
Warnungen zu unterdrücken.

Hat jemand eine Idee.

Grüße René

von Werner (Gast)


Lesenswert?

Da C0/C2 negativ sind wird er wohl subtrahieren da sich bei const der 
Wert nicht mehr ändert. Änder mal das Vorzeichen und schau ob es daran 
liegt.

von Karl H. (kbuchegg)


Lesenswert?

René B. schrieb:

> Gebe ich Lint hier nach, wächst die Codegröße, da nun komischerweise die
> __eabi_fsub noch zusätzlich verwendet wird.

Ist nachvollziehbar.
Der Compiler kann mit static noch einen Tick aggresiver compilieren.

Da es allerdings in den meisten Fällen so sein wird, dass in einem 
Programm eben nicht nur Additionen, sondern auch Subtraktionen vorkommen 
werden, ist das für die Praxis nun wirklich kein Problem, ob der 
Compiler
1
   a + b
über eine Addition, oder aber weil er den Wert für b kennt und weiß dass 
der negativ ist, dann eben
1
  a - 5
mittels Subtraktion erledigt.


Nichts gegen Codeanalysen. Aber sie sollten schon der real vorkommenden 
Situation entsprechen. Sonst kann man die erhaltenen Zahlen gleich in 
die Tonne treten. Diese speziell konstruierten praxisfremden Tests 
führen nur dazu, dass zb Grafikkartenhersteller die in bestimmten Tests 
benutzten Funktionen extrem optimieren um bei den Tests gut 
abzuschneiden.

: Bearbeitet durch User
von René B. (Gast)


Lesenswert?

Hi,

vielen Dank für die Antworten.

Mir ist schon klar, dass, mit aktiven Optimierungen, man es dem Compiler 
überlässt, die "für ihn" günstigsten Funktionen zu wählen.
Weiterhin glaube ich, dass statische Codeanalysen schon recht sinnvoll 
sind, jedoch auch mit Vorsicht zu genießen sind.

Ich habe allerdings lediglich nach einen Weg gesucht, um für diesen 
speziellen Fall die Optimierungen auszuhebeln können. Da das eine kB, 
welches die __eabi_fsub belegt, am Ende recht schmerzhaft sein kann.

Ich werde mal das GCC Manual studieren. Eventuell kann man ihn durch 
geschickte Nutzung von Compiler-Schaltern definitiv dazu zwingen das 
eine oder andere Verfahren anzuwenden. Am Ende sollte es der MCU, ja 
egal sein, ob man wie oben beschrieben

(A -   B) oder
(a + (-B)

rechnet.

von René B. (Gast)


Lesenswert?

So,

ich konnte das Problem lösen.
Die CompilerFlags -ffast-math oder -funsafe-math-optimizations führen 
dazu das auch unter O1, O2, Os und O3 das Polynom ausschließlich mit 
__eabi_fadd und __eabi_fmul berechnet wird.
Damit habe ich wieder das kB frei, welches durch die __eabi_fsub belegt 
wurde.
Weiterhin meckert Lint nicht mehr, da die Koeffizienten nun als "static 
const" angelegt werden können.

von Dr. Sommer (Gast)


Lesenswert?

René B. schrieb:
> Weiterhin meckert Lint nicht mehr, da die Koeffizienten nun als "static
> const" angelegt werden können.
Da sollte eigentlich auch dein "Gefühl" meckern, denn "const int" kann 
in C kaum/nicht optimiert werden, d.h. für die mathematische Operation 
muss die Zahl immer explizit von einer bestimmten Speicherstelle geladen 
werden; bei Integer-Literalen (d.h. auch bei "#define"), "static const", 
und "const" in C++, kann der Compiler evtl. die Konstante in den 
Maschinencode optimieren. Dass der Compiler "static const" optimiert ist 
auch nur pure Freundlichkeit, "per Standard optimierbar" ist außer 
Integer-Literalen nur "const" in C++.

von Karl H. (kbuchegg)


Lesenswert?

Dr. Sommer schrieb:

> Da sollte eigentlich auch dein "Gefühl" meckern, denn "const int" kann
> in C kaum/nicht optimiert werden, d.h. für die mathematische Operation
> muss die Zahl immer explizit von einer bestimmten Speicherstelle geladen
> werden;

Aus welcher Stelle im C-Standard schliesst du das?

Edit:
Ganz im Gegenteil gibt es in der Draft-Version vom C99 Standard die 
Fussnote 112
1
112) The implementation may place a const object that is not volatile
2
in a read-only region of storage. Moreover, the implementation need
3
not allocate storage for such an object if its address is never used.

aus der ich schliesse, dass es dem Compiler frei gestellt ist, ein const 
int komplett aus dem Speicher zu verbannen, wenn das möglich ist.

Weiters sagt der Standard
1
6.7.3 Type qualifiers
2
...
3
5 If an attempt is made to modify an object defined with a
4
  const-qualified type through use of an lvalue with non-const-qualified
5
  type, the behavior is undefined.
"undefined behaviour" ist im Standard oft ein Hinweis darauf, dass man 
es hier mit einer möglichen Optimierung zu tun hat. Im konkreten Fall 
hat man es.
1
....
2
3
  const int i = 5;
4
5
  *(int*)&i = 7;
6
7
  printf( "%d", i );

es ist nicht garantiert, dass die Ausgabe auf 7 lautet.
Durch den "Attempt to modify" ist man im "undefined land" Es kann 7 
rauskommen, muss aber nicht.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

> 112) The implementation may place a const object that is not volatile
> in a read-only region of storage.
Das bringt gar nichts...

Karl Heinz schrieb:
> Moreover, the implementation need
> not allocate storage for such an object if its address is never used.
Okay, das schon eher. Aber dazu müsste der Compiler eben das für den 
gesamten Programmcode feststellen, und das kann zB der GCC erst seit 
kurzem mit LTO (oder eben bei Verwendung von "static" und Analyse der 
einen Translation Unit).

Und das geht immer noch nicht:
1
const int SIZE=10;
2
int myData [SIZE];

von Karl H. (kbuchegg)


Lesenswert?

Dr. Sommer schrieb:

> Okay, das schon eher. Aber dazu müsste der Compiler eben das für den
> gesamten Programmcode feststellen

Nein, das muss er nicht.

Denn du darfst den Wert nicht verändern, sonst landest du bei 
undefined behviour.

Selbst wenn du mittels
1
  const int i = 5;
2
3
  printf( "%p\n", &i );
dir die Adresse von i ausgeben lässt, und damit die Adresse des const 
int benutzt, hast du immer noch die Restriktion, dass der Wert an dieser 
Adresse konstant ist und für dich nicht änderbar ist. Selbst dann, kann 
ein Compiler
1
  const int i = 5;
2
3
  printf( "%p\n", &i );
4
  printf( "%d\n", i );

zu
1
  const int i = 5;
2
3
  printf( "%p\n", &i );
4
  printf( "%d\n", 5 );

optimieren, ohne gegen den Standard zu verstossen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Dr. Sommer schrieb:

> Und das geht immer noch nicht:
>
1
const int SIZE=10;
2
> int myData [SIZE];

das ist aber eine andere Sache, und hat nichts damit zu tun, ob ein 
C-Compiler den Wert eines const int an Stellen einsetzen darf, an denen 
es erlaubt ist.

Es gibt einen Unterschied zwischen C und C++ was const betrifft. Die 
Nichtverwendbarkeit in Variablendeklarationen ist eine davon. Aber das 
hat nichts mit der Verwendung und möglichen Optimierungen in Ausdrücken 
zu tun.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Karl Heinz schrieb:
> Nein, das muss er nicht.
>
> Denn du darfst den Wert nicht verändern, sonst landest du bei
> undefined behviour.
Davon habe ich überhaupt gar nicht gesprochen. Ich meinte, damit der 
Compiler keinen extra-Speicher an einer adressierbaren Stelle für die 
"Konstante" (ob RO- oder RW- Speicher ist egal) anlegt muss er das 
gesamte Programm analysieren:
test1.c:
1
const int X = 5;
2
void test1 () {
3
  printf ("%p\n", &X);
4
}
test2.c:
1
extern const int X;
2
void test2 () {
3
  printf ("%d\n", X);
4
}

Wenn der Compiler die test2.c kompiliert weiß er nicht ob die test1.c 
vielleicht die Adresse von X nimmt, und muss daher für X Speicher 
anlegen (egal ob RO oder RW).

Karl Heinz schrieb:
> Die
> Nichtverwendbarkeit in Variablendeklarationen ist eine davon.
Einer der Gründe warum C schlecht ist...

von Karl H. (kbuchegg)


Lesenswert?

Die Regelung mit der Adresse betrifft nur den Teilaspekt, ob der 
Compiler für einen const int Speicher reservieren muss oder nicht. Es 
schränkt ihn aber nicht darin ein, die Ersetzungsoptimierung zu machen, 
wenn er den Wert des const int kennt. Ich hab die Fussnote deshalb 
angeführt, weil aus ihr klar hervorgeht, dass sich der Standard bewusst 
ist, dass ein const int auch komplett aus dem Speicher rausfliegen kann, 
was im krassen Gegensatz zu deiner Aussage " muss die Zahl immer 
explizit von einer bestimmten Speicherstelle geladen werden" steht. Wenn 
es etwas im Speicher nicht gibt, kann es auch nicht von dort geladen 
werden.

: Bearbeitet durch User
von René B. (Gast)


Lesenswert?

Bitte nicht vergessen, dass der LPC1114 ein Cortex M0 ist.
Dieser unterstützt in Assembler nicht die Verwendung von Literals

268:  4920        ldr  r1, [pc, #128]  ; (2ec <proc+0xa4>)
26a:  1c20        adds  r0, r4, #0
26c:  f000 fd30   bl  cd0 <__aeabi_fmul>
270:  491f        ldr  r1, [pc, #124]  ; (2f0 <proc+0xa8>)
272:  f000 f965   bl  540 <__aeabi_fadd>
276:  1c21        adds  r1, r4, #0
278:  f000 fd2a   bl  cd0 <__aeabi_fmul>

2e0:  41942920   .word  0x41942920
2e4:  43c33d95   .word  0x43c33d95
2e8:  00000352   .word  0x00000352

Die Koeffizienten für die Berechnung werden immer aus dem Speicher 
(Flash/RAM) geladen.
Als Nachtrag für mein Problem. Die Berechnung befindet sich in einer 
Funktion während die Koeffizienten global für das C-File sind.

von Karl H. (kbuchegg)


Lesenswert?

Dr. Sommer schrieb:

> Davon habe ich überhaupt gar nicht gesprochen.

Dann muss ich dir eine Themenverfehlung attestieren.

Das Thema des Threads lautet: kann der Compiler den Zahlenwert eines 
"const x" in mathematishcen Ausdrücken zur Compilerzeit ersetzen -  ja 
oder nein.

Ja. Das kann er, wenn er den Wert kennt
Und zwar auch dann, wenn irgendwo anders im Programm der Compiler 
gezwungen wird, tatsächlich Speicher für den const int bereit zu halten.

> test1.c:
>
1
const int X = 5;
2
> void test1 () {
3
>   printf ("%p\n", &X);
4
> }
> test2.c:
>
1
extern const int X;
2
> void test2 () {
3
>   printf ("%d\n", X);
4
> }
>
> Wenn der Compiler die test2.c kompiliert weiß er nicht ob die test1.c
> vielleicht die Adresse von X nimmt, und muss daher für X Speicher
> anlegen (egal ob RO oder RW).

Du redest hier von etwas ganz anderem. Denn der Compiler kann in test2.c 
den Wert gar nicht einsetzen, weil er ihn gar nicht kennt. Damit ist die 
ganze Voraussetzung für eine mögliche Optimierung in test2.c schon mal 
gar nicht gegeben.

: Bearbeitet durch User
von Hans Ulli K. (Gast)


Lesenswert?

René B. schrieb:
> Wie zwinge ich den GCC nun ausschließlich die __eabi_fadd + __eabi_fmul
> zu verwenden. Und wie kann man gleichzeitig Lint ruhig stellen ohne die
> Warnungen zu unterdrücken.
>
> Hat jemand eine Idee.
>
> Grüße René

Da das Symbol __eabi_fadd, __eabi_fsub usw. aus der libgcc kommt gar 
nicht.

Die einzige Möglichkeit besteht darin einen gcc zu nehmen wo diese 
libgcc nicht vorkommt.

Siehe
http://www.linuxfromscratch.org/lfs/view/stable/chapter05/gcc-pass1.html

von René B. (Gast)


Lesenswert?

Hans Ulli Kroll schrieb:
> Da das Symbol __eabi_fadd, __eabi_fsub usw. aus der libgcc kommt gar
> nicht.
>
> Die einzige Möglichkeit besteht darin einen gcc zu nehmen wo diese
> libgcc nicht vorkommt.

Also ist die Verwendung der Compiler Flags -ffast-math oder 
-funsafe-math-optimizations keine Garantie, dass das gewünschte 
Verhalten unter allen Bedingungen erfüllt wird?
Quasi ein Wechsel auf eine neuere Compiler Version könnte hier schon 
wieder andere Ergebnisse bringen.

Leider sind diese beiden Flags, hinsichtlich ihrer Compilat-Ergebnisse, 
nicht weiter dokumentiert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


von Werner (Gast)


Lesenswert?

René B. schrieb:
> -ffast-math / -funsafe-math-optimizations

Mit diesen Optionen kann deine Berechnung ungenauer werden.

von kalle (Gast)


Lesenswert?

Nicht schön aber selten: eigene Funktion fmad() oder so machen in der 
nur die gewünschten Operationen vorkommen. Da der Compiler nicht weiß 
welche Operanden er bekommt,darf er auch nicht 'optimieren'.

von Matthias H. (hallamen)


Lesenswert?

Karl Heinz schrieb:
> Dr. Sommer schrieb:
>
>> Und das geht immer noch nicht:
>>
1
const int SIZE=10;
2
>> int myData [SIZE];
>
> Es gibt einen Unterschied zwischen C und C++ was const betrifft. Die
> Nichtverwendbarkeit in Variablendeklarationen ist eine davon.

Soweit ich weiß, funktioniert obiges Konstrukt weder in C noch in C++. 
Dafür wurde mit C++11 der 'constexpr'-Qualifier eingeführt.

von René B. (Gast)


Lesenswert?

Johann L. schrieb:
> Doch, natürlich sind die dokumentiert:
>
> http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-ffast_002dmath-919

-ffast-math

Sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, 
-fno-rounding-math, -fno-signaling-nans and -fcx-limited-range.

This option causes the preprocessor macro _FAST_MATH_ to be defined.

This option is not turned on by any -O option besides -Ofast since it 
can result in incorrect output for programs that depend on an exact 
implementation of IEEE or ISO rules/specifications for math functions. 
It may, however, yield faster code for programs that do not require the 
guarantees of these specifications.

Unter Dokumentation verstehe ich nicht zwangsweise den Hinweis das die 
Code-Execution beschleunigt wird und man diese Options lieber 
deaktiviert lässt. Aber um das zu verstehen muss man wohl in die 
Internas des Compiler-Baus einsteigen.

Trotzdem Danke für die vielen Posts. Ich werde wohl, um sicher zu gehen, 
eine eigene math lib erzeugen und nur die gewünschten Funktionen 
einbetten. Dann gehe ich sicher das keine anderen benutzt werden.

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.