Istruzione (informatica)

Istruzione, in informatica, è un elemento di un programma che specifica un'operazione da eseguire oppure determina il flusso di esecuzione del programma stesso.

Il termine assume significati differenti a seconda del livello di astrazione considerato. Nei linguaggi di programmazione indica un costrutto sintattico (in inglese statement) che definisce un'azione o controlla l'esecuzione di altre istruzioni. Nel linguaggio macchina indica invece un'operazione codificata secondo l'insieme di istruzioni di un processore, direttamente eseguibile da un'architettura compatibile.

Definizione

Il significato di un'istruzione dipende dalla sintassi e dalla semantica del linguaggio utilizzato. Nei linguaggi di alto livello, le istruzioni possono modificare lo stato del programma, produrre effetti esterni oppure determinarne il flusso di esecuzione.

Nei linguaggi di alto livello, le istruzioni descrivono le operazioni da compiere e le regole che ne determinano l'ordine di esecuzione. Si distinguono dalle espressioni, generalmente utilizzate per calcolare valori, sebbene la distinzione sintattica e semantica vari da un linguaggio all'altro.

Le istruzioni possono essere semplici, quando costituiscono singoli costrutti del linguaggio, oppure composte, quando comprendono altre istruzioni organizzate secondo determinate regole sintattiche. La loro esecuzione può modificare lo stato del programma, produrre effetti esterni oppure determinare il successivo percorso di esecuzione.

Istruzioni nei linguaggi di programmazione

Nei linguaggi di programmazione, un'istruzione (in inglese statement) è un costrutto sintattico che specifica un'azione da eseguire o regola il flusso di controllo di un programma.

La sintassi e la semantica delle istruzioni variano a seconda del linguaggio utilizzato. Nei linguaggi imperativi, le istruzioni costituiscono uno dei principali strumenti per descrivere le operazioni e la sequenza della loro esecuzione.

In linguaggi come C e Java, molte istruzioni semplici terminano con un punto e virgola, mentre in Python la fine di un'istruzione è generalmente indicata dalla conclusione della riga logica.

Le istruzioni possono essere eseguite in sequenza oppure organizzate mediante strutture di controllo, che consentono di modificare l'ordine di esecuzione in base a condizioni, ripetizioni o trasferimenti del controllo.

Tipologie di istruzioni

Le istruzioni possono essere classificate in base alla funzione svolta durante l'esecuzione di un programma. Le categorie disponibili e la loro realizzazione sintattica dipendono dal linguaggio di programmazione utilizzato.

Istruzioni di assegnazione

Le istruzioni di assegnazione consentono di attribuire un valore a una variabile o a un'altra destinazione prevista dal linguaggio. Il valore assegnato può essere una costante oppure il risultato della valutazione di un'espressione.

Nel linguaggio C, ad esempio:

x = 10;
x = x + 5;

La prima istruzione assegna il valore 10 alla variabile x, mentre la seconda ne incrementa il valore di 5, assumendo che la variabile sia stata precedentemente dichiarata con un tipo appropriato.

L'assegnazione può essere rappresentata mediante operatori differenti a seconda del linguaggio. In alcuni linguaggi costituisce un'istruzione specifica, mentre in altri è un'espressione che può essere utilizzata come istruzione.

Istruzioni di ingresso e uscita

Le operazioni di ingresso e uscita (in inglese input/output, abbreviato I/O) consentono a un programma di ricevere dati dall'esterno e di produrre risultati destinati ad altri dispositivi, programmi o sistemi.

Le operazioni di ingresso permettono, ad esempio, di acquisire dati dalla tastiera, da un file o da una connessione di rete. Le operazioni di uscita consentono invece di visualizzare informazioni su uno schermo, scrivere dati in un file o trasmetterli attraverso una rete.

La gestione dell'ingresso e dell'uscita dipende dal linguaggio e dall'ambiente di esecuzione. Alcuni linguaggi prevedono istruzioni dedicate, mentre altri utilizzano principalmente funzioni o procedure fornite dalle librerie.

Nel linguaggio C, ad esempio, le funzioni della libreria standard stdio.h permettono di effettuare operazioni di ingresso e uscita:

int carattere = getchar();
puts("Esempio di uscita");

La funzione getchar() legge un carattere dallo standard input, oppure restituisce EOF quando viene raggiunta la fine dell'ingresso o si verifica un errore. La funzione puts() scrive una stringa sullo standard output, aggiungendo un carattere di nuova riga.

In questo caso, l'ingresso e l'uscita sono realizzati mediante chiamate a funzioni, anziché mediante istruzioni specifiche del linguaggio.

Istruzioni condizionali

Le istruzioni condizionali permettono di eseguire determinate operazioni soltanto quando una condizione risulta soddisfatta. Costituiscono una delle principali strutture di controllo utilizzate nella programmazione imperativa.

Una delle forme più diffuse è l'istruzione if, che consente di selezionare un percorso di esecuzione in base al risultato di una condizione. In molti linguaggi è possibile utilizzare anche una clausola else per specificare le operazioni alternative.

Nel linguaggio C, ad esempio:

if (x > 0) {
    printf("Numero positivo\n");
} else {
    printf("Numero non positivo\n");
}

Se la variabile x contiene un valore maggiore di zero, viene eseguito il primo blocco; in caso contrario, viene eseguito il secondo.

Alcuni linguaggi prevedono inoltre costrutti di selezione multipla, come switch, che consentono di scegliere tra diversi percorsi di esecuzione in base al valore di un'espressione.

Le istruzioni condizionali permettono quindi di introdurre comportamenti alternativi all'interno di un algoritmo, evitando che tutte le operazioni siano eseguite necessariamente in sequenza.

Istruzioni iterative

Le istruzioni iterative consentono di ripetere l'esecuzione di una o più istruzioni, formando un ciclo. La ripetizione può dipendere dalla valutazione di una condizione oppure dall'attraversamento degli elementi di una sequenza o di una collezione.

Nei linguaggi della famiglia del C, fra i principali costrutti iterativi figurano:

  • while: verifica una condizione prima di ogni iterazione ed esegue il corpo del ciclo finché questa risulta vera;
  • do...while: verifica la condizione dopo l'esecuzione del corpo, garantendone quindi almeno un'esecuzione;
  • for: riunisce in un unico costrutto le operazioni di inizializzazione, verifica della condizione e aggiornamento, quando previste.

Nel linguaggio C, ad esempio:

for (int i = 0; i < 5; i++) {
    printf("%d\n", i);
}

Il ciclo esegue cinque iterazioni, visualizzando i numeri interi da 0 a 4. La variabile i viene inizializzata a zero, incrementata dopo ogni iterazione e confrontata con il valore 5 prima di ogni esecuzione del corpo.

Le istruzioni iterative possono contenere altre strutture di controllo, compresi ulteriori cicli, dando origine a cicli annidati. L'esecuzione può inoltre essere modificata mediante istruzioni come break e continue, nei linguaggi che le prevedono.

Un ciclo può terminare quando la relativa condizione non è più soddisfatta oppure proseguire indefinitamente, dando origine a un ciclo infinito.

Istruzioni di trasferimento del controllo

Le istruzioni di trasferimento del controllo modificano il normale flusso di esecuzione di un programma, provocando il passaggio a un'altra istruzione o l'interruzione dell'esecuzione di una determinata struttura.

Nei linguaggi di programmazione imperativa, tra le principali istruzioni di questo tipo figurano:

  • break: interrompe l'esecuzione di un ciclo o di un costrutto di selezione, secondo le regole del linguaggio;
  • continue: interrompe l'iterazione corrente di un ciclo e passa alla fase successiva prevista dal costrutto;
  • return: termina l'esecuzione di una funzione, eventualmente restituendo un valore al chiamante;
  • goto: trasferisce il controllo a un'istruzione identificata mediante un'etichetta, nei linguaggi che lo prevedono.

Nel linguaggio C, ad esempio:

int cerca(int valore) {
    for (int i = 0; i < 10; i++) {
        if (i == valore) {
            return i;
        }
    }
    return -1;
}

L'istruzione return interrompe l'esecuzione della funzione e restituisce il valore specificato. Nell'esempio, la funzione restituisce un numero compreso tra 0 e 9 se il valore cercato appartiene a tale intervallo, oppure -1 in caso contrario.

L'utilizzo delle istruzioni di trasferimento del controllo dipende dalle regole sintattiche e semantiche del linguaggio adottato. Alcune, come goto, consentono salti espliciti all'interno del codice, mentre altre operano esclusivamente nell'ambito di specifiche strutture di controllo.

Blocchi di istruzioni

Un blocco di istruzioni è un raggruppamento di istruzioni che vengono trattate come un'unità sintattica all'interno di un linguaggio di programmazione. Nei linguaggi che prevedono istruzioni composte, un blocco può essere utilizzato nei punti in cui è ammessa una singola istruzione.

Nei linguaggi C e Java, i blocchi sono delimitati da parentesi graffe ({ }) e possono contenere istruzioni e dichiarazioni, secondo le regole del linguaggio.

Il seguente frammento di codice C mostra un blocco associato a un'istruzione condizionale:

int x = 5;

if (x > 0) {
    int y = x * 2;
    x = y + 1;
}

Le due istruzioni contenute nel blocco associato alla struttura if vengono eseguite soltanto se la condizione risulta vera.

I blocchi possono essere annidati, ossia contenere al proprio interno altri blocchi, permettendo di costruire strutture di controllo articolate.

In molti linguaggi, i blocchi contribuiscono inoltre a definire l'ambito di visibilità delle variabili e di altri identificatori. In C, ad esempio, una variabile dichiarata all'interno di un blocco possiede generalmente un ambito di visibilità limitato a quel blocco.

Un blocco costituisce un'unità sintattica del linguaggio sorgente e non corrisponde necessariamente a una singola istruzione macchina: la sua traduzione dipende dal compilatore, dalle operazioni contenute e dalle eventuali ottimizzazioni applicate.

Istruzioni in linguaggio macchina

Un'istruzione macchina è un'operazione elementare codificata in forma binaria ed eseguibile da un processore compatibile. L'insieme delle istruzioni disponibili, le loro modalità di codifica e il comportamento previsto sono definiti dall'architettura dell'insieme di istruzioni (Instruction Set Architecture, ISA).

A differenza delle istruzioni espresse nei linguaggi di alto livello, le istruzioni macchina specificano operazioni direttamente riconosciute dall'architettura del processore, come calcoli aritmetici, operazioni logiche, trasferimenti di dati e modifiche del flusso di controllo.

Ogni istruzione è rappresentata da una sequenza di bit, la cui lunghezza può essere fissa oppure variabile a seconda dell'architettura. La codifica comprende generalmente un codice operativo (opcode), che identifica l'operazione, ed eventuali campi aggiuntivi che specificano gli operandi e le modalità di esecuzione.

Le istruzioni macchina possono essere rappresentate simbolicamente mediante un linguaggio assembly, che utilizza nomi mnemonici e altre notazioni leggibili al posto delle corrispondenti codifiche binarie.

L'esecuzione di un'istruzione può modificare il contenuto dei registri, accedere alla memoria o modificare il percorso di esecuzione del programma. Alcune istruzioni, come quelle di tipo NOP (no operation), non producono invece modifiche significative allo stato architetturale, fatta eccezione per l'avanzamento dell'esecuzione e gli eventuali effetti previsti dall'architettura.

Codifica delle istruzioni

La codifica delle istruzioni è il processo mediante il quale le operazioni previste dall'architettura dell'insieme di istruzioni (ISA) vengono rappresentate attraverso sequenze di bit interpretabili dal processore.

Un'istruzione macchina comprende generalmente diversi campi, la cui disposizione e dimensione dipendono dall'architettura:

La lunghezza delle istruzioni può essere fissa oppure variabile. Nel primo caso, le istruzioni di un determinato insieme hanno una dimensione uniforme; nel secondo possono occupare un numero differente di byte.

Un esempio di codifica a lunghezza fissa è rappresentato dall'insieme di istruzioni di base RV32I dell'architettura RISC-V, nel quale ogni istruzione occupa 32 bit. Sono previsti quattro formati fondamentali, denominati R, I, S e U, e due varianti, B e J, utilizzate per specifiche istruzioni di controllo del flusso.

L'architettura x86, invece, utilizza istruzioni di lunghezza variabile, composte da uno o più campi che possono includere prefissi, codice operativo, informazioni sugli operandi e valori immediati.

La codifica binaria viene normalmente generata da un assemblatore o da un compilatore, mentre il linguaggio assembly ne fornisce una rappresentazione simbolica più facilmente leggibile.

Operandi e modalità di indirizzamento

Gli operandi sono i dati sui quali agisce un'istruzione macchina. A seconda dell'operazione e dell'architettura del processore, possono rappresentare valori numerici, contenuti di registri, posizioni di memoria o altre informazioni necessarie all'esecuzione.

Le modalità di indirizzamento (addressing modes) definiscono il modo in cui un'istruzione individua i propri operandi. Le modalità disponibili dipendono dall'architettura dell'insieme di istruzioni e possono comprendere:

Le diverse architetture possono utilizzare combinazioni e varianti di queste modalità.

Nell'architettura RISC-V, ad esempio, le istruzioni di caricamento e memorizzazione del sottoinsieme RV32I utilizzano un indirizzamento basato sulla somma del contenuto di un registro e di uno spostamento immediato con segno di 12 bit.

Un esempio in linguaggio assembly RISC-V è:

lw x5, 8(x10)

L'istruzione lw (load word) carica nel registro x5 un valore di 32 bit prelevato dalla memoria all'indirizzo ottenuto sommando 8 al contenuto del registro x10.

Nell'architettura x86, invece, l'indirizzamento della memoria può combinare un registro base, un registro indice moltiplicato per un fattore di scala e uno spostamento costante.

La scelta delle modalità di indirizzamento influenza la rappresentazione delle istruzioni e le operazioni necessarie per accedere ai dati durante l'esecuzione.

Classificazione delle istruzioni macchina

Le istruzioni macchina possono essere classificate in base alla funzione svolta nell'elaborazione dei dati e nel controllo dell'esecuzione del programma.

Una classificazione generale distingue le seguenti categorie:

Alcune architetture prevedono inoltre istruzioni specializzate per l'elaborazione di numeri in virgola mobile, le operazioni SIMD, la sincronizzazione tra processori, la gestione delle eccezioni e le funzioni privilegiate del sistema.

Questa classificazione non è esclusiva né universale: una stessa istruzione può svolgere più funzioni e la suddivisione effettiva dipende dall'architettura dell'insieme di istruzioni (ISA).

Le architetture RISC e CISC adottano approcci differenti alla progettazione e alla complessità delle istruzioni, pur potendo supportare categorie funzionali analoghe.

Istruzioni aritmetiche e logiche

Le istruzioni aritmetiche e logiche permettono al processore di eseguire operazioni matematiche e manipolazioni sui bit degli operandi. Costituiscono una delle principali categorie di istruzioni macchina e vengono generalmente elaborate mediante l'unità aritmetica e logica (ALU).

Tra le operazioni più comuni figurano:

  • Addizione e sottrazione: calcolano rispettivamente la somma e la differenza tra valori numerici.
  • Moltiplicazione e divisione: eseguono operazioni aritmetiche più complesse, quando supportate dall'insieme di istruzioni.
  • Operazioni logiche: applicano operatori booleani sui singoli bit, come AND, OR e XOR.
  • Operazioni di confronto: confrontano due valori e producono un risultato utilizzabile per determinare il successivo comportamento del programma.
  • Operazioni di scorrimento: spostano i bit di un operando verso destra o verso sinistra, secondo modalità logiche o aritmetiche.

Nell'architettura RISC-V, ad esempio, l'istruzione assembly:

add x5, x6, x7

somma i contenuti dei registri x6 e x7, memorizzando il risultato nel registro x5.

Analogamente, l'istruzione:

and x5, x6, x7

esegue un'operazione AND bit a bit tra i contenuti dei registri x6 e x7, scrivendo il risultato nel registro x5.

L'insieme di istruzioni di base RV32I comprende operazioni aritmetiche, logiche, di confronto e di scorrimento su valori interi a 32 bit. Le operazioni intere di moltiplicazione e divisione sono invece definite nell'estensione standard M dell'architettura.

Le istruzioni aritmetiche e logiche possono modificare i registri di destinazione e, in alcune architetture, aggiornare appositi registri di stato contenenti informazioni sul risultato delle operazioni, come gli indicatori di zero, riporto o overflow.

Istruzioni di trasferimento dei dati

Le istruzioni di trasferimento dei dati consentono di copiare o spostare informazioni tra i registri del processore, la memoria e, nelle architetture che lo prevedono, i dispositivi di ingresso e uscita.

Queste istruzioni non eseguono necessariamente operazioni aritmetiche sui dati, ma ne modificano la collocazione all'interno del sistema.

Tra le principali operazioni di trasferimento figurano:

  • Caricamento (load): copia un valore dalla memoria a un registro.
  • Memorizzazione (store): copia un valore da un registro alla memoria.
  • Trasferimento tra registri: copia il contenuto di un registro in un altro, quando previsto dall'architettura.
  • Operazioni di ingresso e uscita: trasferiscono dati tra il processore e i dispositivi periferici, mediante istruzioni dedicate oppure accessi a indirizzi di memoria associati ai dispositivi.

Nelle architetture di tipo load-store, come RISC-V, le istruzioni aritmetiche operano sui registri, mentre l'accesso ordinario ai dati in memoria avviene mediante istruzioni specifiche di caricamento e memorizzazione.

Un esempio in linguaggio assembly RISC-V è:

lw x5, 0(x10)
sw x5, 4(x10)

La prima istruzione, lw (load word), carica nel registro x5 un valore di 32 bit dalla posizione di memoria il cui indirizzo è contenuto nel registro x10.

La seconda istruzione, sw (store word), memorizza il contenuto di x5 all'indirizzo ottenuto sommando 4 al contenuto di x10.

Nell'esempio si presuppone che gli indirizzi siano validi, accessibili e correttamente allineati.

Le istruzioni di trasferimento possono operare su dati di dimensioni differenti, come byte, parole a 16, 32 o 64 bit, a seconda dell'architettura.

Nelle architetture che utilizzano l'ingresso e uscita mappato in memoria (memory-mapped I/O), anche la comunicazione con determinate periferiche può avvenire mediante normali istruzioni di lettura e scrittura della memoria.

Le modalità di trasferimento, le dimensioni dei dati supportate e gli eventuali vincoli di allineamento sono definiti dall'architettura e dall'ambiente di esecuzione.

Istruzioni di controllo del flusso

Le istruzioni di controllo del flusso modificano l'ordine di esecuzione delle istruzioni macchina, consentendo al processore di proseguire da un indirizzo diverso da quello dell'istruzione successiva.

Le principali categorie comprendono:

  • Salti incondizionati: trasferiscono il controllo a un indirizzo specificato senza verificare condizioni.
  • Salti condizionati: modificano il flusso di esecuzione soltanto quando una determinata condizione risulta soddisfatta.
  • Chiamate a sottoprogrammi: trasferiscono il controllo a una subroutine, conservando le informazioni necessarie per riprendere l'esecuzione.
  • Ritorni da sottoprogrammi: permettono di riprendere l'esecuzione dal punto successivo alla chiamata.

Nell'architettura RISC-V, ad esempio, l'istruzione:

beq x5, x6, etichetta

esegue un salto all'indirizzo associato a etichetta se i registri x5 e x6 contengono valori uguali. In caso contrario, l'esecuzione prosegue con l'istruzione successiva.

L'istruzione jal (jump and link) consente invece di effettuare un salto incondizionato, memorizzando in un registro l'indirizzo di ritorno. L'istruzione jalr permette di eseguire un salto il cui indirizzo di destinazione viene calcolato utilizzando un registro.

Le istruzioni di controllo del flusso modificano quindi il valore del program counter, il registro che identifica l'indirizzo dell'istruzione corrente o della successiva istruzione da eseguire, secondo l'architettura considerata.

Nei processori dotati di pipeline, i salti possono influenzare le prestazioni, poiché la destinazione del trasferimento del controllo potrebbe non essere immediatamente nota. Per ridurre questi effetti, molti processori utilizzano tecniche di predizione delle diramazioni.

Ciclo di esecuzione delle istruzioni

Il ciclo di esecuzione delle istruzioni (in inglese instruction cycle) è l'insieme delle operazioni mediante le quali un processore preleva, interpreta ed esegue le istruzioni macchina di un programma.

In un modello semplificato, il ciclo comprende tre fasi fondamentali:

In alcune implementazioni vengono distinte ulteriori fasi, come l'accesso alla memoria (memory access) e la scrittura del risultato (write-back) nei registri di destinazione.

Il ciclo di esecuzione non deve necessariamente corrispondere a un singolo ciclo di clock. Il numero di cicli richiesti dipende dall'istruzione e dall'organizzazione interna del processore.

Nei processori dotati di pipeline, le diverse fasi possono essere sovrapposte, consentendo l'elaborazione contemporanea di più istruzioni in stadi differenti. Alcune microarchitetture supportano inoltre l'esecuzione fuori ordine, nella quale determinate operazioni possono essere elaborate in un ordine diverso da quello del programma, pur rispettando il comportamento architetturale previsto.

Durante l'esecuzione possono inoltre verificarsi eccezioni o interrupt, che provocano il trasferimento del controllo a specifiche procedure di gestione.

Relazione tra istruzioni sorgente e istruzioni macchina

Le istruzioni espresse nel codice sorgente di un programma e quelle eseguite dal processore appartengono a livelli di astrazione differenti.

Nei linguaggi di alto livello, le istruzioni descrivono operazioni mediante costrutti sintattici relativamente indipendenti dall'architettura hardware. Le istruzioni macchina, invece, rappresentano operazioni definite dall'architettura dell'insieme di istruzioni (ISA) del processore.

Il passaggio dal codice sorgente all'esecuzione può avvenire attraverso differenti meccanismi, tra cui la compilazione, l'interpretazione e l'impiego di rappresentazioni intermedie, come il bytecode.

Non esiste una corrispondenza necessariamente univoca tra un'istruzione del linguaggio sorgente e un'istruzione macchina. Una singola istruzione di alto livello può richiedere numerose istruzioni macchina, mentre più istruzioni sorgente possono essere tradotte in una sequenza più breve di operazioni.

Il numero e la disposizione delle istruzioni macchina dipendono da diversi fattori, tra cui:

Alcune operazioni specificate nel codice sorgente possono inoltre essere eliminate durante la compilazione quando il compilatore determina che non contribuiscono al comportamento osservabile del programma, secondo le regole del linguaggio.

La relazione tra istruzioni sorgente e istruzioni macchina non è quindi una semplice sostituzione di singole istruzioni, ma dipende dal processo di traduzione e dalle modalità di esecuzione adottate.

Compilazione

La compilazione è il processo mediante il quale un compilatore traduce un programma scritto in un linguaggio di programmazione in una rappresentazione di livello inferiore, che può comprendere linguaggio assembly, linguaggio macchina o codice intermedio.

Il processo di compilazione può comprendere diverse fasi:

Le fasi effettivamente adottate e il loro ordine dipendono dall'implementazione del compilatore.

Nel caso di un compilatore che produce codice macchina, le istruzioni del linguaggio sorgente vengono tradotte in operazioni compatibili con l'architettura dell'insieme di istruzioni del processore di destinazione.

Il codice risultante può richiedere ulteriori operazioni, come l'assemblaggio e il collegamento (linking), prima di poter essere eseguito.

La compilazione non implica necessariamente la produzione immediata di un file eseguibile: alcuni compilatori generano rappresentazioni intermedie destinate a ulteriori elaborazioni o all'esecuzione mediante una macchina virtuale.

Interpretazione

L'interpretazione è una modalità di esecuzione dei programmi nella quale un interprete elabora le istruzioni di un linguaggio di programmazione, determinando le operazioni da compiere durante l'esecuzione.

A differenza della compilazione tradizionale in codice macchina, l'interpretazione non richiede necessariamente la generazione preventiva di un file eseguibile autonomo. L'interprete può elaborare direttamente il codice sorgente oppure una sua rappresentazione intermedia.

Il funzionamento dipende dall'implementazione del linguaggio. Si possono distinguere, in particolare:

Un esempio è rappresentato dall'implementazione CPython del linguaggio Python, nella quale il codice sorgente viene compilato in bytecode, successivamente eseguito dalla macchina virtuale dell'interprete.

La distinzione tra linguaggi compilati e interpretati non è assoluta: uno stesso linguaggio può disporre di implementazioni basate su strategie differenti o combinare compilazione e interpretazione.

L'interpretazione costituisce quindi una modalità di esecuzione del programma e non una caratteristica necessariamente esclusiva di un determinato linguaggio.

Ottimizzazione delle istruzioni

L'ottimizzazione delle istruzioni comprende le trasformazioni applicate al codice di un programma per migliorarne determinate caratteristiche, come la velocità di esecuzione, l'occupazione di memoria o la dimensione del codice generato, preservando il comportamento previsto dalle regole del linguaggio.

Nei compilatori ottimizzanti, queste trasformazioni possono essere effettuate sul codice intermedio oppure durante la generazione delle istruzioni macchina.

Tra le principali tecniche figurano:

Le ottimizzazioni possono modificare il numero, l'ordine e la struttura delle istruzioni macchina generate. Non comportano necessariamente una riduzione del numero di istruzioni: alcune trasformazioni aumentano la dimensione del codice per migliorare le prestazioni.

L'efficacia delle ottimizzazioni dipende dall'architettura di destinazione, dalle caratteristiche del programma e dalle opzioni di compilazione selezionate.

Note

  1. ↑ Istruzione, in Enciclopedia della Matematica, Istituto dell'Enciclopedia Italiana, 2013.
  2. 1 2 3 (EN) Chapter 14. Blocks, Statements, and Patterns, su The Java Language Specification, Oracle.
  3. 1 2 Cenni preliminari sulle istruzioni C, su Microsoft Learn, Microsoft.
  4. ↑ Istruzione while (C), su Microsoft Learn, Microsoft.
  5. ↑ Istruzione do-while (C), su Microsoft Learn, Microsoft.
  6. 1 2 3 4 5 6 7 8 9 (EN) RV32I Base Integer Instruction Set, Version 2.1, su RISC-V Ratified Specifications Library, RISC-V International.
  7. ↑ (EN) Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1: Basic Architecture (PDF), su cdrdv2-public.intel.com, Intel, Sezione 3.7.
  8. ↑ (EN) What is a Central Processing Unit (CPU)?, su IBM Think, IBM.
  9. ↑ (EN) Armv8-A Instruction Set Architecture, su developer.arm.com, Arm, Sezione 5, Simple sequential execution.
  10. 1 2 3 Cos'è un compilatore?, su IBM Think, IBM.
  11. ↑ (EN) Glossary, su Python Documentation, Python Software Foundation, Voci «bytecode», «interpreted» e «virtual machine».
  12. ↑ (EN) Options That Control Optimization, su Using the GNU Compiler Collection (GCC), GNU Project.
  13. ↑ (EN) LLVM's Analysis and Transform Passes, su LLVM Documentation, LLVM Project.

Bibliografia

Voci correlate

  Portale Informatica: accedi alle voci di Wikipedia che trattano di informatica