Thank you bearophile and Simen for your replies! Very helpful! I'll keep looking into it...
BR /HF bearophile Wrote: > Simen kjaeraas: > > > Essentially, mark the switch as final, and cover every option. > > Likely, the optimizer does that for you if you cover every option but > > don't mark the switch as final. > > This is true in theory, and I remember Walter liking this optimization. But > in practice I don't know if DMD performs this optimization already, so you > need to take a look at the produced asm to be sure. > > -------------------------------- > > This is a little test, D2 code: > > enum E { e1, e2, e3 } > > int foo1(E e) { > switch (e) { > case E.e1: return 1; > case E.e2: return 2; > case E.e3: return 3; > default: assert(0); > } > } > > int foo2(E e) { > switch (e) { > case E.e1: return 1; > case E.e2: return 2; > default: return 3; > } > } > > int foo3(E e) { > final switch (e) { > case E.e1: return 1; > case E.e2: return 2; > case E.e3: return 3; > } > } > void main() {} > > > _D5test4foo1FE5test31EZi > push EAX > test EAX,EAX > je L11 > cmp EAX,1 > je L18 > cmp EAX,2 > je L1F > jmp short L26 > L11: pop ECX > mov EAX,1 > ret > L18: pop ECX > mov EAX,2 > ret > L1F: pop ECX > mov EAX,3 > ret > L26: hlt > > _D5test4foo2FE5test31EZi > push EAX > test EAX,EAX > je LC > cmp EAX,1 > je L13 > jmp short L1A > LC: pop ECX > mov EAX,1 > ret > L13: pop ECX > mov EAX,2 > ret > L1A: pop ECX > mov EAX,3 > ret > > _D5test4foo3FE5test31EZi > push EAX > test EAX,EAX > je L11 > cmp EAX,1 > je L18 > cmp EAX,2 > je L1F > jmp short L26 > L11: pop ECX > mov EAX,1 > ret > L18: pop ECX > mov EAX,2 > ret > L1F: pop ECX > mov EAX,3 > ret > L26: pop EAX > ret > > -------------------------------- > > Some C code compiled with GCC 4.5.1: > > typedef enum { e1, e2, e3 } E; > > int foo2(E e) { > switch (e) { > case e1: return 1; > case e2: return 2; > default: return 3; > } > } > > int foo3(E e) { > switch (e) { > case e1: return 1; > case e2: return 2; > case e3: return 3; > } > } > > int foo4(E e) { > static void *array[] = { &&E1, &&E2, &&E3 }; > > goto *array[e]; > > E1: return 1; > E2: return 2; > E3: return 3; > } > > int main() { > return 0; > } > > > _foo2: > movl 4(%esp), %edx > movl $3, %eax > cmpl $1, %edx > jbe L5 > rep > ret > .p2align 4,,7 > L5: > movl _CSWTCH.1(,%edx,4), %eax > ret > .p2align 4,,15 > > _foo3: > movl 4(%esp), %edx > cmpl $1, %edx > je L11 > movl $1, %eax > jb L6 > cmpl $2, %edx > je L13 > .p2align 4,,3 > rep > ret > .p2align 4,,7 > L11: > movl $2, %eax > L6: > .p2align 4,,3 > rep > ret > .p2align 4,,7 > L13: > movb $3, %al > ret > > _foo4: > movl 4(%esp), %eax > jmp *_array.1639(,%eax,4) > .p2align 4,,7 > L15: > movl $1, %eax > ret > .p2align 4,,7 > L17: > movl $2, %eax > ret > .p2align 4,,7 > L18: > movl $3, %eax > ret > > -------------------------------- > > > My forays into the inline asm idea proved fruitless, but there may yet be > > ways. > > In D+DMD inline asm kills inlining, so you may use inline asm only if you > need to do lot of computations. > In LDC there are pragma(allow_inline) and asm expressions that some most of > this problem. > > Going back to the OP problem: in D there are no computed gotos, that are > useful if you want to write very fast interpreters and other things. But keep > in mind that DMD supports normal gotos from and in inlined asm (LLVM-LDC > doesn't supports this well), plus naked asm, this gives you some > possibilities. > An option on Linux is to write the interpreter core using GNU C (that has > computed gotos) and then link the core to the D code compiled with DMD/GDC. > > It's strange how something as basic, old and necessary as a switch, to create > a basic but fast interpreter, is so hard to compile well for compilers :-) > > Bye, > bearophile