digitalmars.D - Feature request: First class labels
- Paul Findlay <r.lph50+d gmail.com> May 05 2007
- Hasan Aljudy <hasan.aljudy gmail.com> May 05 2007
- Paul Findlay <r.lph50+d gmail.com> May 06 2007
- Walter Bright <newshound1 digitalmars.com> May 06 2007
- Paul Findlay <r.lph50+d gmail.com> May 06 2007
- =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> May 06 2007
- BCS <ao pathlink.com> May 06 2007
- =?ISO-8859-1?Q?Lu=EDs_Marques?= <luismarques+spam gmail.com> May 06 2007
- Daniel Keep <daniel.keep.lists gmail.com> May 06 2007
- janderson <askme me.com> May 06 2007
- Daniel Keep <daniel.keep.lists gmail.com> May 06 2007
- janderson <askme me.com> May 06 2007
First-class labels (or "labels as values" [1]) would make D a much better platform for implementing interpreters. Is there any chance of having something like this? It would mean virtual machine execution could be implemented using direct threading [2] and make possible all sorts of tricks including using D compiler generated executable code for JIT [3]. Direct threading often has less branch mis-prediction than using switches to dispatch VM intructions [2]. I don't know the cost of implementing this for DMD, but it needn't introduce a new basic type or keywords to the language.. (perhaps labels could be typdef'd in std.intrinsics) Hope this makes sense (both what I've written and as a feature :) ) - Paul Findlay 1: http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html 2; http://www.complang.tuwien.ac.at/forth/threaded-code.html 3: M. Anton Ertl and David Gregg, Retargeting JIT compilers using C-compiler generated executable code, in Proceedings of the International Conference on Parallel Architectures and Compilation Techniques (PACT 04), pp. 7-14, Antibes Juan les Pins, Septmber 2004 (http://www.complang.tuwien.ac.at/papers/ertl%26gregg04pact.ps.gz)
May 05 2007
Paul Findlay wrote:First-class labels (or "labels as values" [1]) would make D a much better platform for implementing interpreters. Is there any chance of having something like this?
I'm not sure I understand .. Do you mean like, being able to "increment" labels and move them around?It would mean virtual machine execution could be implemented using direct threading [2] and make possible all sorts of tricks including using D compiler generated executable code for JIT [3]. Direct threading often has less branch mis-prediction than using switches to dispatch VM intructions [2]. I don't know the cost of implementing this for DMD, but it needn't introduce a new basic type or keywords to the language.. (perhaps labels could be typdef'd in std.intrinsics) Hope this makes sense (both what I've written and as a feature :) ) - Paul Findlay 1: http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html 2; http://www.complang.tuwien.ac.at/forth/threaded-code.html 3: M. Anton Ertl and David Gregg, Retargeting JIT compilers using C-compiler generated executable code, in Proceedings of the International Conference on Parallel Architectures and Compilation Techniques (PACT 04), pp. 7-14, Antibes Juan les Pins, Septmber 2004 (http://www.complang.tuwien.ac.at/papers/ertl%26gregg04pact.ps.gz)
May 05 2007
Hasan Aljudy wrote:I'm not sure I understand .. Do you mean like, being able to "increment" labels and move them around?
addresses to do stuff like: memcpy(dest, &start_label, (&end_label - &start_label)); - Paul
May 06 2007
They're a good idea, but they are a fair amount of work to implement, and their utility is not much beyond doing interpreters.
May 06 2007
Walter Bright wrote:They're a good idea, but they are a fair amount of work to implement, and their utility is not much beyond doing interpreters.
- Paul
May 06 2007
Walter Bright wrote:They're a good idea, but they are a fair amount of work to implement, and their utility is not much beyond doing interpreters.
I find them useful. I used them some days ago to get the size of a block of code. Anyway, isn't D going to be an awesome language for interpreters? ;) -- Luís
May 06 2007
Reply to Walter,They're a good idea, but they are a fair amount of work to implement,
Mostly just curiosity, but what makes them hard/not-easy?and their utility is not much beyond doing interpreters.
they can also be used to remove conditionals from loops |for(int i = 1; i<1000000; i++) |{ | if(complex_loop_invariant) | nothing(); | else | that() | if(complex_loop_invariant2) | other(); | else | bat(); |} // no tests in loop. |void* l1 = complex_loop_invariant ? &&a : &&b; |void* l2 = complex_loop_invariant2 ? &&c : &&d; | |for(int i = 1; i<1000000; i++) |{ | goto *l1 | a: nothing(); | goto l2: | b: that() | goto l2: | c: other(); | break; | d: bat(); |} and other fun things I can't talk about for a few days
May 06 2007
BCS wrote:// no tests in loop. |void* l1 = complex_loop_invariant ? &&a : &&b; |void* l2 = complex_loop_invariant2 ? &&c : &&d; | |for(int i = 1; i<1000000; i++) |{ | goto *l1 | a: nothing(); | goto l2: | b: that() | goto l2: | c: other(); | break; | d: bat(); |}
I hope people don't use that except in critical inner-loops or encapsulated in some form :-) -- Luís
May 06 2007
Luís Marques wrote:BCS wrote:// no tests in loop. |void* l1 = complex_loop_invariant ? &&a : &&b; |void* l2 = complex_loop_invariant2 ? &&c : &&d; | |for(int i = 1; i<1000000; i++) |{ | goto *l1 | a: nothing(); | goto l2: | b: that() | goto l2: | c: other(); | break; | d: bat(); |}
I hope people don't use that except in critical inner-loops or encapsulated in some form :-) -- Luís
What about this? |for(int i = 1; i<1000000; i++) |{ | invariant if(complex_loop_invariant) | nothing(); | else | that() | invariant if(complex_loop_invariant2) | other(); | else | bat(); |} Where "invariant if" is defined as "a conditional statement whose result is invariant in the current scope, allowing the compiler to optimise and elide subsequent evaluations until the scope is left." Or something like that. It'd be really cool if this could be extended to the general case inside of functions, provided there's a way to "reset" the switch. Maybe something like this:void padd(ubyte[] a, ubyte[] b) { selectSSE2: invariant if( cpuid.hasSSE2 ) { // SSE2 implementation } else { // Software implementation } } void reset_padd() { break padd.selectSSE2; }
Which could translate to:void* padd_selectSSE2 = &&padd.selectSSE2_init; void padd(ubyte[] a, ubyte[] b) { goto *padd_selectSSE2; selectSSE2_init: if( cpuid.hasSSE2 ) padd_selectSSE2 = &&selectSSE2_true; else padd_selectSSE2 = &&selectSSE2_false; goto *padd_selectSSE2; selectSSE2_true: // SSE2 implementation goto selectSSE2_end; selectSSE2_false: // Software implementation goto selectSSE2_end; selectSSE2_end: } void reset_padd() { padd_selectSSE2 = &&padd.selectSSE2_init; }
That might even please the people talking about multi-platform binaries, especially if the compiler is clever enough to actually re-write the GOTO on the fly :) -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 06 2007
Daniel Keep wrote:Luís Marques wrote:BCS wrote:// no tests in loop. |void* l1 = complex_loop_invariant ? &&a : &&b; |void* l2 = complex_loop_invariant2 ? &&c : &&d; | |for(int i = 1; i<1000000; i++) |{ | goto *l1 | a: nothing(); | goto l2: | b: that() | goto l2: | c: other(); | break; | d: bat(); |}
encapsulated in some form :-) -- Luís
What about this? |for(int i = 1; i<1000000; i++) |{ | invariant if(complex_loop_invariant) | nothing(); | else | that() | invariant if(complex_loop_invariant2) | other(); | else | bat(); |} Where "invariant if" is defined as "a conditional statement whose result is invariant in the current scope, allowing the compiler to optimise and elide subsequent evaluations until the scope is left." Or something like that. It'd be really cool if this could be extended to the general case inside of functions, provided there's a way to "reset" the switch. Maybe something like this:void padd(ubyte[] a, ubyte[] b) { selectSSE2: invariant if( cpuid.hasSSE2 ) { // SSE2 implementation } else { // Software implementation } } void reset_padd() { break padd.selectSSE2; }
Which could translate to:void* padd_selectSSE2 = &&padd.selectSSE2_init; void padd(ubyte[] a, ubyte[] b) { goto *padd_selectSSE2; selectSSE2_init: if( cpuid.hasSSE2 ) padd_selectSSE2 = &&selectSSE2_true; else padd_selectSSE2 = &&selectSSE2_false; goto *padd_selectSSE2; selectSSE2_true: // SSE2 implementation goto selectSSE2_end; selectSSE2_false: // Software implementation goto selectSSE2_end; selectSSE2_end: } void reset_padd() { padd_selectSSE2 = &&padd.selectSSE2_init; }
That might even please the people talking about multi-platform binaries, especially if the compiler is clever enough to actually re-write the GOTO on the fly :) -- Daniel
What about if the compiler just detected the use of a constant, and you didn't have to do anything be specify the variables as const. Also the compiler could do a better optimisation on those loops by taking the jump out all together and having 4 separate loops. -Joel
May 06 2007
janderson wrote:Daniel Keep wrote:void padd(ubyte[] a, ubyte[] b) { selectSSE2: invariant if( cpuid.hasSSE2 ) { // SSE2 implementation } else { // Software implementation } } void reset_padd() { break padd.selectSSE2; }
didn't have to do anything be specify the variables as const. Also the compiler could do a better optimisation on those loops by taking the jump out all together and having 4 separate loops. -Joel
If the contents of the conditional were constant, you could just use static if and remove the branch altogether. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 06 2007
Daniel Keep wrote:janderson wrote:Daniel Keep wrote:void padd(ubyte[] a, ubyte[] b) { selectSSE2: invariant if( cpuid.hasSSE2 ) { // SSE2 implementation } else { // Software implementation } } void reset_padd() { break padd.selectSSE2; }
didn't have to do anything be specify the variables as const. Also the compiler could do a better optimisation on those loops by taking the jump out all together and having 4 separate loops. -Joel
If the contents of the conditional were constant, you could just use static if and remove the branch altogether. -- Daniel
I apologies for not being clear, I was talking about the C++ kind. They can be initiated once every time the function is called. For instance in C++ you can do: void foo() { const Y = rand(); printf("%d\n", Y); } ... foo() foo(); Any you'll get different numbers each time. You can also do this: void foo(const int X) ... Clearly the compiler should be able to figure out that X never changes if its a simple type. -Joel
May 06 2007









Paul Findlay <r.lph50+d gmail.com> 