Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Labels as Values / indirect branch / indirectbr support #1742

Open
lostdj opened this Issue Oct 27, 2013 · 25 comments

Comments

Projects
None yet
5 participants
@lostdj
Copy link

lostdj commented Oct 27, 2013

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?

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Oct 29, 2013

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

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Oct 29, 2013

They do!

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Nov 19, 2013

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.

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Nov 19, 2013

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

@berkus

This comment has been minimized.

Copy link

berkus commented Nov 19, 2013

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

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

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Nov 19, 2013

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
.

@berkus

This comment has been minimized.

Copy link

berkus commented Nov 20, 2013

Maybe it was due to -Werror?

What errors exactly?

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Nov 20, 2013

$ ~/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.
@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Nov 20, 2013

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

@berkus

This comment has been minimized.

Copy link

berkus commented Nov 21, 2013

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

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Nov 21, 2013

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.

@berkus

This comment has been minimized.

Copy link

berkus commented Nov 21, 2013

Whatever flies your boat :)

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Jan 14, 2014

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.

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Jan 21, 2014

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.

@wbrown

This comment has been minimized.

Copy link

wbrown commented Jan 26, 2014

@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.

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Feb 21, 2014

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.
@wbrown

This comment has been minimized.

Copy link

wbrown commented Feb 21, 2014

@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.

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Feb 21, 2014

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

@wbrown

This comment has been minimized.

Copy link

wbrown commented Mar 11, 2014

@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.

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Jun 3, 2014

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.

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Jun 4, 2014

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.

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Jun 5, 2014

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

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Jun 5, 2014

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).

@lostdj

This comment has been minimized.

Copy link
Author

lostdj commented Jun 5, 2014

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).

@kripken

This comment has been minimized.

Copy link
Member

kripken commented Jun 5, 2014

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).

@juj juj added the fastcomp label Jul 25, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.