emscripten-core/emscripten

Labels as Values / indirect branch / indirectbr support

Closed this issue · 26 comments

http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

ERROR    root: compiler frontend failed to generate LLVM bitcode, halting

Test code: https://gist.github.com/lostdj/3897335

Now, I wasn't really expecting to gain any performance improvements over this because of emscripten nature. But is it possible just to support LaV, so this and similar code can run?

Hmm, I think the first question is whether clang and llvm support it. If they do, we can investigate in emscripten.

They do!

It doesn't look like clang supports this, the error is in the frontend. Using clang in a native build, without emscripten, also fails on this. I tried both llvm 3.2 and 3.3.

It builds and runs just fine in 2.8. Maybe they broke something in >=3.2...

Apple clang (LLVM 3.3 based) compiles fine, with a lot of warnings:

compile log here https://gist.github.com/berkus/7541881

Hmm, I tested on 3.3 on linux and got errors.

On Tue, Nov 19, 2013 at 12:02 AM, Berkus Deckus notifications@github.comwrote:

Apple clang (LLVM 3.3 based) compiles fine, with a lot of warnings:

compile log here https://gist.github.com/berkus/7541881


Reply to this email directly or view it on GitHubhttps://github.com//issues/1742#issuecomment-28772046
.

Maybe it was due to -Werror?

What errors exactly?

$ ~/Dev/clang+llvm-3.3-Ubuntu-13.04-x86_64-linux-gnu/bin/clang++ a.cpp
a.cpp:26:19: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier]
        static const int const oparray[]=
                         ^~~~~~
a.cpp:28:21: error: arithmetic on pointers to void
                [OP_NOP]=&&op_nop - &&op_nop,     [OP_JMP]=&&op_jmp - &&op_nop, [OP_JMP_GE]=&&op_jmp_ge - &&op_nop,
                         ~~~~~~~~ ^ ~~~~~~~~
a.cpp:28:55: error: arithmetic on pointers to void
                [OP_NOP]=&&op_nop - &&op_nop,     [OP_JMP]=&&op_jmp - &&op_nop, [OP_JMP_GE]=&&op_jmp_ge - &&op_nop,
                                                           ~~~~~~~~ ^ ~~~~~~~~
a.cpp:28:91: error: arithmetic on pointers to void
                [OP_NOP]=&&op_nop - &&op_nop,     [OP_JMP]=&&op_jmp - &&op_nop, [OP_JMP_GE]=&&op_jmp_ge - &&op_nop,
                                                                                            ~~~~~~~~~~~ ^ ~~~~~~~~
a.cpp:29:21: error: arithmetic on pointers to void
                [OP_MOV]=&&op_mov - &&op_nop,     [OP_ADD]=&&op_add - &&op_nop, [OP_MUL]=&&op_mul - &&op_nop,
                         ~~~~~~~~ ^ ~~~~~~~~
a.cpp:29:55: error: arithmetic on pointers to void
                [OP_MOV]=&&op_mov - &&op_nop,     [OP_ADD]=&&op_add - &&op_nop, [OP_MUL]=&&op_mul - &&op_nop,
                                                           ~~~~~~~~ ^ ~~~~~~~~
a.cpp:29:85: error: arithmetic on pointers to void
                [OP_MOV]=&&op_mov - &&op_nop,     [OP_ADD]=&&op_add - &&op_nop, [OP_MUL]=&&op_mul - &&op_nop,
                                                                                         ~~~~~~~~ ^ ~~~~~~~~
a.cpp:30:25: error: arithmetic on pointers to void
                [OP_PRINT]=&&op_print - &&op_nop, [OP_RET]=&&op_ret - &&op_nop
                           ~~~~~~~~~~ ^ ~~~~~~~~
a.cpp:30:55: error: arithmetic on pointers to void
                [OP_PRINT]=&&op_print - &&op_nop, [OP_RET]=&&op_ret - &&op_nop
                                                           ~~~~~~~~ ^ ~~~~~~~~
a.cpp:59:31: error: arithmetic on a pointer to void
                        case OP_NOP:    op_nop:    NEXT()
                                                   ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:60:69: error: arithmetic on a pointer to void
                        case OP_JMP:    op_jmp:    ip = prog + IMMV_1(); goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *ip ) >> 48)] ); //ip = prog + IMMV_1(); break;
                                                                                ~~~~~~~~ ^
a.cpp:61:111: error: arithmetic on a pointer to void
                        case OP_JMP_GE: op_jmp_ge: if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *ip ) >> 48)] );} else {NEXT()} //if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); break;} else {NEXT()}
                                                                                                                          ~~~~~~~~ ^
a.cpp:61:178: error: arithmetic on a pointer to void
                        case OP_JMP_GE: op_jmp_ge: if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *ip ) >> 48)] );} else {NEXT()} //if((R_OR_IMMV_1() - R_OR_IMMV_2()) >= 0) {ip = prog + IMMV_3(); break;} else {NEXT()}
                                                                                                                                                                                                      ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:62:54: error: arithmetic on a pointer to void
                        case OP_MOV:    op_mov:    R_1() = R_OR_IMMV_2(); NEXT()
                                                                          ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:63:70: error: arithmetic on a pointer to void
                        case OP_ADD:    op_add:    R_3() = R_OR_IMMV_1() + R_OR_IMMV_2(); NEXT()
                                                                                          ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:64:70: error: arithmetic on a pointer to void
                        case OP_MUL:    op_mul:    R_3() = R_OR_IMMV_1() * R_OR_IMMV_2(); NEXT()
                                                                                          ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:65:78: error: arithmetic on a pointer to void
                        case OP_PRINT:  op_print:  printf("%d\n", R_OR_IMMV_1()); fflush(stdout); NEXT()
                                                                                                  ^~~~~~
a.cpp:35:17: note: expanded from macro 'NEXT'
        #define NEXT() GOTO();
                       ^~~~~~
a.cpp:34:33: note: expanded from macro 'GOTO'
        #define GOTO() goto *(&&op_nop + oparray[(uint16_t)((0x00FF000000000000 & *(++ip) ) >> 48)] );
                              ~~~~~~~~ ^
a.cpp:75:21: error: assigning to 'inst *' (aka 'unsigned long *') from incompatible type 'void *'
        inst *program = ip = memset(malloc(sizeof(inst) * 1024), 0, sizeof(inst) * 1024);
                           ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:176:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~
a.cpp:166:18: note: expanded from macro 'READ_AND_SET_IMMV'
                                        scanf("%d", &arg##_ARG_NUM##_i); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:178:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:178:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:178:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:179:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:179:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:179:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:180:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_IMMV(3);
                                ^~~~~~~~~~~~~~~~~~~~~
a.cpp:166:18: note: expanded from macro 'READ_AND_SET_IMMV'
                                        scanf("%d", &arg##_ARG_NUM##_i); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:182:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R(1);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:159:18: note: expanded from macro 'READ_AND_SET_R'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:182:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R(1);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:160:42: note: expanded from macro 'READ_AND_SET_R'
                                        sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                       ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:183:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:183:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:183:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:185:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:185:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:185:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:186:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:186:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:186:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:187:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R(3);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:159:18: note: expanded from macro 'READ_AND_SET_R'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:187:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R(3);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:160:42: note: expanded from macro 'READ_AND_SET_R'
                                        sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                       ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:189:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:189:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:189:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:190:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:190:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:190:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(2);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:191:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R(3);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:159:18: note: expanded from macro 'READ_AND_SET_R'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:191:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R(3);
                                ^~~~~~~~~~~~~~~~~~
a.cpp:160:42: note: expanded from macro 'READ_AND_SET_R'
                                        sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                       ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:193:5: warning: format specifies type 'char *' but the argument has type 'char (*)[32]' [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:144:18: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                        scanf("%s", &arg##_ARG_NUM##_s); \
                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:193:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:147:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[2], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
a.cpp:193:5: warning: format specifies type 'int *' but the argument has type 'inst *' (aka 'unsigned long *') [-Wformat]
                                READ_AND_SET_R_OR_IMMV(1);
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~
a.cpp:152:43: note: expanded from macro 'READ_AND_SET_R_OR_IMMV'
                                                sscanf(&arg##_ARG_NUM##_s[0], "%d", &arg##_ARG_NUM##_i); \
                                                                               ~~   ^
a.cpp:100:5: note: expanded from macro 'OP_SWITCH'
                                _CODE \
                                ^
33 warnings and 17 errors generated.

Ah, try to compile with clang, no ++. And change the file extension to .c

It's not a valid C++, but may pass as average quality C ;)

You're fat and a saboteur.

I wrote this code as a test to compare the performance between register- and stack-based bytecode interpreters, as seen in http://byteworm.com/2010/11/21/the-fastest-vm-bytecode-interpreter/
And since it was already posted in my gists, I used it as a simple test code for this issue.

Whatever flies your boat :)

Looking in the generated code, this uses llvm indirectbr. We support that partially now, but that testcase breaks. My current goal is to work on indirectbr in the new compiler rewrite, which should be easier and also generate better results. Hopefully in a week or two that should be done, unless someone else wants to do it before.

In the end setjmp did not benefit from this, so I did it separately. Not sure when I will have time for this specifically, but if anyone wants some tips on how to get started on it, I can do that.

@kripken Ah-ha. OK, I'll link to my example code here for posterity's sake:

https://github.com/ephsec/svforth/blob/master/experiments/forth-kernel.ll

I may be willing to take a stab at this, if you can give me some pointers on where, what, and how. I've done some pretty loony things in JavaScript as well.

@lostdj Your blog article was really funny, especially considering that I wrote a Threaded Interpreter in LLVM IR -- and wrote it using indirectbr and block address to avoid the C function call overhead. I'll need to try implementing that in my Forth.

indirectbr support has landed on fastcomp-incoming + emscripten-incoming. This passes all the test suite uses of indirectbr. However, the test cases here do not pass. In both cases they fail due to limitations in the pnacl legalization passes that fastcomp relies on. Specifically,

  1. In the original testcase here, things like &&op_nop - &&op_nop where the addresses of branches are subtracted, ends up causing subtractions in global variables, which trips FlattenGlobals: ConstantExpr opcode not handled: sub. Is it necessary to subtract that way?
  2. In the forth testcase, the ir is not generated by clang I assume, and lacks a datalayout and triple info and so forth. Adding in the defaults emscripten expects still does not fix it, because there are structs that trip call { i64, i1 } @llvm_ump(i64 %A.cell.ALU_UM_ADD, i64 %B.cell.ALU_UM_ADD) : Unrecognized struct value - structures like that must be legalized, and the passes legalize the ones clang emits, but this is not one of those. However, I think the underlying issue is that the bitcode was generated for a 64-bit machine, and the passes and emcc expect 32-bit.

@kripken Interesting!

Some context: This is actually handwritten LLVM IR, this isn't generated by any compiler. I'm a masochist. and I wanted to grok LLVM IR.

If you take a look at lines 1-11, you'll see that these are actually type macros. You can change the entire thing to 32 bit.

%pntr = type i64*
%cell = type i64
%cell.ptr = type i64*
%ret = type i64
%ret.ptr = type i64*
%exec = type i64
%exec.ptr = type i64*
%int = type i64
%addr = type i64
%addr.ptr = type i64*
%fnaddr = type i8*

Lines 133-140 would need to be changed to the appropriate 32-bit call, as mentioned in the comments.

However, I need to clean up the stray naked i64 definitions that I'm seeing in the body of the code, and I can do that shortly.

Oh ok, cool. Once you have a proper 32-bit version let's test that.

@kripken I have a tree now with some headway into a 32-bit version. It compiles now -- when I have more time, I will need to figure out why the 32-bit version crashes. But, meanwhile, here it is:

https://github.com/ephsec/llvm-forth

If you don't want to run Make, you can just cat the 32-bit preamble file forth-kernel-preamble-32.ll with forth-kernel.ll to create a 32-bit version that you should be able to throw through emcc.

Sorry for the delay.

In the original testcase here, things like &&op_nop - &&op_nop where the addresses of branches are subtracted, ends up causing subtractions in global variables, which trips FlattenGlobals: ConstantExpr opcode not handled: sub. Is it necessary to subtract that way?

It isn't. For some reason this way it was faster ~two years ago, and now it's actually a bit slower than a simple label addr table.

So everything works now, but unfortunately it's 1.5-2x slower compared to a simple switch. Tested with bundled nodejs (the slowest), FF and Chrome.

This is not fully optimized yet, so not surprising it is slower than a switch, I guess. Although I would have expected it to be about the same as a switch.

If someone is interested to work on this, basically we need to replace the 'label' variable with the label that the indirect branch is targeting.

Hm, just to clarify, are you saying that it may be possible to make it faster than a switch?

Well, a switch can be compiled by a JS VM into a jump table, which is as
fast as it gets. But I think right now we have two levels of indirection,
and we could remove one, leaving a single easy to optimize switch. Should
be significantly faster than now.

On Wed, Jun 4, 2014 at 9:04 PM, Bugs Everywhere notifications@github.com
wrote:

Hm, just to clarify, are you saying that it may be possible to make it
faster than switch?


Reply to this email directly or view it on GitHub
#1742 (comment).

a switch can be compiled by a JS VM into a jump table, which is as fast as it gets

Yes, but I've seen even native compilers fail to do so on just a slight hint of a huge/complicated switch (they failed to make it "just a jump table", suddenly they started introducing complicated logic calculating jump addresses). And my guess is JS VM's can deliberately choose not to spend any more time figuring out how to make it faster and emit native code 1:1 to asm.js (I may be wrong, of course).

True. In asm.js though, at least in Firefox you practically have a
guarantee of a jump table (unless it is a pathologically large table or
such).

On Wed, Jun 4, 2014 at 10:06 PM, Bugs Everywhere notifications@github.com
wrote:

a switch can be compiled by a JS VM into a jump table, which is as fast as
it gets

Yes, but I've seen even native compilers fail to do so on just a slight
hint of a huge/complicated switch (they failed to make it "just a jump
table", suddenly they started introducing complicated logic calculating
jump addresses). And my guess is JS VM's can deliberately choose not to
spend any more time figuring out how to make it faster and emit native code
1:1 to asm.js (I may be wrong, of course).


Reply to this email directly or view it on GitHub
#1742 (comment).

stale commented

This issue has been automatically marked as stale because there has been no activity in the past 2 years. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant.