Arsitektur eksotis yang menjadi perhatian komite standar

154

Saya tahu bahwa standar C dan C ++ meninggalkan banyak aspek implementasi bahasa yang ditentukan hanya karena jika ada arsitektur dengan karakteristik lain, akan sangat sulit atau tidak mungkin untuk menulis kompiler yang sesuai standar untuk itu.

Saya tahu bahwa 40 tahun yang lalu komputer mana pun memiliki spesifikasi uniknya sendiri. Namun, saya tidak tahu ada arsitektur yang digunakan saat ini di mana:

  • CHAR_BIT != 8
  • signed bukan pelengkap dua (saya mendengar Jawa punya masalah dengan yang satu ini).
  • Floating point tidak sesuai dengan IEEE 754 (Edit: Maksud saya "tidak dalam pengkodean biner IEEE 754").

Alasan saya bertanya adalah bahwa saya sering menjelaskan kepada orang-orang bahwa ada baiknya C ++ tidak mengamanatkan aspek tingkat rendah lainnya seperti tipe berukuran tetap . Ini bagus karena tidak seperti 'bahasa lain' itu membuat kode Anda portabel ketika digunakan dengan benar (Edit: karena dapat porting ke lebih banyak arsitektur tanpa memerlukan emulasi aspek tingkat rendah dari mesin, seperti misalnya aritmatika komplemen dua pada arsitektur tanda + magnitude) . Tetapi saya merasa tidak enak karena saya sendiri tidak dapat menunjuk ke arsitektur tertentu.

Jadi pertanyaannya adalah: arsitektur apa yang memperlihatkan properti di atas?

Ini uint*_topsional.

Yakov Galka
sumber
9
Saya pikir Anda memilikinya mundur. Jika C ++ adalah mandat, katakanlah, dua pelengkap untuk bilangan bulat yang ditandatangani, itu akan membuat kode C ++ lebih portabel tidak kurang. Pertanyaan mengapa komite standar C ++ tidak mengamanatkan ini adalah masalah lain. Terutama karena, terlepas dari apa yang Anda katakan, bukan tidak mungkin untuk menulis kompiler untuk arsitektur non-standar, Anda selalu dapat mensimulasikan 8 bit karakter atau dua aritmatika komplemen bahkan ketika platform Anda tidak mendukungnya secara langsung.
john
8
@ John: maka itu akan menjadi tidak praktis sehingga kompiler yang tidak standar akan menghasilkan kode yang lebih cepat daripada yang sesuai. Dan saya masih tidak melihat bagaimana itu membuat kode Anda lebih portabel.
Yakov Galka
4
Saya yakin alasan sebenarnya dari standar ini adalah bukan karena ini adalah solusi ideal. Tetapi sebaliknya itu karena ketika standar ditulis banyak kompiler C dan C ++ sudah ada, dan komite standar tidak ingin menolak kompiler yang ada.
john
4
@ John: Saya ragu bahwa "membuatnya lebih mudah bagi penulis kompiler" adalah prioritas saat membuat standar C ++ (mereka akan melakukan pekerjaan yang buruk jika itu, karena C ++ adalah salah satu bahasa yang paling sulit untuk diurai, dan aspek lain dari bahasa tidak juga membuatnya mudah bagi penulis kompiler). Kinerja, dukungan platform luas, dan kompatibilitas ke belakang cukup penting. Dan ketiganya akan menderita jika pembatasan yang Anda sebutkan akan ditambahkan ke standar.
Sander De Dycker
5
Ini bukan tentang kompiler tetapi perangkat keras. C ++ meninggalkan beberapa hal yang tidak ditentukan untuk memungkinkan penggunaan langsung fitur-fitur perangkat keras. Aplikasi ponsel Anda tidak akan berjalan pada mainframe, jadi tidak ada portabilitas namun sesuai dengan kode tersebut.
Bo Persson

Jawaban:

114

Lihatlah yang ini

Server Unisys ClearPath Dorado

menawarkan kompatibilitas ke belakang untuk orang-orang yang belum memigrasikan semua perangkat lunak Univac mereka.

Poin-poin penting:

  • Kata 36-bit
  • CHAR_BIT == 9
  • pelengkap seseorang
  • 72-bit floating point non-IEEE
  • ruang alamat terpisah untuk kode dan data
  • kata-dialamatkan
  • tidak ada stack pointer khusus

Tidak tahu apakah mereka menawarkan kompiler C ++, tetapi mereka bisa .


Dan sekarang tautan ke edisi terbaru dari manual C mereka telah muncul:

Manual Referensi Pemrograman Unisys C Compiler

Bagian 4.5 memiliki tabel tipe data dengan 9, 18, 36, dan 72 bit.

ukuran dan rentang tipe data dalam kompiler USC C

Bo Persson
sumber
13
Saya kira void * pasti neraka untuk digunakan dalam arsitektur itu.
luiscubal
13
@ybungalobill - Saya percaya char*dan void*harus memiliki ukuran yang sama, dan cukup besar untuk menampung pointer lainnya. Sisanya terserah implementasi.
Bo Persson
22
@ybungalobill: Pada kompiler Win16 lama, pointer reguler dekat pointer dan berisi hanya offset 16-bit, jadi sizeof(int*) == 2, tetapi pointer jauh juga memiliki pemilih 16-bit, jadi sizeof(void*) == 4.
Adam Rosenfield
10
Ada, atau dulu, manual on-line untuk kompiler C ++ mereka. Ini juga layak menunjukkan bahwa ini hanyalah salah satu arsitektur mainframe Unisys: yang lain adalah arsitektur bertanda magnit tagged 48 bit (yang saya hanya menemukan manual C, bukan C ++ satu). Mengenai sisanya: Saya tidak berpikir bahwa di sizeof(int*) != sizeof(char*)sini: keduanya 36 bit. Tetapi pemilih byte di char*adalah pada bit urutan tinggi, dan diabaikan di int*. (Saya telah menggunakan mesin lain, di mana `sizeof (char *)> sizeof (int *).)
James Kanze
16
@Adam Rosenfield Pada kompiler MS / DOS 16 bit, Anda memiliki "mode" yang berbeda, dan pointer data tidak harus sama ukurannya dengan pointer fungsi. Tetapi setidaknya pada yang saya gunakan, semua pointer data (termasuk void*) selalu memiliki ukuran yang sama. (Tentu saja, Anda tidak dapat mengonversi fungsi pointer ke void*, karena void*mungkin lebih kecil. Tetapi menurut standar, Anda juga tidak dapat melakukannya hari ini.)
James Kanze
51

Tidak ada asumsi Anda yang berlaku untuk mainframe. Sebagai permulaan, saya tidak tahu tentang mainframe yang menggunakan IEEE 754: IBM menggunakan basis 16 floating point, dan kedua mainframe Unisys menggunakan basis 8. Mesin Unisys sedikit istimewa dalam banyak hal lain: Bo telah menyebutkan 2200 arsitektur, tetapi arsitektur MPS bahkan lebih aneh: kata-kata dengan tag 48 bit. (Apakah kata itu penunjuk atau tidak tergantung pada sedikit kata tersebut.) Dan representasi numerik dirancang sedemikian rupa sehingga tidak ada perbedaan nyata antara titik mengambang dan aritmatika integral: titik mengambang adalah basis 8; itu tidak memerlukan normalisasi, dan tidak seperti setiap titik apung lain yang pernah saya lihat, itu menempatkan desimal di sebelah kanan mantissa, daripada ke kiri, dan menggunakan besaran yang ditandatangani untuk eksponen (di samping mantissa). Dengan hasil bahwa nilai floating point integral memiliki (atau dapat memiliki) representasi bit yang sama persis dengan integer magnitudo yang ditandatangani. Dan tidak ada instruksi aritmatika floating point: jika eksponen dari kedua nilai keduanya 0, instruksi melakukan aritmatika integral, jika tidak, itu aritmatika floating point. (Kelanjutan dari filosofi penandaan dalam arsitektur.) Yang berarti itu sementaraint dapat menempati 48 bit, 8 di antaranya harus 0, atau nilainya tidak akan diperlakukan sebagai bilangan bulat.

James Kanze
sumber
4
Mainframe IBM (z / Arsitektur) mendukung IEE754 floating point.
Nikita Nemkin
1
fyi lihat komentar twitter ini
Shafik Yaghmour
6
@ Nikita - Mereka lakukan sekarang . Awalnya itu add-on (mahal) untuk mendukung Java.
Bo Persson
42

Kepatuhan penuh IEEE 754 jarang terjadi dalam implementasi floating-point. Dan melemahkan spesifikasi dalam hal itu memungkinkan banyak optimasi.

Misalnya dukungan subnorm berbeda antara x87 dan SSE.

Optimasi seperti menggabungkan penggandaan dan penambahan yang terpisah dalam kode sumber sedikit mengubah hasil juga, tetapi optimasi yang bagus pada beberapa arsitektur.

Atau pada x86 kepatuhan IEEE yang ketat mungkin memerlukan flag tertentu yang ditetapkan atau transfer tambahan antara register titik mengambang dan memori normal untuk memaksanya menggunakan jenis titik mengambang yang ditentukan alih-alih float 80bit internal.

Dan beberapa platform tidak memiliki perangkat keras mengapung sama sekali dan dengan demikian perlu meniru mereka dalam perangkat lunak. Dan beberapa persyaratan IEEE 754 mungkin mahal untuk diimplementasikan dalam perangkat lunak. Secara khusus aturan pembulatan mungkin menjadi masalah.

Kesimpulan saya adalah bahwa Anda tidak perlu arsitektur eksotis untuk masuk ke situasi yang Anda tidak selalu ingin menjamin kepatuhan IEEE yang ketat. Untuk alasan ini adalah beberapa bahasa pemrograman menjamin kepatuhan IEEE yang ketat.

CodesInChaos
sumber
7
Satu set perangkat keras "eksotis" lainnya adalah mainframe IBM di mana format floating point mendahului standar IEEE. Tidak seperti Java, C ++ masih dapat menggunakan perangkat keras yang ada.
Bo Persson
5
IEEE 754 tidak sepenuhnya didukung oleh GPU.
kerem
3
Kurangnya kepatuhan yang ketat terhadap IEEE 754 mengganggu bagi sebagian orang, tapi saya rasa tidak cukup dalam lingkup masalah yang sangat diperhatikan OP.
Mahakuasa
3
@ Matthieu Karena ini juga ditandai "C", saya harus menyebutkan penganalisis C yang dapat memberi tahu Anda semua nilai yang mungkin diambil oleh program titik-mengambang Anda dengan register floating-point 80 bit yang tumpah ke memori saat kehendak kompiler C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq
2
@ MatthieuM .: Terlalu buruk ISO / ANSI tidak mengizinkan parameter variad untuk menentukan ukuran minimum / maksimum untuk argumen floating-point dan integer; jika mereka punya, 80-bit long doublebisa menjadi tipe yang berguna dan berumur panjang, karena satu-satunya masalah dengan itu adalah bahwa ia bekerja dengan buruk printf. Fakta bahwa perpanjangan ganda menyimpan angka 1 terdepan secara eksplisit mempercepat perhitungan pada sistem non-FPU dan juga akan menghilangkan perlunya penanganan khusus penolakan dalam konteks apa pun selain konversi ke / dari jenis lain. Sayang sekali C printfmengacaukan semuanya.
supercat
40

Saya menemukan tautan ini mendaftar beberapa sistem di mana CHAR_BIT != 8. Mereka termasuk

beberapa DSP TI miliki CHAR_BIT == 16

Chip BlueCore-5 (chip Bluetooth dari Cambridge Silicon Radio) yang sudah CHAR_BIT == 16.

Dan tentu saja ada pertanyaan tentang Stack Overflow: Platform apa yang memiliki sesuatu selain 8-bit char

Sedangkan untuk sistem non-komplemen ada bacaan menarik di comp.lang.c ++. Dimoderasi . Ringkasnya: ada platform yang memiliki pelengkap atau tanda dan representasi besarnya.

dcn
sumber
5
Perangkat Analog 32-bit SHARC DSP miliki CHAR_BIT=32, dan Texas Instruments DSP dari TMS32F28xx miliki CHAR_BIT=16. GCC 3.2 untuk PDP-10 miliki CHAR_BIT=9. Saya pikir, S / 360 mungkin memiliki char tidak-8bit juga.
osgx
1
Saya masih ingin contoh untuk arsitektur 'non-komplemen'. Terutama karena kebetulan itu CHAR_BITSadalah duplikat parsial.
Yakov Galka
TI DSP memiliki karakter 16-bit hanya karena pelaksana memilihnya (itu akan menjadi pekerjaan yang lebih sedikit untuk membuatnya berfungsi dengan benar, tetapi IIRC tidak terlalu sulit - mungkin hanya beberapa "lubang" dalam perancah codegen dalam kompiler yang mendasarinya) . Jadi itu bukan alasan arsitektur yang mendalam. Kode C bekerja pada mesin abstrak. Jika yang Anda miliki adalah 16-bit INT, simpan dua karakter di masing-masing, dan tambahkan penggabungan baca-modifikasi-tulis ke pengoptimal lubang (paling tidak). Tentu, ini lebih banyak pekerjaan, tetapi lihatlah betapa lebih banyak pekerjaan bagi semua orang untuk berurusan dengan tipe aneh di tempat-tempat di mana mereka tidak akan pernah muncul. Yuck.
Pasang kembali Monica
24

Saya cukup yakin bahwa sistem VAX masih digunakan. Mereka tidak mendukung IEEE floating-point; mereka menggunakan format mereka sendiri. Alpha mendukung format floating-point VAX dan IEEE.

Mesin vektor Cray, seperti T90, juga memiliki format floating-point sendiri, meskipun sistem Cray yang lebih baru menggunakan IEEE. (T90 yang saya gunakan dinonaktifkan beberapa tahun yang lalu; Saya tidak tahu apakah ada yang masih aktif digunakan.)

T90 juga memiliki / memiliki beberapa representasi menarik untuk pointer dan integer. Alamat asli hanya dapat menunjuk ke kata 64-bit. Kompiler C dan C ++ memiliki CHAR_BIT == 8 (diperlukan karena menjalankan Unicos, rasa Unix, dan harus beroperasi dengan sistem lain), tetapi alamat asli hanya dapat menunjuk pada kata 64-bit. Semua operasi tingkat byte disintesis oleh kompiler, dan a void*atau char*menyimpan byte offset dalam urutan tinggi 3 bit kata. Dan saya pikir beberapa tipe integer memiliki bit padding.

Mainframe IBM adalah contoh lain.

Di sisi lain, sistem khusus ini tidak perlu menghalangi perubahan standar bahasa. Cray tidak menunjukkan minat khusus untuk meningkatkan kompiler C menjadi C99; agaknya hal yang sama diterapkan pada kompiler C ++. Ini mungkin masuk akal untuk memperketat persyaratan untuk implementasi host, seperti membutuhkan CHAR_BIT == 8, Format IEEE floating-point jika tidak semantik penuh, dan 2's-pelengkap tanpa bantalan bit untuk bilangan bulat ditandatangani. Sistem lama dapat terus mendukung standar bahasa sebelumnya (C90 tidak mati ketika C99 keluar), dan persyaratannya bisa lebih longgar untuk implementasi freestanding (embedded system) seperti DSP.

Di sisi lain, mungkin ada alasan bagus untuk sistem masa depan untuk melakukan hal-hal yang dianggap eksotis hari ini.

Keith Thompson
sumber
6
Poin bagus di akhir tentang bagaimana standar yang terlalu ketat mencegah inovasi. Ketika kita mendapatkan komputer kuantum (atau organik) dengan status triner, persyaratan modulo aritmatika untuk unsignedtipe integral akan menjadi masalah besar, sementara aritmatika yang ditandatangani akan baik-baik saja.
Ben Voigt
@ BenVoigt. Mengapa aritmatika tanpa tanda itu menyakitkan? Bukankah modulo 3 ^ n adders di komputer itu tidak mungkin?
phuclv
2
@ LưuVĩnhPhúc: Itulah intinya, dengan operasi perangkat keras dilakukan modulo 3 ** n, memberikan C ++ tipe yang tidak ditandatangani yang operasinya didefinisikan modulo 2 ** n akan sulit.
Ben Voigt
2
Saya tahu satu VAX 11/780 masih digunakan sebagai host untuk kompiler silang yang menargetkan sistem tertanam khusus dengan arsitektur berpemilik. Untuk mempertahankan VAX tertentu, penjaga telah mendekati museum untuk suku cadang.
Peter
2
@Keith - secara teknis, satu-satunya kendala adalah melalui proses untuk memberikan bukti yang akan memenuhi persyaratan peraturan, karena sistem yang disematkan target sangat kritis. Ada banyak hambatan non-teknis (politik organisasi, dll), namun, hingga saat ini telah diatasi. Saat ini lebih mudah untuk memasang case untuk menyerang museum daripada memperbarui host.
Peter
16

CHAR_BITS

Menurut kode sumber gcc :

CHAR_BITadalah 16bit untuk 1750a , dsp16xx arsitektur.
CHAR_BITadalah 24bit untuk arsitektur dsp56k .
CHAR_BITadalah 32bit untuk arsitektur c4x .

Anda dapat dengan mudah menemukan lebih banyak dengan melakukan:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

atau

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

jika CHAR_TYPE_SIZEdidefinisikan dengan tepat.

Kepatuhan IEEE 754

Jika arsitektur target tidak mendukung instruksi floating point, gcc dapat menghasilkan penyihir fallback perangkat lunak tidak sesuai standar secara default. Lebih dari itu, opsi khusus (seperti -funsafe-math-optimizationspenyihir juga menonaktifkan tanda melestarikan untuk nol) dapat digunakan.

ivaigult
sumber
3
ditingkatkan untuk hanya mengarahkan OP untuk melihat sumber dari kompiler populer; ini adalah definisi RFTM dalam hal ini, jadi ini harus menjadi tempat pertama yang dilihat orang.
underscore_d
9

Representasi biner IEEE 754 tidak umum pada GPU sampai saat ini, lihat GPU Floating-Point Paranoia .

EDIT: pertanyaan telah diajukan dalam komentar apakah GPU floating point relevan dengan pemrograman komputer biasa, tidak terkait dengan grafik. Yeah! Sebagian besar hal kinerja tinggi yang dihitung secara industri saat ini dilakukan pada GPU; daftar termasuk AI, penambangan data, jaringan saraf, simulasi fisik, ramalan cuaca, dan banyak lagi. Salah satu tautan dalam komentar menunjukkan alasannya: urutan keunggulan floating point GPU.

Hal lain yang ingin saya tambahkan, yang lebih relevan dengan pertanyaan OP: apa yang dilakukan orang 10-15 tahun lalu ketika GPU floating point bukan IEEE dan ketika tidak ada API seperti OpenCL atau CUDA hari ini untuk memprogram GPU? Percaya atau tidak, pelopor komputasi GPU awal berhasil memprogram GPU tanpa API untuk melakukannya ! Saya bertemu salah satu dari mereka di perusahaan saya. Inilah yang dia lakukan: dia menyandikan data yang dia perlukan untuk menghitung sebagai gambar dengan piksel yang mewakili nilai yang sedang dikerjakannya, kemudian menggunakan OpenGL untuk melakukan operasi yang diperlukannya (seperti "gaussian blur" untuk mewakili konvolusi dengan distribusi normal. , dll), dan mendekodekan gambar yang dihasilkan kembali ke dalam array hasil. Dan ini masih lebih cepat daripada menggunakan CPU!

Hal-hal seperti itulah yang mendorong NVidia untuk akhirnya membuat data biner internal mereka kompatibel dengan IEEE dan untuk memperkenalkan API yang berorientasi pada perhitungan daripada manipulasi gambar.

Michael
sumber
Bagaimana GPU relevan? (a) Halaman ini tampaknya sangat usang. (B) Sampai hari ini Anda tidak dapat memprogram GPU dalam C: karena C mendukung hal-hal seperti fungsi rekursif yang GPU, sejauh pengetahuan saya, tidak. Jadi Anda bahkan tidak dapat menulis kompiler jika Anda mau.
Yakov Galka
1
@ybungalobill, offloading pekerjaan berulang ke GPU saat ini adalah metode yang disukai untuk perhitungan skala besar . Bahkan, saya sedang mengembangkan satu di C ++. Untungnya, kami hanya bekerja dengan NVidia CUDA GPU yang memiliki representasi biner float yang kompatibel dengan IEEE 754.
Michael
Saya tidak mengatakan GPU tidak digunakan untuk perhitungan GP. Saya mengatakan bahwa Anda tidak benar-benar memprogram kernel di C, meskipun sintaksisnya mirip. Bisakah Anda mengeksekusi int f(int n) { return n <= 1 ? 1 : n * f(n-1); }di CUDA? Jika tidak, maka GPU tidak relevan untuk pertanyaan ini (yang menanyakan tentang komite C dan C ++).
Yakov Galka
6
@ybungalobill: beberapa jawaban untuk itu. Pertama, CUDA mendukung C, C ++, dan Fortran . Lihat tautan yang sama untuk keunggulan kinerja yang luar biasa dari GPU 2048-benang dibanding CPU 8-benang Anda. Kedua, benar, hanya himpunan bagian (meskipun yang besar) dari bahasa-bahasa tersebut yang didukung, termasuk kurangnya dukungan yang sesuai untuk rekursi model pemrograman CUDA (disebut "paralelisme dinamis") hingga CUDA 5.0. Ketiga, rekursi biasanya dapat diganti dengan loop, yang diperlukan untuk kinerja multithreaded.
Michael