2012-10-27 14 views
9

fare diverse CPU x86 (con build-in FPU e ragionevolmente recente, diciamo lanciato questo millennio) produrre esattamente lo stesso risultato per i loro galleggianti primitive Point, assumendo la stessa istruzione è disponibile sul CPU a confronto, stesso ingresso e lo stesso parametri operativi come la modalità di arrotondamento? Non mi interessano le differenze nei tempi, né nello Pentium FDIV bug (che non si qualifica solo perché quell'incidente è antico).Le operazioni FP danno ESATTAMENTE lo stesso risultato su varie CPU x86?

Suppongo che la risposta sia sì per addizione, sottrazione, negazione e round-to-integer, poiché questi hanno definizioni precise, e non riesco a immaginare quale potrebbe essere una divergenza nelle implementazioni (breve forse di un bug nel rilevamento di overflow/underflow, ma quello sarebbe un disastro in alcune applicazioni, quindi immagino che questo sarebbe stato catturato e risolto molto tempo fa).

La moltiplicazione sembra più probabile che abbia implementazioni divergenti: determinare il numero a virgola mobile a doppia precisione (a 64 bit, incluso 52 + 1 di mantissa) del prodotto di due DPFPN a volte richiede il calcolo del prodotto di la loro mantissa alla (circa) accuratezza di 104 bit, che, per i pochi LSBit, è discutibilmente uno spreco di sforzi. Mi chiedo se questo sia addirittura tentato e fatto correttamente. O forse IEEE-754, o qualche standard de facto, prescrive qualcosa?

La divisione sembra ancora più delicata.

E, a meno di un progetto comune, dubito che tutte le implementazioni di cose molto più complesse (funzioni trigonometriche, log ..) potrebbero essere esattamente sincronizzate, data la varietà di metodi matematici che possono essere utilizzati.

Lo sto chiedendo da una combinazione di pura oscurità; disponibilità a migliorare that answer of mine; e il desiderio di un metodo per (a volte) consentire a un programma in esecuzione in una VM di rilevare una mancata corrispondenza tra la CPU che finge di essere in esecuzione e quella reale.

+1

Mentre la domanda è molto interessante (e mi piacerebbe vedere una risposta), sembra improbabile che si possa usare questo per rilevare la virtualizzazione. La maggior parte delle VM che eseguo (principalmente VMWare e KVM) hanno riportato correttamente la CPU fisica, quindi le stranezze del chipset non causerebbero una mancata corrispondenza in quel caso. – ssube

+0

La generazione di codice ottimizzata è una cosa molto più grande di cui preoccuparsi. L'FPU è * molto * difficile da ottimizzare in modo coerente. I compilatori di grandi motivi sono passati a SSE2. –

+0

Non sono d'accordo con i commenti ravvicinati. Sebbene la motivazione della domanda possa essere non costruttiva, la domanda reale è abbastanza valida e può essere "supportata da fatti, riferimenti o competenze specifiche". –

risposta

9

Sul livello di assemblaggio le istruzioni di base in virgola mobile (sommare, sottrarre, moltiplicare, dividere, radice quadrata, FMA, rotondo) producono sempre lo stesso risultato, come descritto dallo standard IEEE754. Esistono due tipi di istruzioni che possono produrre risultati diversi su architetture diverse: istruzioni FPU complesse per il calcolo di operazioni trascendentali (FSIN, FCOS, F2XM1 e simili) e istruzioni SSE approssimative (RCPSS/RCPPS per il calcolo reciproco approssimativo e RSQRTSS, RSQRTPS per calcolare la radice quadrata reciproca approssimativa). Le operazioni Transcendental x87 FPU sono implementate in microcodice e AFAIK tutte le CPU Intel e AMD tranne AMD K5 utilizzano lo stesso microcodice, quindi non è possibile utilizzarlo per il rilevamento. Potrebbe essere utile solo per il rilevamento di VIA, Cyrix, Transmeta e altre vecchie CPU, ma queste sono troppo rare da considerare. Le istruzioni SSE approssimative sono implementate in modo diverso su Intel e AMD e AFAIK presenta alcune differenze nell'implementazione su CPU AMD precedenti (pre-K8) e più recenti. È possibile utilizzare questa differenza per rilevare la CPU AMD che finge di essere Intel e viceversa, ma si tratta di un caso d'uso limitato.

+1

Ho eseguito alcuni esperimenti randomizzati che sono coerenti con [questo] (http://stackoverflow.com/a/13102431/903600) e [quell'altro] (http://stackoverflow.com/a/13102625/903600) risposta . Ho alimentato bit pseudo-casuali (convertiti in doppio lungo 80-bit usando un unione C) in '/', 'sqrtl',' sinl' (implementato come istruzioni x87) e ho cancellato i risultati (convertito in bit), 1e6 volte. L'unica differenza che ho individuato era con 'sinl', che ha dato diversi hash tra Intel e AMD (ma coerente tra PIII e Core i7, così come Athlon XP e Althlon 5050e). – fgrieu

2

Fatta eccezione per i casi estremi che sono molto ben documentati in errata, le istruzioni ALL IA-32 si comportano in modo identico tra i processori.

Le ovvie eccezioni sono, naturalmente, CPUID e gli accessi MSR.

Le non-eccezioni ovvie sono le varie operazioni logiche, integer e in virgola mobile. Come Maratyszcza ha scritto in his answer, molte delle operazioni più complesse sono calcolate dal microcodice. Questo microcodice può essere molto diverso tra processori con diverse microarchitetture, ma il risultato è garantito essere lo stesso.Intel, per esempio (non ho conoscenza diretta di altri sviluppatori x86), investe enormi risorse per assicurare la retrocompatibilità tra i processori, anche riproducendo un comportamento che è "buggato" (che cambia i bug nelle nuove specifiche).

Se l'architettura si comporta in modo diverso, ad esempio con VMX (Virtualizzazione) e SMM (Gestione sistema), le strutture di controllo includono un ID revisione. A tutti i processori che utilizzano lo stesso ID di revisione è garantito lo stesso comportamento per quanto riguarda queste architetture.

Per rispondere alla domanda originale, le operazioni FP, siano esse x87, SSE o AVX, danno lo stesso risultato su tutti i processori, in base allo IEEE 754.

Problemi correlati