Forskellen mellem opkalderbesparede og callee-gemte registre påvirker programpræstation og effektivitet markant, primært gennem omkostningerne til at gemme og gendanne registerværdier under funktionsopkald.
Opkalderbesparede registre (også kendt som flygtige registre):
* Definition: Disse registre er ansvaret for opkalder (funktionen, der foretager opkaldet) for at bevare, hvis deres værdier er nødvendige efter callee (funktionen, der kaldes) returnerer.
* mekanisme: Før den ringer til en funktion, hvis den, der ringer, har vigtige værdier, der er gemt i opkalderbesparede registre, skal den skubbe disse værdier på stakken (eller gemme dem andre steder i hukommelsen). Når Callee vender tilbage, kan den, der ringer, poppe de gemte værdier tilbage i disse registre.
* indflydelse på ydeevne:
* overhead på opkaldsstedet: Opkalderbesparede registre fører til overhead ved opkaldsfunktionen. Hvert opkald kræver muligvis at skubbe og sprænge registre, selvom Callee faktisk ikke bruger disse registre.
* potentielt mindre overhead, hvis Callee er enkel: Hvis Callee er lille og ikke behøver at bruge mange registre, behøver den, der ringer muligvis ikke for at gemme noget, hvilket gør opkaldet relativt effektivt. Opkalderen gemmer kun registre, den ved, at den har brug for *, og * Callee kan muligvis klappe.
* Velegnet til kortvarige værdier: God til variabler, der kun behøver at leve på tværs af et lille omfang, da redning/gendannelse bliver mindre af en bekymring.
* Eksempel: I mange x86-64 opkaldskonventioner (som System V AMD64 ABI), registre som `rax`,` rcx`, `rdi`,` rsi`, `r8`,` r9`, 'r10', 'r11' (og floating-point-registers som `xmm0-xmm15 'på nogle systemer) er kaldes-saved.
callee-gemte registre (også kendt som ikke-flygtige registre):
* Definition: Disse registre er ansvaret for callee (Funktionen kaldes) for at bevare. Hvis Callee ønsker at bruge dem, skal den gemme deres originale værdier i begyndelsen af funktionen og gendanne dem, før de vender tilbage.
* mekanisme: Callee skubber de originale værdier for disse registre på stakken i begyndelsen af dens udførelse. Før Callee vender tilbage, springer Callee disse værdier tilbage i registre og gendanner dem effektivt til deres oprindelige tilstand.
* indflydelse på ydeevne:
* overhead inden for callee: Callee-gemte registre introducerer overhead inden for Callee-funktionen. Hver callee, der bruger disse registre, skal udføre besparelse og gendannelse, uanset hvad den, der ringer, gør.
* bedre for Callee ved hjælp af mange registre: Hvis Callee har brug for en masse registre, kan det være mere effektive at bruge Callee-gemte registre end opkalderbesparede registre. Opkalderen er garanteret, at disse registre vil blive bevaret uden at skulle gøre noget.
* Velegnet til langvarige værdier: God til variabler, der har brug for at leve på tværs af et stort funktionsomfang, da omkostningen af redning/gendannelse afskrives over den længere varighed af deres anvendelse.
* Eksempel: I x86-64-systemet v amd64 ABI, registre som `rbx`,` rsp`, `rbp`,` r12`, `r13`,` r14`, `r15` er callee-gemte. `RSP 'er speciel (stakpointer), og` RBP' (basepointer) bruges ofte til stack rammehåndtering og fejlsøgning.
Nøgleforskelle og præstationsmæssige implikationer:
| Funktion | Opkalderbesparede registre | Callee-gemte registre |
| ---------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Ansvar | Opkalder for at gemme og gendanne om nødvendigt, før du ringer til en funktion. | Callee for at gemme og gendanne, hvis de bruges af callee. |
| Overhead | Primært ved opkaldsfunktionen (potentielt ingen overhead, hvis det ikke har brug for disse registre). | Primært inden for den kaldte funktion (overhead, uanset om den opkalder har brug for registre, der er bevaret). |
| Bedste brug | Når den, der ringer, skal bevare værdier på tværs af en lille undergruppe af opkald. | Når Callee er stor og sandsynligvis bruger mange registre, skal du undgå den, der ringer, at skulle redde mange mulige registre. |
| Eksempel (x86-64) | `rax`, 'rcx', 'rdi`,' rsi`, 'r8`,' r9 ',' r10 ',' r11 '| `rbx`,` rsp`, `rbp`,` r12`, `r13`,` r14`, `r15` |
hvilket er bedre?
Der er ingen universelt "bedre" tilgang. Det optimale valg afhænger af detaljerne i de opkaldskonventioner, programmets struktur, hyppigheden af funktionsopkald og størrelsen og kompleksiteten af funktionerne. Registerfordelingsstrategier, der bruges af kompilatorer og programmerere, sigter mod at minimere omkostningen af at spare og gendanne registre ved intelligent at vælge, hvilke registre de skal bruge til forskellige formål.
* Hyppige små opkald: Opkalderbesparet kan være at foretrække, da den, der ringer, kun sparer det, den har brug for. Callee får brug af registre uden besparelses-/gendannelse af omkostninger.
* sjældne store opkald: Callee-Gaved kan være at foretrække, hvis Callee bruger mange registre. Callee tager omkostningerne ved at spare/gendanne disse registre, men den, der ringer, frigøres fra at skulle forudse, hvilke registre der skal gemmes.
Kortfattet:
Valget mellem opkalderbesparede og callee-gemte registre involverer en afveksling mellem overhead på opkaldsstedet og overhead inden for den kaldte funktion. Effektive registerfordelings- og opkaldskonventioner sigter mod at minimere denne overhead for at forbedre programydelsen. Kompilatorer og monteringsprogrammerere skal forstå disse koncepter for at optimere kode for effektivitet. ABI (Application Binary Interface) definerer, hvilke registre der er opkaldere-gemt, og hvilke der er gældet til en bestemt arkitektur og operativsystem.