Re: The X Macro using D

2017-07-22 Thread Martin Nowak via Digitalmars-d

On Saturday, 22 July 2017 at 11:50:40 UTC, Stefan Koch wrote:

tuple map and array are all pretty expensive.

please profile.


Well a bit more compile time isn't the end of the world, and by 
far not the only metric (e.g. readability and maintainability 
also rank high). You're slightly obsessed with the template 
compile-time topic ;).


BTW, the term expensive is fairly subjective easily 
misunderstood. Sth. more specific would reduce the chance for 
confusion, e.g. "tuple map and array require longer to compile"


Re: The X Macro using D

2017-07-22 Thread Stefan Koch via Digitalmars-d

On Friday, 21 July 2017 at 20:44:13 UTC, Enamex wrote:

On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:

[...]


How about this (if I'm not mistaken, this's only one template 
instantiation per tuple-type):


[...]


tuple map and array are all pretty expensive.

please profile.


Re: The X Macro using D

2017-07-21 Thread Nicholas Wilson via Digitalmars-d

On Friday, 21 July 2017 at 19:26:05 UTC, Johan Engelen wrote:

On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:

Some time ago, I wrote about the X Macro in C:

  https://digitalmars.com/articles/b51.html

I used it from time to time in C code. It's one of the things 
I actually like about the C preprocessor. But in translating 
the aged C code to D it was time to make X work in D. Here's 
the C code, followed by the D translation.


This mechanism is used in LLVM in a number of places, where the 
list entries are used e.g. to populate tables and to define 
aggregate member fields.

For example:
https://github.com/llvm-mirror/compiler-rt/blob/master/lib/profile/InstrProfData.inc#L29-L51


And those in turn are generated from TableGen.


Re: The X Macro using D

2017-07-21 Thread Enamex via Digitalmars-d

On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:

On 7/20/2017 2:21 PM, Stefan Koch wrote:

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.


If you like, present the CTFE solution. Should be fun!


How about this (if I'm not mistaken, this's only one template 
instantiation per tuple-type):


```d

import std.typecons: tuple, Tuple;
import std.algorithm: map;
import std.array: array;

enum regm_t {
AX, BX, CX, DX, DI, SI, None
}

enum tym_t {
uchar_, ushort_, ulong_
}

enum Ydata = [
tuple("AH",   4, regm_t.AX,   tym_t.uchar_),
tuple("AL",   0, regm_t.AX,   tym_t.uchar_),
tuple("AX",   8, regm_t.AX,   tym_t.ushort_),
tuple("BH",   7, regm_t.BX,   tym_t.uchar_),
tuple("BL",   3, regm_t.BX,   tym_t.uchar_),
tuple("BP",  13, regm_t.None, tym_t.ushort_),
tuple("BX",  11, regm_t.BX,   tym_t.ushort_),
tuple("CH",   5, regm_t.CX,   tym_t.uchar_),
tuple("CL",   1, regm_t.CX,   tym_t.uchar_),
tuple("CX",   9, regm_t.CX,   tym_t.ushort_),
tuple("DH",   6, regm_t.DX,   tym_t.uchar_),
tuple("DI",  15, regm_t.DI,   tym_t.ushort_),
tuple("DL",   2, regm_t.DX,   tym_t.uchar_),
tuple("DX",  10, regm_t.DX,   tym_t.ushort_),
tuple("EAX", 16, regm_t.AX,   tym_t.ulong_),
tuple("EBP", 21, regm_t.None, tym_t.ulong_),
tuple("EBX", 19, regm_t.BX,   tym_t.ulong_),
tuple("ECX", 17, regm_t.CX,   tym_t.ulong_),
tuple("EDI", 23, regm_t.DI,   tym_t.ulong_),
tuple("EDX", 18, regm_t.DX,   tym_t.ulong_),
tuple("ESI", 22, regm_t.SI,   tym_t.ulong_),
tuple("ESP", 20, regm_t.None, tym_t.ulong_),
tuple("SI",  14, regm_t.SI,   tym_t.ushort_),
tuple("SP",  12, regm_t.None, tym_t.ushort_),
];

static auto Y(size_t idx, T...)(Tuple!(T)[] ts) pure nothrow {
// I thought to try something like assumeUnique here
// but was thinking of the Rust semantics in doing so
// Not sure if this leads to spurious allocations at
// the points where Y is used. Is there someway to tell them,
// even if the target type is const or immutable
// that this returned array is brand new with no other 
references

// around?
return ts
.map!(x => x[idx])
.array
;
}

enum {
Xtab = 0,
Xreg,
Xmask,
Xty,
}

// Register number to use in addressing mode
private __gshared const(char)*[24] pseudotab = Y!Xtab(Ydata);


// Register number to use in addressing mode
__gshared ubyte[24] pseudoreg = Y!Xreg(Ydata);


// Mask to use for registers affected
__gshared regm_t[24] pseudomask = Y!Xmask(Ydata);


// Table for type of pseudo register variable
private __gshared const(tym_t)[24] pseudoty = Y!Xty(Ydata);
```


Re: The X Macro using D

2017-07-21 Thread Johan Engelen via Digitalmars-d

On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:

Some time ago, I wrote about the X Macro in C:

  https://digitalmars.com/articles/b51.html

I used it from time to time in C code. It's one of the things I 
actually like about the C preprocessor. But in translating the 
aged C code to D it was time to make X work in D. Here's the C 
code, followed by the D translation.


This mechanism is used in LLVM in a number of places, where the 
list entries are used e.g. to populate tables and to define 
aggregate member fields.

For example:
https://github.com/llvm-mirror/compiler-rt/blob/master/lib/profile/InstrProfData.inc#L29-L51




Re: The X Macro using D

2017-07-21 Thread Jacob Carlborg via Digitalmars-d

On 2017-07-21 14:27, Olivier FAURE wrote:


Quick questions: isn't it possible to do

 private __gshared const(char)*[24] pseudotab = Y.map!(x => x.id);

instead? That seems like the most obvious and easy to read option; and
in contrast to the other solutions proposed, it's closer to the Rule of
Least Power.


Yes, that's basically what my solution is doing [1].

[1] http://forum.dlang.org/post/oksd27$1li9$1...@digitalmars.com

--
/Jacob Carlborg


Re: The X Macro using D

2017-07-21 Thread Olivier FAURE via Digitalmars-d

On Friday, 21 July 2017 at 12:27:35 UTC, Olivier FAURE wrote:


private __gshared const(char)*[24] pseudotab = Y.map!(x => 
x.id);




I meant

 private __gshared static immutable string[Y.length] 
pseudotab = Y.map!(x => x.id);


but you get my point.

Also, upon trying it, it doesn't seem to work (at least the 
immutable part doesn't), but I don't really understand why. All 
the variables in the expression are known at compile time.


Re: The X Macro using D

2017-07-21 Thread Olivier FAURE via Digitalmars-d

On Friday, 21 July 2017 at 08:06:09 UTC, Stefan Koch wrote:

My pleasure :)

// ...

mixin((){
// ...

enum Y = [
//  id   reg  mask   ty
X("AH",   4, mAX, TYuchar),
X("AL",   0, mAX, TYuchar),
X("AX",   8, mAX, TYushort),
X("BH",   7, mBX, TYuchar),
X("BL",   3, mBX, TYuchar),
// ...
X("ESI", 22, mSI, TYulong),
X("ESP", 20,   0, TYulong),
X("SI",  14, mSI, TYushort),
X("SP",  12,   0, TYushort),
];


enum lns = itos(Y.length);

string pseudotab = "\nprivate __gshared static immutable 
string[" ~ lns ~ "] pseudotab = [";


foreach(i, r; Y)
{
pseudotab ~= `"` ~ r.id ~ `", `;
}

pseudotab ~= "];\n";

}());


Quick questions: isn't it possible to do

private __gshared const(char)*[24] pseudotab = Y.map!(x => 
x.id);


instead? That seems like the most obvious and easy to read 
option; and in contrast to the other solutions proposed, it's 
closer to the Rule of Least Power.


Re: The X Macro using D

2017-07-21 Thread Nick Treleaven via Digitalmars-d

On Friday, 21 July 2017 at 11:19:47 UTC, Patrick Schluter wrote:

In C there's no point in the X macro anymore since C99.
Designated initializer allow to do it properly[1] now.

enum COLORS { red, blue, green, max };
char *cstring[max] = {[red]="red", [blue]="blue", 
[green]="green" };  /* C99 */


I don't see how this allows data for different arrays to be 
written in interleaved form and then extracted by column to 
initialize the separate arrays, as Walter's does.


Re: The X Macro using D

2017-07-21 Thread Nicholas Wilson via Digitalmars-d

On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:

Some time ago, I wrote about the X Macro in C:

  https://digitalmars.com/articles/b51.html

I used it from time to time in C code. It's one of the things I 
actually like about the C preprocessor. But in translating the 
aged C code to D it was time to make X work in D. Here's the C 
code, followed by the D translation.


(I suppose it could be done with C++ templates, but I'll leave 
that to Andrei or Eric Niebler .)


 C Version 

// Macro trick to generate several parallel tables

#define Y \
X("AH",4,mAX,TYuchar)   \
X("AL",0,mAX,TYuchar)   \
X("AX",8,mAX,TYushort)  \
X("BH",7,mBX,TYuchar)   \
X("BL",3,mBX,TYuchar)   \
X("BP",13,0,TYushort)   \
X("BX",11,mBX,TYushort) \
X("CH",5,mCX,TYuchar)   \
X("CL",1,mCX,TYuchar)   \
X("CX",9,mCX,TYushort)  \
X("DH",6,mDX,TYuchar)   \
X("DI",15,mDI,TYushort) \
X("DL",2,mDX,TYuchar)   \
X("DX",10,mDX,TYushort) \
X("EAX",16,mAX,TYulong) \
X("EBP",21,0,TYulong)   \
X("EBX",19,mBX,TYulong) \
X("ECX",17,mCX,TYulong) \
X("EDI",23,mDI,TYulong) \
X("EDX",18,mDX,TYulong) \
X("ESI",22,mSI,TYulong) \
X("ESP",20,0,TYulong)   \
X("SI",14,mSI,TYushort) \
X("SP",12,0,TYushort)

// Table for identifiers
static const char *pseudotab[] =
{
#define X(id,reg,m,ty)  id,
Y
#undef X
};

// Register number to use in addressing mode
unsigned char pseudoreg[] =
{
#define X(id,reg,m,ty)  reg,
Y
#undef X
};

// Mask to use for registers affected
regm_t pseudomask[] =
{
#define X(id,reg,m,ty)  m,
Y
#undef X
};

// Table for type of pseudo register variable
static unsigned char pseudoty[] =
{
#define X(id,reg,m,ty)  mTYvolatile | ty,
Y
#undef X
};

 D Version 

/* 4 parallel tables using "X Macro" technique
 */

template Y(alias X)
{
enum Y =
[
//  id   reg  mask   ty
X!("AH",   4, mAX, TYuchar),
X!("AL",   0, mAX, TYuchar),
X!("AX",   8, mAX, TYushort),
X!("BH",   7, mBX, TYuchar),
X!("BL",   3, mBX, TYuchar),
X!("BP",  13,   0, TYushort),
X!("BX",  11, mBX, TYushort),
X!("CH",   5, mCX, TYuchar),
X!("CL",   1, mCX, TYuchar),
X!("CX",   9, mCX, TYushort),
X!("DH",   6, mDX, TYuchar),
X!("DI",  15, mDI, TYushort),
X!("DL",   2, mDX, TYuchar),
X!("DX",  10, mDX, TYushort),
X!("EAX", 16, mAX, TYulong),
X!("EBP", 21,   0, TYulong),
X!("EBX", 19, mBX, TYulong),
X!("ECX", 17, mCX, TYulong),
X!("EDI", 23, mDI, TYulong),
X!("EDX", 18, mDX, TYulong),
X!("ESI", 22, mSI, TYulong),
X!("ESP", 20,   0, TYulong),
X!("SI",  14, mSI, TYushort),
X!("SP",  12,   0, TYushort),
];
}

// Table for identifiers

template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = 
A; }


private __gshared const(char)*[24] pseudotab = Y!Xtab;


// Register number to use in addressing mode

template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = 
B; }


__gshared ubyte[24] pseudoreg = Y!Xreg;


// Mask to use for registers affected

template Xmask(alias A, alias B, alias C, alias D) { enum Xmask 
= C; }


__gshared regm_t[24] pseudomask = Y!Xmask;


// Table for type of pseudo register variable

template Xty(alias A, alias B, alias C, alias D) { enum Xty = 
mTYvolatile | D; }


private __gshared const(tym_t)[24] pseudoty = Y!Xty;


I wonder if you could use one of the SoA implementations (e.g 
from here: 
https://wiki.dlang.org/Transforming_slice_of_structs_into_struct_of_slices) to the same effect.


Re: The X Macro using D

2017-07-21 Thread Patrick Schluter via Digitalmars-d

On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:

Some time ago, I wrote about the X Macro in C:

  https://digitalmars.com/articles/b51.html

I used it from time to time in C code. It's one of the things I 
actually like about the C preprocessor. But in translating the 
aged C code to D it was time to make X work in D. Here's the C 
code, followed by the D translation.



In C there's no point in the X macro anymore since C99.
Designated initializer allow to do it properly[1] now.

enum COLORS { red, blue, green, max };
char *cstring[max] = {[red]="red", [blue]="blue", 
[green]="green" };  /* C99 */


It works also with array indexes[2].

int a[3] = { [2]=1, [0]=3, [1]=2 };  /* C99 designated 
initializer */
int a[3] = { [2]=1, [0]=3, 2 };  /* C99 designated 
initializer */


C++ hasn't yet integrated.


[1]: https://dlang.org/ctod.html#arrayenum
[2]: https://dlang.org/ctod.html#arrayinit2


Re: The X Macro using D

2017-07-21 Thread Jacob Carlborg via Digitalmars-d

On 2017-07-21 10:25, Stefan Koch wrote:


and leaves bloat in the binary.


Perhaps that should be fixed in the compiler ;)

--
/Jacob Carlborg


Re: The X Macro using D

2017-07-21 Thread Stefan Koch via Digitalmars-d

On Friday, 21 July 2017 at 08:12:55 UTC, Jacob Carlborg wrote:

On 2017-07-21 00:02, Walter Bright wrote:

On 7/20/2017 2:21 PM, Stefan Koch wrote:

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.


If you like, present the CTFE solution. Should be fun!


Here's my solution. It sill uses templates for the 
implementation of "map":



that uses more compile-time then mine :)
and leaves bloat in the binary.


Re: The X Macro using D

2017-07-21 Thread Jacob Carlborg via Digitalmars-d

On 2017-07-21 10:06, Stefan Koch wrote:


My pleasure :)


My approach, without string mixin: 
http://forum.dlang.org/post/oksd27$1li9$1...@digitalmars.com :)


--
/Jacob Carlborg


Re: The X Macro using D

2017-07-21 Thread Jacob Carlborg via Digitalmars-d

On 2017-07-21 00:02, Walter Bright wrote:

On 7/20/2017 2:21 PM, Stefan Koch wrote:

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.


If you like, present the CTFE solution. Should be fun!


Here's my solution. It sill uses templates for the implementation of "map":

auto map(alias func)(const(Row)[] array)
{
alias R = typeof(func(Row.init));
R[] result;

foreach (e ; array)
result ~= func(e);

return result;
}

struct Row
{
string id;
int reg;
int mask;
int ty;
}

immutable Row[2] table = [
Row("AH", 4, mAX, TYuchar),
Row("AL", 0, mAX, TYuchar)
];

alias regm_t = int;
alias tym_t = int;

enum mAX = 1;
enum TYuchar = 1;
enum mTYvolatile = 2;

private __gshared const(char)*[table.length] pseudotab = table.map!(row 
=> row.id);

__gshared ubyte[table.length] pseudoreg = table.map!(row => row.reg);
__gshared int[table.length] pseudomask = table.map!(row => row.mask);
private __gshared const(tym_t)[table.length] pseudoty = table.map!(row 
=> mTYvolatile | row.ty);


I added some type aliases and enums to be able to run the code self 
contained without DMD. Some advantages:


* Less use of templates
* More readable since there's a specific type (Row) with named fields, 
no need to write the fields in comments

* Easier to update when the length of the arrays are not hard coded

--
/Jacob Carlborg


Re: The X Macro using D

2017-07-21 Thread Stefan Koch via Digitalmars-d

On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:

On 7/20/2017 2:21 PM, Stefan Koch wrote:

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.


If you like, present the CTFE solution. Should be fun!


My pleasure :)

string itos(uint n)
{
char[] result = [];
immutable len = 10;
result.length = len;
uint i = len - 1;

while (n > 10)
{
result[i--] = cast(char) ('0' + (n % 10));
n /= 10;
}
result[i] = cast(char) ('0' + (n % 10));

return cast(string) result[i .. $];
}


mixin((){
static struct X
{
string id;
ubyte reg;
uint mask;
ubyte ty;
}

enum Y = [
//  id   reg  mask   ty
X("AH",   4, mAX, TYuchar),
X("AL",   0, mAX, TYuchar),
X("AX",   8, mAX, TYushort),
X("BH",   7, mBX, TYuchar),
X("BL",   3, mBX, TYuchar),
X("BP",  13,   0, TYushort),
X("BX",  11, mBX, TYushort),
X("CH",   5, mCX, TYuchar),
X("CL",   1, mCX, TYuchar),
X("CX",   9, mCX, TYushort),
X("DH",   6, mDX, TYuchar),
X("DI",  15, mDI, TYushort),
X("DL",   2, mDX, TYuchar),
X("DX",  10, mDX, TYushort),
X("EAX", 16, mAX, TYulong),
X("EBP", 21,   0, TYulong),
X("EBX", 19, mBX, TYulong),
X("ECX", 17, mCX, TYulong),
X("EDI", 23, mDI, TYulong),
X("EDX", 18, mDX, TYulong),
X("ESI", 22, mSI, TYulong),
X("ESP", 20,   0, TYulong),
X("SI",  14, mSI, TYushort),
X("SP",  12,   0, TYushort),
];


enum lns = itos(Y.length);

string pseudotab = "\nprivate __gshared static immutable 
string[" ~ lns ~ "] pseudotab = [";
string pseudoreg = "\nprivate __gshared static immutable 
ubyte[" ~ lns ~ "] pseudoreg = [";
string pseudomask = "\nprivate __gshared static immutable 
regm_t[" ~ lns ~ "] pseudomask = [";
string pseudoty = "\nprivate __gshared static immutable 
ubyte[" ~ lns ~ "] pseudoty = [";


foreach(i, r; Y)
{
pseudotab ~= `"` ~ r.id ~ `", `;
pseudoreg ~= itos(r.reg) ~ `, `;
pseudomask ~= itos(r.mask) ~ `, `;
pseudoty ~=  itos(r.ty) ~ `, `;
}


pseudotab ~= "];\n";
pseudoreg ~= "];\n";
pseudomask ~= "];\n";
pseudoty ~=  "];\n";


return pseudotab ~ pseudoreg ~ pseudomask ~ pseudoty;
}());



Re: The X Macro using D

2017-07-20 Thread Walter Bright via Digitalmars-d

On 7/20/2017 2:21 PM, Stefan Koch wrote:

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.


If you like, present the CTFE solution. Should be fun!


Re: The X Macro using D

2017-07-20 Thread Stefan Koch via Digitalmars-d

On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:

template Y(alias X)
{
enum Y =
[
//  id   reg  mask   ty
X!("AH",   4, mAX, TYuchar),
X!("AL",   0, mAX, TYuchar),
X!("AX",   8, mAX, TYushort),
X!("BH",   7, mBX, TYuchar),
X!("BL",   3, mBX, TYuchar),
X!("BP",  13,   0, TYushort),
X!("BX",  11, mBX, TYushort),
X!("CH",   5, mCX, TYuchar),
X!("CL",   1, mCX, TYuchar),
X!("CX",   9, mCX, TYushort),
X!("DH",   6, mDX, TYuchar),
X!("DI",  15, mDI, TYushort),
X!("DL",   2, mDX, TYuchar),
X!("DX",  10, mDX, TYushort),
X!("EAX", 16, mAX, TYulong),
X!("EBP", 21,   0, TYulong),
X!("EBX", 19, mBX, TYulong),
X!("ECX", 17, mCX, TYulong),
X!("EDI", 23, mDI, TYulong),
X!("EDX", 18, mDX, TYulong),
X!("ESI", 22, mSI, TYulong),
X!("ESP", 20,   0, TYulong),
X!("SI",  14, mSI, TYushort),
X!("SP",  12,   0, TYushort),
];
}

// Table for identifiers

template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = 
A; }


private __gshared const(char)*[24] pseudotab = Y!Xtab;


// Register number to use in addressing mode

template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = 
B; }


__gshared ubyte[24] pseudoreg = Y!Xreg;


// Mask to use for registers affected

template Xmask(alias A, alias B, alias C, alias D) { enum Xmask 
= C; }


__gshared regm_t[24] pseudomask = Y!Xmask;


// Table for type of pseudo register variable

template Xty(alias A, alias B, alias C, alias D) { enum Xty = 
mTYvolatile | D; }


private __gshared const(tym_t)[24] pseudoty = Y!Xty;


Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.