digitalmars.D - Complex (constant) C macros -> D
- brad domain.invalid (67/67) Feb 22 2005 I'm just looking at a couple of projects, and wondering how I can
- Kris (19/85) Feb 22 2005 One way to do it is to use the PP on the D source code. There's nothing ...
- brad domain.invalid (7/28) Feb 22 2005 Ugh! You're not really suggesting that I re-use C's pre-processor with
- Kris (8/35) Feb 22 2005 It's what one has to do to get _Line_ and _File_ info at this time. Sham...
- brad domain.invalid (9/18) Feb 22 2005 Thanks for the suggestion. I've managed to get this code working, which...
- Kris (17/35) Feb 22 2005 I tried it with mixins:
- Aleksey Bobnev (6/7) Feb 23 2005 The better way:
- brad beveridge (4/17) Feb 23 2005 Ah, much nicer. I thought there should be a way to do that, but didn't
- Ben Hinkle (17/23) Feb 22 2005 [snip]
- brad domain.invalid (10/44) Feb 22 2005 That is probably a good choice. It doesn't need to be a constant (in my...
- Ben Hinkle (4/46) Feb 22 2005 Well, technically all that the C version does is the inlining. The const...
- brad domain.invalid (31/37) Feb 22 2005 True, but would it actually work like that with plain functions? For
- Ben Hinkle (21/56) Feb 22 2005 It's the same as with C's macros. Let me illustrate. The C code
- brad beveridge (10/33) Feb 22 2005 That's good to hear, and it is what I expected. I had thought that what...
- brad beveridge (52/74) Feb 22 2005 As much as replying to my own post is poor form, here I am doing it.
- Ben Hinkle (13/86) Feb 23 2005 I had forgotten about this bug where initializers aren't inlined. Everyt...
- brad beveridge (4/19) Feb 23 2005 Not quite fine - the function gets inlined, and called with the
- Ben Hinkle (5/22) Feb 23 2005 Did you pass the -inline and -O flags to the compiler? When I tell the
- brad domain.invalid (4/33) Feb 23 2005 My apologies - you are correct. I wasn't using the -O flag. Though the...
- Kris (3/13) Feb 23 2005 I'll second that ~ such thing can cause much wailing, and gnashing of te...
- Walter (11/105) Feb 24 2005 inlining
- Derek Parnell (10/81) Feb 22 2005 It might "feel a little ugly" to you, but that is exactly what module
- brad domain.invalid (8/15) Feb 22 2005 The only remaining difference is that I can't assign a value to a const
- xs0 (9/13) Feb 22 2005 I think the issue is that foo(10) may not always return the same thing
- Derek Parnell (12/30) Feb 22 2005 Oops! I forgot about the need for a 'const'.
- Manfred Nowak (31/33) Feb 26 2005 sather has `once' parameters
- Georg Wrede (25/30) Feb 22 2005 That's a bit like the following C++, from src/dmd/parse.c
- Andy Friesen (33/40) Feb 25 2005 Sure does. Try this:
I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific. The details aren't too specific, but the macros convert from one constant form to another, here is the C code. #define INVERT_COMMANDS #ifdef INVERT_COMMANDS #define INVERT ~ #else #define INVERT #endif #define FLIP_COMMANDS #ifdef FLIP_COMMANDS #define FLIP(x) ( ((x & 0x80) >> 7) | \ ((x & 0x40) >> 5) | \ ((x & 0x20) >> 3) | \ ((x & 0x10) >> 1) | \ ((x & 0x08) << 1) | \ ((x & 0x04) << 3) | \ ((x & 0x02) << 5) | \ ((x & 0x01) << 7) ) #else #define FLIP(x) (x) #endif #define SOME_COMMAND ((INVERT (FLIP (0xE0)) & 0xFF )) Now, yes I know this is ugly, but for this project we were reverse engineering a legacy interface and were not certain of a lot of things, being able to transform the value E0, which was what the documentation said, to what the hardware expected was essential. If you notice, a decent pre-processor will fold all of those operations into a single new constant that is inverted and bit fliped. Is there anyway to do this with D? I suspect that the cleanest, and most D like way would be along the lines of: version (flip_commands) { static uint flip(uint x) { return ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ) } } else { static uint flip (uint x) { return x; } } const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called. I really feel like this would be a powerful addition to D (if it doesn't already support it). If it does support it - how can I do it? Hmm, just thinking about it some more, I can use a static module constructor to assign the value, ie static this () { SOME_COMMAND = flip (0xE0); } But that feels a little ugly. Cheers Brad PS - sorry if the formatting sucks :)
Feb 22 2005
One way to do it is to use the PP on the D source code. There's nothing stopping you using a C compiler (with PP output only!) to handle macros within D. However, you can likely do the equivalent thing using templates: template Flip (T : int) { T swizzle (T i) { // your stuff here ... return (i << 1) | (i >> 7); } } void test() { int flipped = Flip!(int).swizzle(0xEB30); } And then use 'alias' to clean up the syntax a bit. - Kris In article <cvg7sd$1d4k$1 digitaldaemon.com>, brad domain.invalid says...I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific. The details aren't too specific, but the macros convert from one constant form to another, here is the C code. #define INVERT_COMMANDS #ifdef INVERT_COMMANDS #define INVERT ~ #else #define INVERT #endif #define FLIP_COMMANDS #ifdef FLIP_COMMANDS#define FLIP(x) ( ((x & 0x80) >> 7) | \((x & 0x40) >> 5) | \ ((x & 0x20) >> 3) | \ ((x & 0x10) >> 1) | \ ((x & 0x08) << 1) | \ ((x & 0x04) << 3) | \ ((x & 0x02) << 5) | \ ((x & 0x01) << 7) ) #else #define FLIP(x) (x) #endif #define SOME_COMMAND ((INVERT (FLIP (0xE0)) & 0xFF )) Now, yes I know this is ugly, but for this project we were reverse engineering a legacy interface and were not certain of a lot of things, being able to transform the value E0, which was what the documentation said, to what the hardware expected was essential. If you notice, a decent pre-processor will fold all of those operations into a single new constant that is inverted and bit fliped. Is there anyway to do this with D? I suspect that the cleanest, and most D like way would be along the lines of: version (flip_commands) { static uint flip(uint x) { return ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ) } } else { static uint flip (uint x) { return x; } } const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called. I really feel like this would be a powerful addition to D (if it doesn't already support it). If it does support it - how can I do it? Hmm, just thinking about it some more, I can use a static module constructor to assign the value, ie static this () { SOME_COMMAND = flip (0xE0); } But that feels a little ugly. Cheers Brad PS - sorry if the formatting sucks :)
Feb 22 2005
Kris wrote:One way to do it is to use the PP on the D source code. There's nothing stopping you using a C compiler (with PP output only!) to handle macros within D. However, you can likely do the equivalent thing using templates: template Flip (T : int) { T swizzle (T i) { // your stuff here ... return (i << 1) | (i >> 7); } } void test() { int flipped = Flip!(int).swizzle(0xEB30); } And then use 'alias' to clean up the syntax a bit.Ugh! You're not really suggesting that I re-use C's pre-processor with D? Shame on you! :) I don't think that the template really solves my problem, because it still doesn't let me assign to a const variable, or outside of any functions. Brad
Feb 22 2005
In article <cvgcip$1l9p$1 digitaldaemon.com>, brad domain.invalid says...Kris wrote:It's what one has to do to get _Line_ and _File_ info at this time. Shame on Walter ... :-)One way to do it is to use the PP on the D source code. There's nothing stopping you using a C compiler (with PP output only!) to handle macros within D. However, you can likely do the equivalent thing using templates: template Flip (T : int) { T swizzle (T i) { // your stuff here ... return (i << 1) | (i >> 7); } } void test() { int flipped = Flip!(int).swizzle(0xEB30); } And then use 'alias' to clean up the syntax a bit.Ugh! You're not really suggesting that I re-use C's pre-processor with D? Shame on you! :)I don't think that the template really solves my problem, because it still doesn't let me assign to a const variable, or outside of any functions.Hmm. Walter shows a trick-pony via a recursive "compile time" template example near the bottom of this page: http://digitalmars.com/d/index.html One would hope that beast could be 'persuaded' to do what you need. - Kris
Feb 22 2005
Hmm. Walter shows a trick-pony via a recursive "compile time" template example near the bottom of this page: http://digitalmars.com/d/index.html One would hope that beast could be 'persuaded' to do what you need. - KrisThanks for the suggestion. I've managed to get this code working, which presumably could be extended to any other constant folding exercise. template Foo(int n) { const int val = n - 1; } const int test = Foo!(10).val; Though I think the syntax is on the clunky side :) Brad
Feb 22 2005
In article <cvgjed$20sn$1 digitaldaemon.com>, brad domain.invalid says...I tried it with mixins: template Flip(int b) { const int swizzle = (b << 7) | (b >> 2); } void main() { mixin Flip!(0x4566) a; mixin Flip!(0xfee1) b; printf ("%x, %x\n", a.swizzle, b.swizzle); } Would be great to get 'regular' functions evaluated at compile time. Templates are indeed klunky for such things, and terribly non-intuitive. That aside, the biggest issue with templates is that they are nigh impossible to use with a source-code debugger. - KrisHmm. Walter shows a trick-pony via a recursive "compile time" template example near the bottom of this page: http://digitalmars.com/d/index.html One would hope that beast could be 'persuaded' to do what you need. - KrisThanks for the suggestion. I've managed to get this code working, which presumably could be extended to any other constant folding exercise. template Foo(int n) { const int val = n - 1; } const int test = Foo!(10).val; Though I think the syntax is on the clunky side :) Brad
Feb 22 2005
Though I think the syntax is on the clunky side :)The better way: template Foo(int n) { const int Foo = n - 1; } const int test = Foo!(10);
Feb 23 2005
Aleksey Bobnev wrote:Ah, much nicer. I thought there should be a way to do that, but didn't know the template syntax well enough. BradThough I think the syntax is on the clunky side :)The better way: template Foo(int n) { const int Foo = n - 1; } const int test = Foo!(10);
Feb 23 2005
<brad domain.invalid> wrote in message news:cvg7sd$1d4k$1 digitaldaemon.com...I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific.[snip]const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called.[snip] Does SOME_COMMAND really have to be const? Can it be an inlined function call instead? I'm thinking something like uint flip(uint x){ compute and return flipped x } uint SOME_COMMAND(){ return flip(0xE0); } Then if you compile with -inline -O the call to SOME_COMMAND() and flip() should be inlined and the constant folding logic in the optimizer should evaluate the resulting expression at compile time. The down-sides of this approach are 1) assumes inlining and constant folding are enabled 2) you can't take the address of SOME_COMMAND and get a uint* 3) you have to write SOME_COMMAND() in code instead of SOME_COMMAND I think it's worth a shot, though. -Ben
Feb 22 2005
Ben Hinkle wrote:<brad domain.invalid> wrote in message news:cvg7sd$1d4k$1 digitaldaemon.com...That is probably a good choice. It doesn't need to be a constant (in my case), though it is a little more code than in the C case. It does also make assumptions about the inliner/optimiser - but that is easily verified with an assembler check. I guess I was hoping that I would be able to control constant munging in D just as well as I can in C with the preprocessor. I mean, with the C code I know that it will fold down to just another constant - I'll need to check the assembler output with the D method :) BradI'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific.[snip]const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called.[snip] Does SOME_COMMAND really have to be const? Can it be an inlined function call instead? I'm thinking something like uint flip(uint x){ compute and return flipped x } uint SOME_COMMAND(){ return flip(0xE0); } Then if you compile with -inline -O the call to SOME_COMMAND() and flip() should be inlined and the constant folding logic in the optimizer should evaluate the resulting expression at compile time. The down-sides of this approach are 1) assumes inlining and constant folding are enabled 2) you can't take the address of SOME_COMMAND and get a uint* 3) you have to write SOME_COMMAND() in code instead of SOME_COMMAND I think it's worth a shot, though. -Ben
Feb 22 2005
<brad domain.invalid> wrote in message news:cvghv0$1u9s$1 digitaldaemon.com...Ben Hinkle wrote:Well, technically all that the C version does is the inlining. The constant folding is still the same as D.<brad domain.invalid> wrote in message news:cvg7sd$1d4k$1 digitaldaemon.com...That is probably a good choice. It doesn't need to be a constant (in my case), though it is a little more code than in the C case. It does also make assumptions about the inliner/optimiser - but that is easily verified with an assembler check. I guess I was hoping that I would be able to control constant munging in D just as well as I can in C with the preprocessor. I mean, with the C code I know that it will fold down to just another constant - I'll need to check the assembler output with the D method :) BradI'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific.[snip]const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called.[snip] Does SOME_COMMAND really have to be const? Can it be an inlined function call instead? I'm thinking something like uint flip(uint x){ compute and return flipped x } uint SOME_COMMAND(){ return flip(0xE0); } Then if you compile with -inline -O the call to SOME_COMMAND() and flip() should be inlined and the constant folding logic in the optimizer should evaluate the resulting expression at compile time. The down-sides of this approach are 1) assumes inlining and constant folding are enabled 2) you can't take the address of SOME_COMMAND and get a uint* 3) you have to write SOME_COMMAND() in code instead of SOME_COMMAND I think it's worth a shot, though. -Ben
Feb 22 2005
Well, technically all that the C version does is the inlining. The constant folding is still the same as D.True, but would it actually work like that with plain functions? For example, the optimiser would need to be clever enough to realise that each call to the function that has a constant input should be evaluated at compile time, and then just that constant injected into the code. And for non-const inputs the actual function code gets called. What I think would happen is this int invert (int i) { return ~i; }; int myConst () { return invert(0xF0); } void code () { ... someFunc(myConst) ... } I think the optimiser would turn this into (with inlining, and constant folding) void code () { ... someFunc ( ~0xF0 ); .. } ie, the call will be inlined, but does the optimiser then further reduce that inlined call to the final optimisation of someFunc (0x0F) ? Doing it with templates (as discussed in this thread) would do it properly. I don't know enough about how the optimiser works to see if both the call will be inlined, and the constant folded. And if I don't know the answer well enough, my first instinct (when time/space is critical) is NOT to trust the compiler to do it right :) Brad
Feb 22 2005
<brad domain.invalid> wrote in message news:cvgm9s$25ab$1 digitaldaemon.com...It's the same as with C's macros. Let me illustrate. The C code #define invert(x) (~x) #define myConst (invert(0xF0)) ... someFunc( myConst ) gets expanded by the preprocessor to someFunc( (~(0xF0)) ) and then the compiler's constant folding takes it from there. In D the only difference is that there is no preprocessor to inline the "macros" - the compiler does it instead. After inlining the D compiler ends up with the exact same expression tree as the C version and from then on it is the same as C.Well, technically all that the C version does is the inlining. The constant folding is still the same as D.True, but would it actually work like that with plain functions? For example, the optimiser would need to be clever enough to realise that each call to the function that has a constant input should be evaluated at compile time, and then just that constant injected into the code. And for non-const inputs the actual function code gets called. What I think would happen is this int invert (int i) { return ~i; }; int myConst () { return invert(0xF0); } void code () { ... someFunc(myConst) ... } I think the optimiser would turn this into (with inlining, and constant folding) void code () { ... someFunc ( ~0xF0 ); .. } ie, the call will be inlined, but does the optimiser then further reduce that inlined call to the final optimisation of someFunc (0x0F) ?Doing it with templates (as discussed in this thread) would do it properly. I don't know enough about how the optimiser works to see if both the call will be inlined, and the constant folded. And if I don't know the answer well enough, my first instinct (when time/space is critical) is NOT to trust the compiler to do it right :) BradThat's ok - trusting the compiler can be risky. Though if dmd's inlining and constant folding can't produce the same result in your case as a C compiler would then Walter needs to spend some time and fix that. See also http://www.digitalmars.com/d/htomodule.html the section about macros and http://www.digitalmars.com/d/pretod.html the section about macros. Inlining is your friend!
Feb 22 2005
It's the same as with C's macros. Let me illustrate. The C code #define invert(x) (~x) #define myConst (invert(0xF0)) ... someFunc( myConst ) gets expanded by the preprocessor to someFunc( (~(0xF0)) ) and then the compiler's constant folding takes it from there. In D the only difference is that there is no preprocessor to inline the "macros" - the compiler does it instead. After inlining the D compiler ends up with the exact same expression tree as the C version and from then on it is the same as C.<snip>That's ok - trusting the compiler can be risky. Though if dmd's inlining and constant folding can't produce the same result in your case as a C compiler would then Walter needs to spend some time and fix that. See also http://www.digitalmars.com/d/htomodule.html the section about macros and http://www.digitalmars.com/d/pretod.html the section about macros. Inlining is your friend!That's good to hear, and it is what I expected. I had thought that what might happen is 1) Constant folding occurs (ie, 0xF0 - this is as reduced as it can get) 2) Inlining occurs, the ~ operation still has to happen on 0xF0. But if constant folding occurs after inlining, then everything is OK. If I am feeling particularly bored I might need to look at the assembler output. I think the template method is closer to what I am wanting. Brad
Feb 22 2005
brad beveridge wrote:As much as replying to my own post is poor form, here I am doing it. The following code illustrates both methods 1) Inlining a function call of a constant 2) Generating a constant with a template The bad news is that you were wrong Ben :) (1) doesn't give optimal results (2) does D doesn't inline & then fold constants. Which makes sense - I don't know much about compilers/optimisers, but I expect that an optimiser would need to be very smart to decide "hey, this function has constant inputs, maybe I should evaluate it at compile time and see if I can give it a constant output" Anyhow, here is some sample code. A little grovelling through the assembler output shows what is going on. Brad import std.stdio; int flip(int x) { return ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } template tflip(int x) { const int val = ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } void main() { // comment these lines in/out to show that constant folding happens // before inlining. // sub-optimal behaviour, the flip function is called and 0xFE // is bit flipped at runtime // note, you cannot have this int "const" //int i = flip(0xFE); // optimal method - the template is evaluated at compile time // and i evaluates to 0x7F, as is correct //const int i = tflip!(0xFE).val; writef("%d\n", i); }That's ok - trusting the compiler can be risky. Though if dmd's inlining and constant folding can't produce the same result in your case as a C compiler would then Walter needs to spend some time and fix that. See also http://www.digitalmars.com/d/htomodule.html the section about macros and http://www.digitalmars.com/d/pretod.html the section about macros. Inlining is your friend!That's good to hear, and it is what I expected. I had thought that what might happen is 1) Constant folding occurs (ie, 0xF0 - this is as reduced as it can get) 2) Inlining occurs, the ~ operation still has to happen on 0xF0. But if constant folding occurs after inlining, then everything is OK. If I am feeling particularly bored I might need to look at the assembler output. I think the template method is closer to what I am wanting. Brad
Feb 22 2005
"brad beveridge" <brad nowhere.com> wrote in message news:cvhc9r$1vm$1 digitaldaemon.com...brad beveridge wrote:I had forgotten about this bug where initializers aren't inlined. Everything works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers. -BenAs much as replying to my own post is poor form, here I am doing it. The following code illustrates both methods 1) Inlining a function call of a constant 2) Generating a constant with a template The bad news is that you were wrong Ben :) (1) doesn't give optimal results (2) does D doesn't inline & then fold constants. Which makes sense - I don't know much about compilers/optimisers, but I expect that an optimiser would need to be very smart to decide "hey, this function has constant inputs, maybe I should evaluate it at compile time and see if I can give it a constant output" Anyhow, here is some sample code. A little grovelling through the assembler output shows what is going on. Brad import std.stdio; int flip(int x) { return ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } template tflip(int x) { const int val = ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } void main() { // comment these lines in/out to show that constant folding happens // before inlining. // sub-optimal behaviour, the flip function is called and 0xFE // is bit flipped at runtime // note, you cannot have this int "const" //int i = flip(0xFE); // optimal method - the template is evaluated at compile time // and i evaluates to 0x7F, as is correct //const int i = tflip!(0xFE).val; writef("%d\n", i); }That's ok - trusting the compiler can be risky. Though if dmd's inlining and constant folding can't produce the same result in your case as a C compiler would then Walter needs to spend some time and fix that. See also http://www.digitalmars.com/d/htomodule.html the section about macros and http://www.digitalmars.com/d/pretod.html the section about macros. Inlining is your friend!That's good to hear, and it is what I expected. I had thought that what might happen is 1) Constant folding occurs (ie, 0xF0 - this is as reduced as it can get) 2) Inlining occurs, the ~ operation still has to happen on 0xF0. But if constant folding occurs after inlining, then everything is OK. If I am feeling particularly bored I might need to look at the assembler output. I think the template method is closer to what I am wanting. Brad
Feb 23 2005
I had forgotten about this bug where initializers aren't inlined. Everything works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers. -BenNot quite fine - the function gets inlined, and called with the parameter 0xFE. This correctly gets converted to 0x7F, but it gets converted at runtime, not compiletime. Brad
Feb 23 2005
"brad beveridge" <brad nowhere.com> wrote in message news:cvij05$1mdo$1 digitaldaemon.com...Did you pass the -inline and -O flags to the compiler? When I tell the compiler to inline and optimize it does everything at compile time (except with the initiliazer bug). Without those flags it doesn't.I had forgotten about this bug where initializers aren't inlined. Everything works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers. -BenNot quite fine - the function gets inlined, and called with the parameter 0xFE. This correctly gets converted to 0x7F, but it gets converted at runtime, not compiletime. Brad
Feb 23 2005
Ben Hinkle wrote:"brad beveridge" <brad nowhere.com> wrote in message news:cvij05$1mdo$1 digitaldaemon.com...My apologies - you are correct. I wasn't using the -O flag. Though the initialiser not inlining/optimising thing is annoying. BradDid you pass the -inline and -O flags to the compiler? When I tell the compiler to inline and optimize it does everything at compile time (except with the initiliazer bug). Without those flags it doesn't.I had forgotten about this bug where initializers aren't inlined. Everything works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers. -BenNot quite fine - the function gets inlined, and called with the parameter 0xFE. This correctly gets converted to 0x7F, but it gets converted at runtime, not compiletime. Brad
Feb 23 2005
In article <cvi17n$ubp$1 digitaldaemon.com>, Ben Hinkle says...I had forgotten about this bug where initializers aren't inlined. Everything works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers.I'll second that ~ such thing can cause much wailing, and gnashing of teeth. - Kris
Feb 23 2005
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:cvi17n$ubp$1 digitaldaemon.com..."brad beveridge" <brad nowhere.com> wrote in message news:cvhc9r$1vm$1 digitaldaemon.com...inliningbrad beveridge wrote:That's ok - trusting the compiler can be risky. Though if dmd'swhatand constant folding can't produce the same result in your case as a C compiler would then Walter needs to spend some time and fix that. See also http://www.digitalmars.com/d/htomodule.html the section about macros and http://www.digitalmars.com/d/pretod.html the section about macros. Inlining is your friend!That's good to hear, and it is what I expected. I had thought thatget)might happen is 1) Constant folding occurs (ie, 0xF0 - this is as reduced as it canIf2) Inlining occurs, the ~ operation still has to happen on 0xF0. But if constant folding occurs after inlining, then everything is OK.knowI am feeling particularly bored I might need to look at the assembler output. I think the template method is closer to what I am wanting. BradAs much as replying to my own post is poor form, here I am doing it. The following code illustrates both methods 1) Inlining a function call of a constant 2) Generating a constant with a template The bad news is that you were wrong Ben :) (1) doesn't give optimal results (2) does D doesn't inline & then fold constants. Which makes sense - I don'tneedmuch about compilers/optimisers, but I expect that an optimiser wouldmaybeto be very smart to decide "hey, this function has constant inputs,EverythingI should evaluate it at compile time and see if I can give it a constant output" Anyhow, here is some sample code. A little grovelling through the assembler output shows what is going on. Brad import std.stdio; int flip(int x) { return ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } template tflip(int x) { const int val = ( ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ); } void main() { // comment these lines in/out to show that constant folding happens // before inlining. // sub-optimal behaviour, the flip function is called and 0xFE // is bit flipped at runtime // note, you cannot have this int "const" //int i = flip(0xFE); // optimal method - the template is evaluated at compile time // and i evaluates to 0x7F, as is correct //const int i = tflip!(0xFE).val; writef("%d\n", i); }I had forgotten about this bug where initializers aren't inlined.works fine if you replace int i = flip(0xFE); with int i; i = flip(0xFE); or if you hadn't used a variable at all and instead just wrote writef("%d\n", flip(0xFE)); Walter, is that bug fixable? It's very natural to want to put inlinable expressions in initializers.Yes.
Feb 24 2005
On Wed, 23 Feb 2005 10:23:43 +1300, brad domain.invalid wrote:I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific. The details aren't too specific, but the macros convert from one constant form to another, here is the C code. #define INVERT_COMMANDS #ifdef INVERT_COMMANDS #define INVERT ~ #else #define INVERT #endif #define FLIP_COMMANDS #ifdef FLIP_COMMANDS #define FLIP(x) ( ((x & 0x80) >> 7) | \ ((x & 0x40) >> 5) | \ ((x & 0x20) >> 3) | \ ((x & 0x10) >> 1) | \ ((x & 0x08) << 1) | \ ((x & 0x04) << 3) | \ ((x & 0x02) << 5) | \ ((x & 0x01) << 7) ) #else #define FLIP(x) (x) #endif #define SOME_COMMAND ((INVERT (FLIP (0xE0)) & 0xFF )) Now, yes I know this is ugly, but for this project we were reverse engineering a legacy interface and were not certain of a lot of things, being able to transform the value E0, which was what the documentation said, to what the hardware expected was essential. If you notice, a decent pre-processor will fold all of those operations into a single new constant that is inverted and bit fliped. Is there anyway to do this with D? I suspect that the cleanest, and most D like way would be along the lines of: version (flip_commands) { static uint flip(uint x) { return ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ) } } else { static uint flip (uint x) { return x; } } const uint SOME_COMMAND = flip (0xE0); Where SOME_COMMAND is evalutated once at runtime, before the main function gets called. I really feel like this would be a powerful addition to D (if it doesn't already support it). If it does support it - how can I do it? Hmm, just thinking about it some more, I can use a static module constructor to assign the value, ie static this () { SOME_COMMAND = flip (0xE0); } But that feels a little ugly.It might "feel a little ugly" to you, but that is exactly what module constructors are for ... "SOME_COMMAND is evaluated once at runtime, before the main function gets called". In fact, I'd even make the flip() function a nested function within the module constructor if it's not needed elsewhere in the program. -- Derek Melbourne, Australia 23/02/2005 11:06:35 AM
Feb 22 2005
It might "feel a little ugly" to you, but that is exactly what module constructors are for ... "SOME_COMMAND is evaluated once at runtime, before the main function gets called". In fact, I'd even make the flip() function a nested function within the module constructor if it's not needed elsewhere in the program.The only remaining difference is that I can't assign a value to a const variable with the static module constructor method. I'm not particularly concerned, just found a little corner that I think C does better than D, and I'd like D to be better than C everywhere :) Is there a reason why D the following couldn't be valid D? static int foo(int i) { return i/2; }; const int myVar = foo(10); Brad
Feb 22 2005
Is there a reason why D the following couldn't be valid D? static int foo(int i) { return i/2; }; const int myVar = foo(10);I think the issue is that foo(10) may not always return the same thing in the general case, so you'd need to do code analysis to see that it does. Requiring code analysis in the spec (meaning every compiler has to do it) is not a good thing. The meta-programming technique (those recursive templates) is somewhat different and doesn't require code analysis (except evaluating constant expressions, but that is easy). Basically, by instantiating (sp?) those templates, a function call is simulated and its "return value" can be used.. xs0
Feb 22 2005
On Wed, 23 Feb 2005 13:20:51 +1300, brad domain.invalid wrote:Oops! I forgot about the need for a 'const'. I've occasionally thought that a write-once type of variable would be a useful addition to a language. I other words, once an assignment to such a variable has been done, all other attempts at assigning something to it would be a run-time error. It could be used for things whose value was not knowable at compile time, but during run time, it should behave as if it was a const. -- Derek Melbourne, Australia 23/02/2005 12:34:28 PMIt might "feel a little ugly" to you, but that is exactly what module constructors are for ... "SOME_COMMAND is evaluated once at runtime, before the main function gets called". In fact, I'd even make the flip() function a nested function within the module constructor if it's not needed elsewhere in the program.The only remaining difference is that I can't assign a value to a const variable with the static module constructor method. I'm not particularly concerned, just found a little corner that I think C does better than D, and I'd like D to be better than C everywhere :) Is there a reason why D the following couldn't be valid D? static int foo(int i) { return i/2; }; const int myVar = foo(10);
Feb 22 2005
Derek Parnell <derek psych.ward> wrote: [...]I've occasionally thought that a write-once type of variable would be a useful addition to a language.sather has `once' parameters <cite href="http://www.icsi.berkeley.edu/ ~sather/Documentation/LanguageDescription/webmaker/DescriptionX2Eiter ators-chapte-1.html#HEADING1-36"> Arguments which are marked with the mode 'once' are only evaluated the first time they are encountered during a loop execution. </cite> And "once" variables are easily done in D with properties: <example> private: int m= void; bit assigned= false; public: int i(){ if( assigned) return m; else throw new Exception; } int i( int value){ if( assigned) throw new Exception; else { m= value; assigned= true; } } </example>
Feb 26 2005
brad domain.invalid wrote:I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific. The details aren't too specific, but the macros convert from one constant form to another, here is the C code.That's a bit like the following C++, from src/dmd/parse.c switch (token.value) { #define X(tok,ector) \ case tok: nextToken(); e2 = parseAssignExp(); \ e = new ector(loc,e,e2); continue; X(TOKassign, AssignExp); X(TOKaddass, AddAssignExp); X(TOKminass, MinAssignExp); X(TOKmulass, MulAssignExp); X(TOKdivass, DivAssignExp); X(TOKmodass, ModAssignExp); X(TOKandass, AndAssignExp); X(TOKorass, OrAssignExp); X(TOKxorass, XorAssignExp); X(TOKshlass, ShlAssignExp); X(TOKshrass, ShrAssignExp); X(TOKushrass, UshrAssignExp); X(TOKcatass, CatAssignExp); #undef X default: break; } I've found some ways to rewrite this in D, but none of them "look nice".
Feb 22 2005
brad domain.invalid wrote:I'm just looking at a couple of projects, and wondering how I can convert them to D. The point of these macros to to translate a human readable value to something that is hardware specific. The details aren't too specific, but the macros convert from one constant form to another [...]I really feel like this would be a powerful addition to D (if it doesn't already support it). If it does support it - how can I do it?Sure does. Try this: version = INVERT_COMMANDS; version (INVERT_COMMANDS) { template INVERT(int I) { const int INVERT = ~I; } } else { template INVERT(int I) { const int INVERT = I; } } version = FLIP_COMMANDS; version (FLIP_COMMANDS) { template FLIP(int X) { const int FLIP = ((x & 0x80) >> 7) | ((x & 0x40) >> 5) | ((x & 0x20) >> 3) | ((x & 0x10) >> 1) | ((x & 0x08) << 1) | ((x & 0x04) << 3) | ((x & 0x02) << 5) | ((x & 0x01) << 7) ) ; } } else { template FLIP(int X) { const int FLIP = X; } } const int SOME_COMMAND = INVERT!(FLIP!(0xE0) & 0xFF); -- andy
Feb 25 2005