Kode Mesin x86-64, 8 byte
Terinspirasi oleh solusi Bruce Forte , tetapi sedikit di bawah par. :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
InfiniteLoop:
F3 73 FD rep jnc InfiniteLoop ; test CF; infinite loop back here if input was even
C3 ret ; return with original input in EAX if it was odd
Parameter integer tunggal diambil dalam EDI
register, mengikuti konvensi pemanggilan Sistem V AMD64.
Salinan nilai ini awalnya dibuat, dan dimasukkan ke EAX
dalamnya sehingga dapat dikembalikan jika sesuai. ( LEA
digunakan alih-alih yang normal MOV
karena kita memerlukan instruksi dengan byte aneh.)
Kemudian, nilai dalam EDI
digeser ke kanan dengan 1, yang menempatkan bit yang dialihkan ke bendera pembawa (CF). Bit ini akan menjadi 0 jika angkanya genap, atau 1 jika ganjil.
Kami kemudian menguji CF menggunakan JNC
instruksi, yang akan bercabang hanya jika CF adalah 0 (yaitu, angkanya genap). Ini berarti bahwa kita akan masuk ke loop tak terbatas untuk nilai genap. Untuk nilai ganjil, kami melewati dan nilai asli (dalam EAX
) dikembalikan.
Ada sedikit trik dengan JNC
instruksinya, tetapi itu memiliki REP
awalan! Biasanya, REP
awalan hanya digunakan dengan instruksi string, tetapi karena manual Intel dan AMD sama-sama setuju bahwa REP
awalan yang tidak relevan / berlebihan / berlebihan diabaikan, kami melemparkan satu pada instruksi cabang di sini untuk membuatnya panjang 3 byte. Dengan begitu, offset relatif yang disandikan dalam instruksi lompat juga aneh. (Dan, tentu saja, REP
itu sendiri merupakan awalan byte aneh.)
Syukurlah RET
dikodekan menggunakan byte aneh!
Cobalah online!
Jika Anda tidak berpikir mengembalikan nilai jika itu aneh atau masuk ke loop tak terbatas jika itu genap (sehingga Anda tidak pernah kembali) memenuhi persyaratan "output" dari tantangan, atau Anda hanya menginginkan sesuatu yang lebih menarik, inilah fungsi yang menampilkan nilai ke port serial (tetapi hanya jika itu aneh, tentu saja).
x86-64 Kode Mesin (output ke port serial), 17 byte
8D 07 lea eax, [rdi] ; put copy of input parameter (EDI) in EAX
B1 F7 mov cl, 0xf7 ; put 0xF7 into low-order bits of CX
B5 03 mov ch, 0x03 ; put 0x03 into high-order bits of CX
FE C1 inc cl ; increment low-order bits of CX to 0xF8 (so all together it's now 0x3F8)
0F B7 D1 movzx edx, cx ; move CX to DX ("MOV DX, CX" would have a 16-bit prefix of 0x66)
D1 EF shr edi, 1 ; shift LSB of input parameter into CF
73 01 jnc IsEven ; test CF: branch if 0 (even), fall through if 1 (odd)
EF out dx, eax ; output EAX (original input) to I/O port 0x3F8 (in DX)
IsEven:
C3 ret ; return
Apa yang membuat ini sedikit lebih menarik adalah bahwa kode melakukan lebih banyak , yang berarti lebih sulit untuk melakukan semuanya menggunakan instruksi yang disandikan menggunakan hanya byte aneh. Tentu saja, ini juga berarti gagal pada kode golf, jadi ini semacam pertukaran - apakah Anda ingin menarik dan menantang, atau Anda ingin pendek?
Bagaimanapun, ini menggunakan OUT
instruksi x86 untuk menulis ke port I / O 0x3F8, yang merupakan port serial standar COM1 pada PC. Bagian yang menyenangkan, tentu saja, adalah bahwa semua port I / O standar (serial dan paralel) memiliki alamat genap, sehingga mereka tidak dapat dengan mudah dikodekan sebagai OUT
instruksi langsung atau dipindahkan langsung ke register. Anda harus menginisialisasi dengan satu kurang dari nilai aktual, dan kemudian menambah nilai dalam register. Anda juga dibatasi untuk menggunakan register tertentu untuk manipulasi karena Anda memerlukan register yang dikodekan menggunakan byte aneh dalam instruksi ketika digunakan sebagai operan.
Juga, saya harus menginisialisasi DX
register (melalui CX
register) di bagian atas loop, meskipun ini hanya diperlukan jika nilainya ganjil, untuk memastikan bahwa JNC
instruksi akan memiliki offset ganjil. Namun, karena apa yang kita lewati adalah OUT
instruksi, semua kode ini lakukan adalah siklus limbah dan register awal clobber; itu sebenarnya tidak menghasilkan apa-apa, jadi itu tidak melanggar aturan.
Akhirnya, fungsi ini akan kembali (setelah selesai atau tidak melakukan output ke port serial) dengan nilai input tersisa EAX
. Tapi itu tidak benar-benar melanggar aturan apa pun; semua fungsi dalam bahasa assembly akan kembali dengan nilai dalam EAX
— pertanyaannya adalah apakah itu nilai yang signifikan atau nilai sampah . Itu ditentukan oleh dokumentasi fungsi (pada dasarnya, apakah mengembalikan nilai atau mengembalikan void
), dan dalam hal ini, saya mendokumentasikannya sebagai tidak mengembalikan nilai. :-)
Tidak ada tautan TIO untuk yang ini, karena tidak menerapkan output ke port serial. Anda akan membutuhkan besi asli, atau imajinasi.