Pertimbangkan kode sederhana ini:
void g();
void foo()
{
volatile bool x = false;
if (x)
g();
}
Anda dapat melihat bahwa tidak gcc
juga clang
mengoptimalkan potensi panggilan ke g
. Ini benar dalam pemahaman saya: Mesin abstrak mengasumsikan bahwa volatile
variabel dapat berubah setiap saat (karena misalnya perangkat keras-dipetakan), jadi melipat- false
inisialisasi inisialisasi menjadi if
cek akan salah.
Tetapi MSVC menghilangkan panggilan untuk g
sepenuhnya (menjaga membaca dan menulis volatile
meskipun!). Apakah perilaku sesuai standar ini?
Latar belakang: Saya kadang-kadang menggunakan konstruksi semacam ini untuk dapat mengaktifkan / menonaktifkan output debugging on-the-fly: Kompiler harus selalu membaca nilai dari memori, jadi mengubah variabel / memori selama debugging harus memodifikasi aliran kontrol sesuai . Output MSVC membaca ulang nilainya tetapi mengabaikannya (mungkin karena lipat dan / atau penghapusan kode mati), yang tentu saja mengalahkan niat saya di sini.
Suntingan:
Penghapusan membaca dan menulis
volatile
dibahas di sini: Apakah diizinkan untuk kompiler untuk mengoptimalkan variabel volatile lokal? (terima kasih Nathan!). Saya pikir standarnya sangat jelas bahwa membaca dan menulis itu harus terjadi. Tetapi diskusi itu tidak mencakup apakah legal bagi kompiler untuk mengambil hasil dari bacaan-bacaan itu dengan benar dan mengoptimalkan berdasarkan itu. Saya kira ini adalah standar yang tidak ditentukan , tetapi saya akan senang jika seseorang membuktikan saya salah.Saya tentu saja dapat membuat
x
variabel non-lokal untuk mengesampingkan masalah ini. Pertanyaan ini lebih karena penasaran.
sumber
Jawaban:
Saya pikir [intro.execution] (nomor paragraf bervariasi) dapat digunakan untuk menjelaskan perilaku MSVC:
Standar tidak mengizinkan penghapusan membaca melalui glvalue yang mudah menguap, tetapi paragraf di atas dapat ditafsirkan sebagai memungkinkan untuk memprediksi nilai
false
.BTW, Standar C (N1570 6.2.4 / 2) mengatakan itu
Tidak jelas apakah mungkin ada toko non-eksplisit ke dalam objek dengan durasi penyimpanan otomatis dalam memori C / model objek.
sumber
volatile
membeli Anda (selain membaca / menulis berlebihan) jika diabaikan untuk tujuan optimasi?TL; DR Kompiler dapat melakukan apa pun yang diinginkan pada setiap akses volatil. Tetapi dokumentasi tersebut harus memberi tahu Anda .-- "Semantik dari akses melalui nilai yang mudah menguap ditentukan oleh implementasi."
Standar ini mendefinisikan untuk program yang diizinkan urutan "akses mudah menguap" & "perilaku yang dapat diamati" lainnya (dicapai melalui "efek samping") bahwa suatu implementasi harus menghormati per "aturan 'seolah-olah'.
Tetapi standar mengatakan (penekanan tebal saya):
Demikian pula untuk perangkat interaktif (penekanan tebal saya):
(Pokoknya kode spesifik apa yang dihasilkan untuk suatu program tidak ditentukan oleh standar.)
Jadi, meskipun standar mengatakan bahwa akses volatil tidak dapat dielakkan dari urutan abstrak efek samping mesin abstrak & perilaku yang dapat diamati yang didefinisikan oleh beberapa kode, Anda tidak dapat mengharapkan sesuatu tercermin dalam kode objek atau dunia nyata perilaku kecuali dokumentasi kompiler Anda memberi tahu Anda apa yang merupakan akses volatil . Ditto untuk perangkat interaktif.
Jika Anda tertarik pada volatile vis a vis urutan abstrak dari efek samping mesin abstrak dan / atau perilaku yang dapat diamati yang didefinisikan oleh beberapa kode (mungkin) maka katakanlah demikian . Tetapi jika Anda tertarik pada kode objek apa yang dihasilkan, maka Anda harus menafsirkannya dalam konteks kompiler & kompilasi Anda .
Kronis orang secara keliru percaya bahwa untuk akses yang mudah menguap evaluasi mesin / dibaca abstrak menyebabkan membaca diimplementasikan & tugas mesin abstrak / write menyebabkan write dilaksanakan. Tidak ada dasar untuk keyakinan ini tidak ada dokumentasi implementasi mengatakan demikian. Ketika / jika implementasi mengatakan bahwa itu benar - benar melakukan sesuatu pada "akses volatile", orang dibenarkan dalam mengharapkan sesuatu - mungkin, generasi kode objek tertentu.
sumber
Saya percaya adalah sah untuk melewatkan cek.
Paragraf yang suka dikutip semua orang
tidak menyiratkan bahwa suatu implementasi harus mengasumsikan toko-toko seperti itu dimungkinkan kapan saja, atau untuk variabel volatil apa pun. Implementasi tahu toko mana yang mungkin. Misalnya, sepenuhnya masuk akal untuk mengasumsikan bahwa penulisan implisit tersebut hanya terjadi untuk variabel volatil yang dipetakan ke register perangkat, dan pemetaan seperti itu hanya mungkin untuk variabel dengan tautan eksternal. Atau suatu implementasi dapat berasumsi bahwa penulisan semacam itu hanya terjadi pada lokasi memori yang sejajar kata-kata.
Karena itu, saya pikir perilaku MSVC adalah bug. Tidak ada alasan dunia nyata untuk mengoptimalkan panggilan. Optimalisasi seperti itu mungkin sesuai, tetapi sia-sia jahat.
sumber
volatile
seharusnya menjadi petunjuk untuk pelaksanaan yang nilai dapat mengubah dengan cara yang tidak diketahui pelaksanaan.volatile
untuk pada platform itu dan di luar spesifikasi itu, itu selalu akan menjadi omong kosong.volatile
dilakukan dan tetap pada itu. Maksud saya adalah bahwa kode itu sendiri (sesuai dengan C ++ standar / mesin abstrak) tidak memungkinkan Anda untuk menentukan apakahg
dapat dipanggil.