C nach asm
-
hola leute
vielleicht will (koennen wuerden es sicherlich die meisten) mir jemand bei ner umsetzung von C nach asm helfen.
habe zwei pointer vom type int die auf zwei speicherstellen zeigen.
nun moechte ich die zwei ints nach z.b. ecx und edx laden und dort auf gleichheit vergleichen. je nach dem ob gleich oder ungleich soll ein bestimmter programmcode ausgefuert werden. naja in form eines if-else.
das moecht ich fuern inline asm (bcb) machen.kann man dafuer ecx, edx, eax oder so einfach hernehmen oder muss man die register zu erst auf den stack pushen ? wann weiß man ob man pushen muss oder nicht ? also bei nem inline asm ?
cermy
Meep Meep
-
Vieleicht so:
int test,test2; void testen() { int *i=&test; int *i2=&test2; _asm { mov ebx,i mov ecx,[ebx] mov ebx,i2 mov edx,[ebx] cmp ecx,edx je _tue_dies jne _tue_jenes ...
ich hätte das so gemacht, der Code ist aber bestimmt nicht der schnellste...
Hoffe, ich konnte helfen,
Gruß Streusselkuchen.
-
sorry, nicht genau gelesen...
Theoretisch sichert der Compiler die register selber, du musst die also nicht sichern (er macht selber push & pop).
Zumindestens bei VC++6.0 is das so, zumindestens hab ich das gelesen. Bei BCB ist das bestimmt auch so
-
hoi
Streusselkuchen schrieb:
Vieleicht so:
int test,test2; void testen() { int *i=&test; int *i2=&test2; _asm { mov ebx,i // (1) mov ecx,[ebx] mov ebx,i2 mov edx,[ebx] cmp ecx,edx je _tue_dies jne _tue_jenes ...
wuerde in deinem fall in zeile (1) nicht die adresse von test nach ebx anstatt des wertes geladen werden ?
Meep Meep
-
eax, ecx und edx dürfen frei verändert werden
damit wird das ganze dann zu:
int *a,*b; void if_else() { __asm { mov ecx, a mov edx, b mov eax, [ ecx ] cmp eax, [ edx ] jne ungleich // gleich: ... ungleich: // ... } }
-
Meep Meep schrieb:
wuerde in deinem fall in zeile (1) nicht die adresse von test nach ebx anstatt des wertes geladen werden ?
das würde passieren mit
mov ebx,offset i
oder
lea ebx,i
Edit: falsch gelesen - du hast ja nach der adresse von test und nicht der von i gefragt - andererseits ist i und i2 sowieso völlig überflüssig
-
wuerde in deinem fall in zeile (1) nicht die adresse von test nach ebx anstatt des wertes geladen werden ?
ich wollte ja auch die adresse laden
danach kommt dochmov ecx,[ebx]
damit wird dann der Wert von test nach ecx geladen.
-
camper schrieb:
eax, ecx und edx dürfen frei verändert werden
-
re
hab jetz den asm-code bissl erweitert:
__asm { mov ecx, i1; mov edx, i2; mov eax, [ecx]; mov ebx, [edx]; bswap eax; bswap ebx; cmp eax, ebx; jne ungleich; inc c; ungleich: }
der grund dafuer ist mein stringarray. da wollte ich bei der sortierung bissl mehr leistung rausholen. naja zu mindest es probieren.
mein gedanke war, das ich mir von den beiden zu vergleichenden strings die ersten vier zeichen hole, mit bswap die bytes tausche und dann die zahlen vergleichen kann, ob groesser oder kleiner.jetzt frag ich mich aber gerade, ob das nicht doch der falsche weg ist.
gibts dafuer ne bessere loesung ? oder is die schon recht gut. im durchschnitt ist sie jetz schon mal schneller also ueber strcmp, wenn ich das richtig gemessen habe.was meint ihr dazu ?
Meep Meep
PS: kann man anstatt i1 auch die adresse eines char-arrays uebergeben ? bei mir meldet der bcb dann "Operadengroesse stimmt nicht ueberein"
-
bswap? unsinn wenn du nur auf gleichheit testest.
und die operanden grösse stimmt nat. nicht überein, da temp ein char array ist, ist temp - als skalare variable betrachtet - auch nur ein char. aber für assembler gibt es auch casts...typedef unsigned long long u64; inline u64 rdtsc() { __asm rdtsc } int main() { char temp1[] = "test"; char temp2[] = "tewt"; int c = 0; u64 min = ~0ULL; for ( int i = 0; i < 10000; ++i ) { u64 time = rdtsc(); __asm { mov eax, dword ptr temp1 sub eax, dword ptr temp2 sub eax, 1 adc c, 0 } time = rdtsc() - time; if ( time < min ) { min = time; i = 0; } } cout << min << endl; }
nat. ist das ergebnis völlig unbrauchbar und ohne aussagekraft was unter anderem an den eigenheiten von rdtsc liegt.
-
re
wieso sollte bswap unsinn sein ? ich geh mal davon aus, das ein string auch mal weniger als 4 zeichen haben kann. dann ist mit normalem int-vergleich sense.
dank dir mal fuer deine hilfe und erklaerung
Meep Meep
-
Meep Meep schrieb:
re
wieso sollte bswap unsinn sein ? ich geh mal davon aus, das ein string auch mal weniger als 4 zeichen haben kann. dann ist mit normalem int-vergleich sense.
dank dir mal fuer deine hilfe und erklaerung
Meep Meep
richtig, aber dann genügt ein einfacher test auf gleichheit ohnehin nicht mehr. zunächst müssten alle bytes, die nicht mehr zum string gehören, maskiert werden. selbst für eine lexikografische ordnung zweier strings würde ich das byteswap erst durchführen, wenn die ungleichheit feststeht (oder zumindest erst nach dem cmp einschieben) - bswap ist nähmlich nicht sonderlich schnell und kann auf dem P4 auch nicht parallel ausgeführt werden. willst du nur wissen, ob zwei strings unterschiedlich sind, ohne dich dafür zu interessieren, welcher nun vor dem anderen im lexikon stehen würde, brauchst du bswap nicht.
-
re
stimmt. hast recht. bringt beim normalen vergleich nix. jedoch brauch ich dann fuer meine sortierung dann noch den lexicalischen vergleich, insofern brauch ich dann bswap.
noch ne andere frage:
der bcb zeigt mir bei ner inline funktion, das er sie nicht als inline nehmen kann, weil inline asm drinnen vorkommt. ist das nun vom bcb abhaengig oder generell bei C(++) compilern so ?
kann man inlines auch extern mit nem MASM, TASM oder so machen, wo der compiler das dann auc hals inline uebernimmt ? die inline hat naemlich grad mal 3 befehle. da wurde der funktionsaufruf wahrscheinlich fast gleich lange dauern wie die funktion selbercermy
Meep Meep
-
Bei gcc ist es nicht so, aber bei den meisten anderen schon.
-
gcc stört sich nicht daran, weil die parameterübergabe an assembler dort nicht an funktionen gebunden ist. bei vc klappt es zumindest dann (d.h. die funktion wird geinlined), wenn der assembler code keinen bezug auf parameter oder lokale variablen der funktion nimmt - obige rdtsc funktion beispielsweise wird direkt eingefügt. allerdings dürfte dieser typ von funktion selten sein, im grunde kann man ja höchtens bezug auf globale variablen nehmen. in allen anderen fällen schlägt das inlining meiner erfahrung nach fehl. ich kann nur vermuten, dass es bei bcb ähnlich ist.
externe funktionen, jedenfalls wenn sie in assembler geschrieben werden, werden niemals geinlined - der compiler bekommt sie ja nie zu sehen, und der linker kann nicht wissen, wie die funktion arbeitet; um eine funktion zu inlinen muss man wissen was sie tut und wie sie es tut. weil das so ist, kann es bei exteren funktionen (jedenfalls solchen, die in einer sprache geschrieben sind, die der linker nicht kennt) auch nicht zum umordnen von (global sichtbaren) instruktionen um den aufruf herum kommen - das ist fundamental um überhaupt multithreaded programme schreiben zu können, die einigermassen korrekt sind.
-
Dafür gibt's asm volatile beim gcc.
-
laut manual hat volatile eine andere bedeutung:
The volatile keyword indicates that the instruction has important side-effects. GCC will not delete a volatile asm if it is reachable. (The instruction can still be deleted if GCC can prove that control-flow will never reach the location of the instruction.) Note that even a volatile asm instruction can be moved relative to other code, including across jump instructions.
For example, on many targets there is a system register which can be set to control the rounding mode of floating point operations. You might try setting it with a volatile asm, like this PowerPC example:asm volatile("mtfsf 255,%0" : : "f" (fpenv));
sum = x + y;This will not work reliably, as the compiler may move the addition back before the volatile asm. To make it work you need to add an artificial dependency to the asm referencing a variable in the code you don't want moved, for example:
asm volatile ("mtfsf 255,%1" : "=X"(sum): "f"(fpenv));
sum = x + y;Similarly, you can't expect a sequence of volatile asm instructions to remain perfectly consecutive. If you want consecutive output, use a single asm. Also, GCC will perform some optimizations across a volatile asm instruction; GCC does not “forget everything” when it encounters a volatile asm instruction the way some other compilers do.
An asm instruction without any output operands will be treated identically to a volatile asm instruction.
die anordnung relativ zum umgebenden code ist also nicht unbedingt fest. man könnte den inline assembler nutzen um einen einfachen spin-lock zu implementieren. nun muss ein mutex aber gleichzeitig als barrier hinhalten, sonst macht er keinen sinn. andererseits ist der code, der den mutex benutzt ja nicht von dem code abhängig, der durch den mutex geschützt wird. hier muss man also sehr gut aufpassen. obiges beispiel eine künstliche abhängigkeit einzufügen ist eine möglichkeit, aber nicht gerade transparent. in der regel ist es hier fast immer günstiger, externe funktionen zu benutzen.
-
Es wird aber überall, wo mit solchen SMP-aware locks gearbeitet wird, einfach asm volatile für die barriers verwendet. (glibc, Linux kernel, usw.)
-
tja, dann ist möglichweise die dokumentation falsch... ich kanns ja nicht ändern, aber das zitat ist direkt aus der gcc 4.0.0 doku (und ist in gcc 3 auch nicht anders)
ich könnte mir vorstellen, dass asm volatile - auch wenn das in der dokumentation so nicht gesagt wird - wie ein zugriff auf volatile daten wirkt. und diese sind ja (untereinander) total geordnet.
-
Mir fällt aber jetzt ein, dass dort immer "memory" als clobber angegeben wird, das dürfte es wahrscheinlich ausmachen...