I have a C++ function that defines multiple labels and attempts to compute a target address based on an input value. The function then uses a goto
statement to jump to the computed address. However, when I compile this code with GCC or Clang, it only uses the first two labels. (compiler explorer)
Why do GCC and Clang fail to compile this code correctly, and how can I fix it? Is this behavior intended according to the C++ standard, or is it a compiler bug? Should I report it?
#include <cstdint>
#include <cstddef>
#include <cstring>
uint8_t SWARfloor64OverNGoto(const uint64_t n)
{
// Define the labels
void *label0_address = &&label0;
void *label1_address = &&label1;
// Calculate the offset at compile time
const uint64_t offset = reinterpret_cast<uintptr_t>(label1_address) - reinterpret_cast<uintptr_t>(label0_address);
// Compute the target address
void *target = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(label0_address) + n * offset);
// Jump to the target address
goto *reinterpret_cast<void**>(target);
label0:
return 0;
label1:
return 64;
label2:
return 32;
label3:
return 21;
label4:
return 16;
label5:
return 12;
label6:
return 10;
label7:
return 9;
label8:
return 8;
label9:
return 7;
label10:
return 6;
label11:
return 5;
label12:
return 5;
label13:
return 4;
label14:
return 4;
label15:
return 4;
label16:
return 4;
label17:
return 3;
label18:
return 3;
label19:
return 3;
label20:
return 3;
label21:
return 3;
label22:
return 2;
label23:
return 2;
label24:
return 2;
label25:
return 2;
label26:
return 2;
label27:
return 2;
label28:
return 2;
label29:
return 2;
label30:
return 2;
label31:
return 2;
label32:
return 2;
label33:
return 1;
label34:
return 1;
label35:
return 1;
label36:
return 1;
label37:
return 1;
label38:
return 1;
label39:
return 1;
label40:
return 1;
label41:
return 1;
label42:
return 1;
label43:
return 1;
label44:
return 1;
label45:
return 1;
label46:
return 1;
label47:
return 1;
label48:
return 1;
label49:
return 1;
label50:
return 1;
label51:
return 1;
label52:
return 1;
label53:
return 1;
label54:
return 1;
label55:
return 1;
label56:
return 1;
label57:
return 1;
label58:
return 1;
label59:
return 1;
label60:
return 1;
label61:
return 1;
label62:
return 1;
label63:
return 1;
}
The compiled assembly code only uses the first two labels, which is not the intended behavior.
SWARfloor64OverNGoto(unsigned long):
mov eax, OFFSET FLAT:.L3
sub rax, OFFSET FLAT:.L2
imul rax, rdi
add rax, OFFSET FLAT:.L2
jmp rax
.L2:
xor eax, eax
ret
.L3:
mov eax, 64
ret
1