www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reducing source code: weak+alias values in array

reply "Jens Bauer" <doctor who.no> writes:
I was wondering if there's a way to reduce my bulky startup files 
a bit.

If using the GNU Assembler (GAS), then one can reduce the code 
using a macro like this:


/* The EXC macro makes a weak+alias for the
  * symbol 'value', then it stores the value in memory: */
	.macro		EXC	value,defaultValue
	.ifnb		\defaultValue
	.weakref	\value,\defaultValue
	.else
	.weakref	\value,defaultExceptionVector
	.endif
	.4byte		\value
	.endm


/* The exception vector now looks quite simple: */
isr_vector:
	.4byte		_stack
	EXC		Reset_Handler,defaultResetHandler
	EXC		NMI_Handler
	EXC		HardFault_Handler
	EXC		MemManage_Handler
	EXC		BusFault_Handler
	EXC		UsageFault_Handler
	.4byte		0
	.4byte		0
	.4byte		0
	.4byte		0
	EXC		SVC_Handler
	EXC		DebugMon_Handler
	.4byte		0
	EXC		PendSV_Handler
	EXC		SysTick_Handler

An example on one of my bulky startup files:
https://github.com/jens-gpio/MCU/blob/master/startup/stm/stm32f439_startup.d

I was thinking about alias (Tuple) or similar, but I'm not sure 
it would work if not declaring the label weak+alias in advance. 
Any thoughts ?
(Other suggestions on how to reduce the source code size are also 
welcome).
Apr 27 2015
parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 04/27/15 19:49, Jens Bauer via Digitalmars-d-learn wrote:
 I was wondering if there's a way to reduce my bulky startup files a bit.
 
 If using the GNU Assembler (GAS), then one can reduce the code using a macro
like this:
 
 
 /* The EXC macro makes a weak+alias for the
  * symbol 'value', then it stores the value in memory: */
     .macro        EXC    value,defaultValue
     .ifnb        \defaultValue
     .weakref    \value,\defaultValue
     .else
     .weakref    \value,defaultExceptionVector
     .endif
     .4byte        \value
     .endm
 
 
 /* The exception vector now looks quite simple: */
 isr_vector:
     .4byte        _stack
     EXC        Reset_Handler,defaultResetHandler
     EXC        NMI_Handler
     EXC        HardFault_Handler
     EXC        MemManage_Handler
     EXC        BusFault_Handler
     EXC        UsageFault_Handler
     .4byte        0
     .4byte        0
     .4byte        0
     .4byte        0
     EXC        SVC_Handler
     EXC        DebugMon_Handler
     .4byte        0
     EXC        PendSV_Handler
     EXC        SysTick_Handler
 
 An example on one of my bulky startup files:
 https://github.com/jens-gpio/MCU/blob/master/startup/stm/stm32f439_startup.d
Just create a helper module, which the startup files can all use to generate the data from a dsl. Eg import my.helper.mod; mixin(VectorFuncs!(q{ PTR stack = {`_stack`}; EXC Reset_Handler = {`defaultResetHandler`}; EXC NMI_Handler; EXC HardFault_Handler; PAD pad01; PAD pad02; //... })); // Then, in my.helper.mod: property /* section("discard.etc")*/ VectorFuncs(string dsl)() { static struct A { struct PTR { string n; property s() {return `cast(VectorFunc)&`~n;} } struct PAD { string n; property s() {return `cast(VectorFunc)null`;} } struct EXC { string n = `defaultExceptionHandler`; property s() {return null;} } mixin(dsl); } string code; foreach (I, M; A.init.tupleof) static if (is(typeof(M)==A.EXC)) code ~= ` weakalias("`~M.n~`") extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; code ~= "\n isr_vector VectorFunc[] g_pfnVectors = [\n"; foreach (I, M; A.init.tupleof) code ~= " " ~ (M.s?M.s:"&"~__traits(identifier, A.tupleof[I])) ~ ",\n"; code ~= "];\n"; return code; } and what the compiler will see when building the startup modules will look like weakalias("defaultResetHandler") extern (C) void Reset_Handler(); weakalias("defaultExceptionHandler") extern (C) void NMI_Handler(); weakalias("defaultExceptionHandler") extern (C) void HardFault_Handler(); isr_vector VectorFunc[] g_pfnVectors = [ cast(VectorFunc)&_stack, &Reset_Handler, &NMI_Handler, &HardFault_Handler, cast(VectorFunc)null, cast(VectorFunc)null, ]; artur
Apr 29 2015
next sibling parent "Jens Bauer" <doctor who.no> writes:
On Wednesday, 29 April 2015 at 13:58:14 UTC, Artur Skawina wrote:
 On 04/27/15 19:49, Jens Bauer via Digitalmars-d-learn wrote:
 I was wondering if there's a way to reduce my bulky startup 
 files a bit.
 
 If using the GNU Assembler (GAS), then one can reduce the code 
 using a macro like this:
 
{snip}
 
 An example on one of my bulky startup files:
 https://github.com/jens-gpio/MCU/blob/master/startup/stm/stm32f439_startup.d
Just create a helper module, which the startup files can all use to generate the data from a dsl. Eg
That is very cool and quite short. Thank you! I'll try it out ... I'm already starting to understand some of what's going on, but it'll probably be clearer when I've typed the code (I do not just do copy-and-paste, as I've found out that I learn better by forcing each letter through my brain).
Apr 29 2015
prev sibling next sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 29 April 2015 at 13:58:14 UTC, Artur Skawina wrote:
 On 04/27/15 19:49, Jens Bauer via Digitalmars-d-learn wrote:
 I was wondering if there's a way to reduce my bulky startup 
 files a bit.
{snip}
 Just create a helper module, which the startup files can all
 use to generate the data from a dsl. Eg
{snip} I've experimented a little with the code, but ran into two minor problems. code ~= ` weakalias("`~M.n~`") extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; The above part gives me some problems; I do not know how to create the weakalias. I can make a exc (which defaults to defaultExceptionVector) and rst (which defaults to defaultResetHandler), but I have not yet succeeded in making a universal weakalias. alias Tuple(A...) = A; alias rst = Tuple!(weak, gcc.attribute.attribute("alias", "defaultResetHandler")); alias exc = Tuple!(weak, gcc.attribute.attribute("alias", "defaultExceptionHandler")); ... I tried messing with changing the above code, but no luck so far: code ~= ` weak gcc.attribute.attribute("alias", "`~M.n~`") extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; If I modify the above to ... foreach (I, M; A.init.tupleof) { static if (is(typeof(M)==A.RST)) code ~= ` rst extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; static if (is(typeof(M)==A.EXC)) code ~= ` exc extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; } ... then it will build and produce the expected results. That requires replacing the EXC for the ResetHandler by RST, I like the original code much better, though. :) I also had some trouble with the exception vectors not being generated, and it turned out that my array was dynamic instead of static. For now, I've just made the array a constant size (100 elements); eg. changed ... code ~= "\n isr_vector VectorFunc[] g_pfnVectors = [\n"; ... to ... code ~= "\n isr_vector VectorFunc[100] g_pfnVectors = [\n"; ... Is it possible to generate a static array without specifying a fixed array size ? Apart from the above two mentioned problems, the code builds and produces the expected results. I even started to understand some parts of it, and I find it pretty awesome. ;)
May 01 2015
parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 05/01/15 22:29, Jens Bauer via Digitalmars-d-learn wrote:
 On Wednesday, 29 April 2015 at 13:58:14 UTC, Artur Skawina wrote:
 On 04/27/15 19:49, Jens Bauer via Digitalmars-d-learn wrote:
 I was wondering if there's a way to reduce my bulky startup files a bit.
{snip}
 Just create a helper module, which the startup files can all
 use to generate the data from a dsl. Eg
{snip} I've experimented a little with the code, but ran into two minor problems. code ~= ` weakalias("`~M.n~`") extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; The above part gives me some problems; I do not know how to create the weakalias.
My fault; I only looked at the generated code, but never actually tested it. Use ` weakalias!"blah"` instead: enum weakalias(string A) = gcc.attribute.attribute("alias", A); weakalias!"defaultResetHandler" extern (C) void Reset_Handler();
 I also had some trouble with the exception vectors not being generated, and it
turned out that my array was dynamic instead of static.
 
 For now, I've just made the array a constant size (100 elements); eg. changed
...
     code ~= "\n isr_vector VectorFunc[] g_pfnVectors = [\n";
 ... to ...
     code ~= "\n isr_vector VectorFunc[100] g_pfnVectors = [\n";
 ... Is it possible to generate a static array without specifying a fixed array
size ?
No, but you can just do: code ~= "\n isr_vector VectorFunc[" ~ A.tupleof.length.stringof ~ "] g_pfnVectors = [\n";
 Apart from the above two mentioned problems, the code builds and produces the
expected results. I even started to understand some parts of it, and I find it
pretty awesome. ;)
(Ab)using the compiler for the DSL parsing gets really awesome once you use other D features like multiple named member initializers, lambdas and/or static-ifs etc /inside/ the DSL. Next thing you know you'll be using DSLs that generate other DSLs that emit plain D code, with a few layers of expression templates in between... :) artur
May 01 2015
parent "Jens Bauer" <doctor who.no> writes:
On Friday, 1 May 2015 at 21:36:29 UTC, Artur Skawina wrote:
 On 05/01/15 22:29, Jens Bauer via Digitalmars-d-learn wrote:
 On Wednesday, 29 April 2015 at 13:58:14 UTC, Artur Skawina 
 wrote:
Use ` weakalias!"blah"` instead: enum weakalias(string A) = gcc.attribute.attribute("alias", A); weakalias!"defaultResetHandler" extern (C) void Reset_Handler();
Here's my resulting code-snippet: enum weak = gcc.attribute.attribute("weak"); alias Tuple(A...) = A; alias weakalias(string A) = Tuple!(weak, gcc.attribute.attribute("alias", A)); ... foreach (I, M; A.init.tupleof) { static if (is(typeof(M)==A.EXC)) code ~= ` weakalias!"`~M.n~`" extern (C) void ` ~ __traits(identifier, A.tupleof[I]) ~ "();\n"; } ... because the 'alias' attribute does not automcatically include the 'weak' attribute. It seems to work, but did I write the code correctly ?
 ... Is it possible to generate a static array without 
 specifying a fixed array size ?
No, but you can just do: code ~= "\n isr_vector VectorFunc[" ~ A.tupleof.length.stringof ~ "] g_pfnVectors = [\n";
That works great. Thank you for your valuable help. :)
 Apart from the above two mentioned problems, the code builds 
 and produces the expected results. I even started to 
 understand some parts of it, and I find it pretty awesome. ;)
(Ab)using the compiler for the DSL parsing gets really awesome {snip}
I remember the Atari 130XE (and thus the Atari 600XL/800XL) were able to auto-generate basic-code, saving a lot of typing. Though different, this really reminds me of those days. :) I've never touched a C++ template, but I've been using #define in C. Though #define is a neat feature, it does not beat this, and as I've never had enough reason to use C++ templates, I expect they're not as powerful as D's ability to generate code at compile-time.
May 01 2015
prev sibling parent reply "Jens Bauer" <doctor who.no> writes:
 On 04/27/15 19:49, Jens Bauer via Digitalmars-d-learn wrote:
 I was wondering if there's a way to reduce my bulky startup 
 files a bit.
 
On Wednesday, 29 April 2015 at 13:58:14 UTC, Artur Skawina wrote:
    mixin(VectorFuncs!(q{
       PTR stack = {`_stack`};
       EXC Reset_Handler = {`defaultResetHandler`};
       EXC NMI_Handler;
       EXC HardFault_Handler;
       PAD pad01;
       PAD pad02;
       //...
    }));
For some reason, my build time has increased dramatically... Building with 1 vector takes 0.6 seconds. Building with 2 vector takes 0.7 seconds. Building with 4 vector takes 0.9 seconds. Building with 8 vector takes 1.1 seconds. Building with 16 vectors takes 1.7 seconds. Building with 32 vectors takes 3.4 seconds. Building with 64 vectors takes 12.4 seconds. Building with 112 vectors takes 55.5 seconds. Building with 113 vectors takes 56.7 seconds. ... Two foreach loops shouldn't take that long, right ? The generated code appears to be correct, though.
May 01 2015
parent reply "Jens Bauer" <doctor who.no> writes:
On Saturday, 2 May 2015 at 03:21:38 UTC, Jens Bauer wrote:
 For some reason, my build time has increased dramatically...

 Building with 1 vector takes 0.6 seconds.
 Building with 2 vector takes 0.7 seconds.
 Building with 4 vector takes 0.9 seconds.
 Building with 8 vector takes 1.1 seconds.
 Building with 16 vectors takes 1.7 seconds.
 Building with 32 vectors takes 3.4 seconds.
 Building with 64 vectors takes 12.4 seconds.
 Building with 112 vectors takes 55.5 seconds.
 Building with 113 vectors takes 56.7 seconds.
Here's the source code for the file I'm building: http://pastebin.com/pCh9e7hQ
May 01 2015
parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 05/02/15 05:28, Jens Bauer via Digitalmars-d-learn wrote:
 On Saturday, 2 May 2015 at 03:21:38 UTC, Jens Bauer wrote:
 For some reason, my build time has increased dramatically...

 Building with 1 vector takes 0.6 seconds.
 Building with 2 vector takes 0.7 seconds.
 Building with 4 vector takes 0.9 seconds.
 Building with 8 vector takes 1.1 seconds.
 Building with 16 vectors takes 1.7 seconds.
 Building with 32 vectors takes 3.4 seconds.
 Building with 64 vectors takes 12.4 seconds.
 Building with 112 vectors takes 55.5 seconds.
 Building with 113 vectors takes 56.7 seconds.
Apparently CTFE can be very inefficient sometimes -- compiler issue. Can't think of a workaround right now; manually parsing (instead of using mixins) might help, but that would make the solution less obvious...
 Here's the source code for the file I'm building:
 
 http://pastebin.com/pCh9e7hQ
For some reason I was never really affected by the horrible CTFE perf. For example, your code from that link, after a few tweaks to get it to build, compiles in ~3s for me. (64 bit x86 linux gdc build) artur
May 02 2015
parent "Jens Bauer" <doctor who.no> writes:
On Saturday, 2 May 2015 at 13:08:27 UTC, Artur Skawina wrote:
 On 05/02/15 05:28, Jens Bauer via Digitalmars-d-learn wrote:
 On Saturday, 2 May 2015 at 03:21:38 UTC, Jens Bauer wrote:
 For some reason, my build time has increased dramatically...

 Building with 1 vector takes 0.6 seconds.
 Building with 2 vector takes 0.7 seconds.
 Building with 4 vector takes 0.9 seconds.
 Building with 8 vector takes 1.1 seconds.
 Building with 16 vectors takes 1.7 seconds.
 Building with 32 vectors takes 3.4 seconds.
 Building with 64 vectors takes 12.4 seconds.
 Building with 112 vectors takes 55.5 seconds.
 Building with 113 vectors takes 56.7 seconds.
Apparently CTFE can be very inefficient sometimes -- compiler issue. Can't think of a workaround right now; manually parsing (instead of using mixins) might help, but that would make the solution less obvious...
I'll try and make a few experiments to see if there's something that helps speeding it up.
 http://pastebin.com/pCh9e7hQ
For some reason I was never really affected by the horrible CTFE perf. For example, your code from that link, after a few tweaks to get it to build, compiles in ~3s for me. (64 bit x86 linux gdc build)
That's quick. I'd expect your computer to be a bit faster than mine. ;) I have a QuadCore 2.5GHz PowerMac G5. But I'll also be building on a Dual 2GHz ARM Cortex-A7 based CubieBoard2 if I succeed building a D compiler for it; this. I think it's important for the user that the compilation time is kept low, because many people will be building on Cortex-A based devices.
May 02 2015