Dieses Register wird im Ram zwischengespeichert, damit darin später andere Werte gespeichert werden können. (z.B. via Inline Assembler Code).
Gruß
pctoaster
Hallo,
ich hoffe Ihr könnt mir helfen. Ich beschäftige mich zur Zeit mit dem gcc, genauer gesagt mit der Zwischensprache des GCC also RTL(Register Transfer Language). In ihr kommt ein Befehl (clobber x) wobei x meist ein Register ist.
Laut GCC internals bewirkt dies eine speicherung bzw eine mögliche speicherung von x hier mal ein beispiel
kann mir wer sagen was nun genau dabei gemacht wird, also was der befehl clobber mit dem reg17 macht-Code:(insn 9 8 10 1 (parallel [ (set (reg:SI 60) (plus:SI (mem/c/i:SI (reg/f:SI 53 virtual-incoming-args) [0 a+0 S4 A32]) (reg:SI 61))) (clobber (reg:CC 17 flags)) ]) -1 (nil) (nil))
gruss matze
Dieses Register wird im Ram zwischengespeichert, damit darin später andere Werte gespeichert werden können. (z.B. via Inline Assembler Code).
Gruß
pctoaster
clobber sagt, daß REG 17 durch diese insn verändert wird; und zwar in einer Weise, die zu kompliziert ist, um sie hier genau zu beschreiben. Wichtig ist, daß REG 17 den Inhalt wechselt. REG 17 hat den Mode (enum machine_mode) CCmode (CC), enthält also den condition code der Maschine.Code:(clobber (reg:CC 17 flags))
das parallel[] (eine zeitgleiche(!) Ausführung mehrerer insns) enthält ein set. In C-Syntax:
reg60 = (*(reg53)) + reg61
wobei die Operation als 32-Bit ausgeführt wird (SImode=single integer). Sie lädt also einen 32-Bit-Wert, und diese Ladeoperation hat eine nicht weiter spezifizierte Änderung von reg17 zur Folge.
Was weiter mit REG 17 geschieht, ist aus der insn nicht ersichtlich. Weiterverwendet werden kann REG 17 nicht -- was wollte man mit einem Register mit undefiniertem Inhalt auch anfangen?
Wie REG 17 auf Funktionsebene gehandhabt wird, hängt davon ab, ob es sich um ein Hard-Reg handelt oder um ein Pseudo-Reg (siehst du im Header ./gcc/config/target/target.h). Zu vermuten ist, daß die Maschine 16 GPRs hat und REG 17 ebenfalls zu den Hard-Regs gehört.
Dieser Beitrag passt übrigens nicht in dieses Forum, da es sich dabei nicht um Assembler-Programmierung handelt. (Die insn entstand ja nicht aus einem Inline-Assembler, und selbst wenn, ist es keine Frage von asm-Programmierung), sondern ist ein Pattern aus der Backend-Beschreibung der Maschine, die du findest in ./gcc/config/target/target.md
Dieses Thema gehört zu "Compilerbau", also am ehesten nach "Software, Algorithmen und KI".
Disclaimer: none. Sue me.
danke erst mal für die schnelle antwort. der hauptgrund, warum ich nun in diesem forum meine frage stellte ist der das ich nun nicht rausbekommen hatte, was der befehl clobber nun genau macht. das einzige was ich fand war
der asm befehl. ich hoffte das es da einen zusammenhang gab zwischen beiden befehlen
was der befehl nun genau mit dem register macht kann man wo nicht sagen?
ich habe zwar das internal des GCC gelesen, kann aber immer noch nicht sagen was da nun geschied besonders in verbindung mit dem (scratch:m) befehl was nich immer für mich sinn macht
zum beispiel ?Code:(clobber (scratch:SI))
Was hier passiert ist wesentlich komplexer als bei inline asm.
Nehmen wir mal das Beispiel einer 16-Bit AND-Insn für AVR:
Diese Standard-Insn wird vom Middle-End emitiert, wenn ein 16-BitCode:(define_insn "andhi3" [(set (match_operand:HI 0 "register_operand" "=r,d,r") (and:HI (match_operand:HI 1 "register_operand" "%0,0,0") (match_operand:HI 2 "nonmemory_operand" " r,i,M"))) (clobber (match_scratch:QI 3 "=X,X,&d"))] "" { if (which_alternative==0) return (AS2 (and,%A0,%A2) CR_TAB AS2 (and,%B0,%B2)); else if (which_alternative==1) { if (GET_CODE (operands[2]) == CONST_INT) { int mask = INTVAL (operands[2]); if ((mask & 0xff) != 0xff) output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands); if ((mask & 0xff00) != 0xff00) output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands); return ""; } return (AS2 (andi,%A0,lo8(%2)) CR_TAB AS2 (andi,%B0,hi8(%2))); } return (AS2 (ldi,%3,lo8(%2)) CR_TAB AS2 (and,%A0,%3) CR_TAB AS1 (clr,%B0)); } [(set_attr "length" "2,2,3") (set_attr "cc" "set_n,clobber,set_n")])
bitweises And gemacht werden soll. %0 und %1 liegen vor Pass LREG
höchstwahrscheinlich in Pseudo-Registern, %2 ist ein Immediate oder
ein Reg und %3 ist ein evtl. benötigtes Clobber-Register.
Vor Pass LREG hat das clobber nur eine Funktion was Matching der
Insn-Pattern angeht. Wichtig wird es erst im Reload-Pass, also in
GREG. GREG kümmert sich um die globale Register-Allokierung, d.h. es
bildet die (potentiell) unendlich vielen Pseudo-Regs auf die endlich
vielen Hard-Regs der Maschine ab, wobei noch Nebenbedingungen
berücksichtigt werden müssen, weil nicht jede Instruktion auf jedem
GPR erlaubt ist.
GREG hat 3 Möglichkeiten der Allokierung, beschrieben in den Constraints:
- #0 ist einfach: Ein- und Ausgabe liegen in Registern; das And wird mit
2 AND-Instruktionen erledigt und die Constraint zu %1 sorgt dafür,
daß %0 und %1 im gleichen Hard-Reg zu liegen kommen (dafür muss GREG
evtl. eine movhi-Insn emittieren).- #1 ist auch einfach: Ausgabe ist ein REG aus Klasse "d" (LD_REGS) auf
das eine Konstante drauf-geundet wird. Für diese Register gibt's die
ANDI-Instruktion, und je nachdem, ob die Konstante schon zur
Compilezeit bekannt ist oder nicht (Symbole sind zB Konstanten, die
aber erst zur Locate-Zeit bekannt werden) werden eine oder zwei ANDI
ausgegeben.- #2 %2 ist eine 16-Bit-Konstante und %0 gehört nicht zu LD_REGS
(regclass NO_LD_REGS). In diesem Falls ist es
nicht möglich, die ANDI-Instruktion zu verwenden. Falls %2 eine
8-Bit-Konstante ist (Contraint "M"), dann bewirkt das "=&d" bei %3,
daß GREG ein Register aus Klasse "d" zur Verfügung stellt, das wir
temporär in dieser insn verwenden können.
Globale Register-Allokierung ist einer der schwierigen und
komplexesten Teile jedes optimierenden Compilers.
Es ist zB denkbar, daß kein "d"-Reg mehr frei ist, und GCC muss erst
eines frei machen und extra Code dafür ausgeben, indem irgendein
"d"-Reg auf den Stack gesichert wird.
#2 erledigt den Reload der Konstanden in das Register %3 von Hand und führt
das AND auf dem unteren Byte von %0 aus. Das obere Byte ist 0, denn
die Konstante ist nur 8 Bit breit.- Es verbleibt der Fall, daß %0 zu NO_LD_REGS gehört und die
Konstante keine 8-Bit-Konstante ist. In diesem Fall kümmert sich GREG
um den Reload, lädt also %2 in ein GPR und wird dann #0 anwenden
können. Schwierig daran ist dann der Reload von %2, weil man keine
Konstante nach NO_LD_REGS laden darf... Wie das gelöst wird, führt
jetzt zu weit.
In #0 und #1 sagt die Contraint "X" bei %3, daß kein Clobber-Reg
gebraucht wird.
Clobber macht also mehr, als zu sagen, daß der Registerinhalt
verändert wird (um das Register zu verändern, müssen wir es erst
*haben*!)
Es hat Einfluß auf Insn-Matching und die
Register-Allokierung. Beachte, daß das Ergebnis besser ist, als wenn
man über ein extra Pseudo arbeiten würde um die Konstante dahin zu
laden. Dann würde man einen Expander schreiben und dort die Konstante
in ein Pseudo laden. Dann würde man allerdings nicht in dieser Form
von der ANDI profitieren können.
Um das Pattern für #2 erzeugen zu lassen, muss man schon was
tricksen. Für avr-gcc 3.4.6 geht's mit folgender Quelle:
Das asm volatile dient nur dazu, daß GREG b nicht nach 16/17 legtCode:void foo (void); int B; void bar (void) { int b = B; foo (); asm volatile ("":::"16","17"); B = b & 0xf; }
(würde zu #1 führen). Zum weiteren Verständnis wird's nicht gebraucht.
Code:avr-gcc clobber.c -S -Os -da -dP -fverbose-asmCode:; (insn 14 12 15 (parallel [(set (reg/v:HI 14 r14 [orig:41 b ] [41]) ; (and:HI (reg/v:HI 14 r14 [orig:41 b ] [41]) ; (const_int 15 [0xf]))) ; (clobber (reg:QI 24 r24)) ; ]) 45 {andhi3} (insn_list 8 (nil)) ; (expr_list:REG_UNUSED (reg:QI 24 r24) ; (nil))) ldi r24,lo8(15) ; , ; 14 andhi3/3 [length = 3] and r14,r24 ; b, clr r15 ; b
Disclaimer: none. Sue me.
also ich bin mir nicht so sicher ob ich deine Antwort verstanden habe?
also ich denke mal das die Constraints die in "" beschriebnen werte sind wie zB "=r,d,r" nur kann ich diese net so recht deuten! in der entsprechenden definition für den i386 sieht es wie folgt aus[(set (match_operand:HI 0 "register_operand" "=r,d,r")
(and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
(match_operand:HI 2 "nonmemory_operand" " r,i,M")))
(clobber (match_scratch:QI 3 "=X,X,&d"))]
hier werden keine solche angaben gemacht?(define_expand "andhi3"
[(set (match_operand:HI 0 "nonimmediate_operand" "")
(and:HI (match_operand:HI 1 "nonimmediate_operand" "")
(match_operand:HI 2 "general_operand" "")))
(clobber (reg:CC FLAGS_REG))] "TARGET_HIMODE_MATH"
"ix86_expand_binary_operator (AND, HImode, operands); DONE;")
PS: wo kann man den diese Sachen nachlesen?
In Expandern (define_expand) werden keine Constraints angegeben, man wird sogar angewarnt wenn man es tut. Ein Expander arbeitet ja auf Pseudo-Ebene. Constraints findest du zB bei Insns (define_insn, define_insn_and_split) und bei den Scratch-Regs für Peephole2 (define_peephole2).
RTL anhand von i386 zu lernen ist übel, weil das eines der komplexesten Maschinenbeschreibungen überhaupt ist; es kann Code für 32-Bit oder 64-Bit Maschinen ausgegeben werden, es werden unterschiedliche Assembler-Dialekte unterstützt, und es gibt *viele* Hacks.
reg 17 gehört zu den fixed Hard-Regs des i386, d.h. es wird nicht von GCC verwaltet. Von daher sind die Clobbers auf reg 17 nicht so spannend. Es heisst einfach, daß ein vorher in reg 17 vorhandener Wert nicht mehr verwendbar und futsch ist.
Gute Frage... Zum Einstieg ist das GCC Internals ganz ok. Teilweise Kommentare in den Quellen des Middle-End von gcc. Aber erschöpfende Auskunft und Spezifikation ist meiner Erfahrung nach Fehlanzeige. Zum Nachlesen ist das Genannte ganz ok, aber wenn man selber ein Backend implementiert stösst man fix an die Grenzen und man muss sich durchackern...Zitat von matzeed7
Disclaimer: none. Sue me.
Ach du schande da habe ich mich natürlich mit meinem i386 ganz schon was eingebrockt!!!
Ich schreibe zZ eine Art Semesterarbeit über die Möglichkeit, welche Aussagen man, über die Infos die man aus dem GCC mit -da und dann aus der *.c.00.expand datei erhält, treffen kann . Ziel ist also die Erstellung eines RTL parsers (den habe ich schon fast fertig) und dann halt noch die Umwandlung der einzelnen RTL Konstrukte (set, mem, plus....) in eine Art Pseudocode. Dafür brauch ich aber die Bedeutung der einzelnen Konstrukte!!!
Danke erst mal !!!!!!!
zZ hänge ich an der Fragestellung, wie ich den mem am besten darstellen kann, der er ja zum lesen und schreiben benutzt wird, zB
(set(reg:SI 61)(mem ...))
und dann halt noch
(set (mem ...)(reg:SI 66))
PS: diese Arbeit soll dann mal als Grundlage für gewisse tests dienen.
Lesezeichen