January 08, 2014
On Tuesday, 7 January 2014 at 21:52:54 UTC, Dwhatever wrote:
>> What CPU/MCU are you targeting?  Are you building for bare-metal?
>
> Yes, for bare metal, no OS, nothing.
>
> I think I have to specify my target architecture and CPU otherwise the compiler cannot know that I'm cross compiling for ARM. -march= -mcpu= will not work for me.
>
> I'm trying to compile a simple stand alone object file.
>
> class TestClass
> {
>     ubyte member;
>
>     this(ubyte m) { member = m; }
>     ubyte Get() { return member; }
> };
>
>
> extern(C) void main()
> {
>     // stack class
>    scope test = new TestClass(0);
>
>    // simple inline asm test
>    __asm("mov r0,#1;
>           mov r1,#2", "~{r0,r1}");
> }
>
> This test should be simple enough I thought but it turned out that to compile and link this, D requires almost everything from the runtime.
>
> So the challenge is, compile and link the simple code above targeting ARM using LDC, no OS allowed.

First of all, there's no such thing as a class allocated on the stack in D. See here ( http://dlang.org/deprecate.html#scope for allocating classes on the stack).  You have to go with structs if you want that feature, but there are other ways like Scoped(T), RefeCounted(T), scope(exit), etc...  It feels as little half-ass to do things this way, but D is quite powerful, and an alternate, elegant solution is probably just waiting to be discovered.

Anyway, once you add the word "class" or "struct" you release an avalanche of snowballing required runtime stuff that you are likely not even using, directly or indirectly, in your program. And if using --gc-sections in your linker, it all just gets stripped out in the end. I was trying to articulate that here (http://forum.dlang.org/post/zewevdmburppufkjxdje@forum.dlang.org)

IMO this is a problem with the compiler, not D, and LDC suffers from it much more than GDC. Iain Buclaw recently made a change to GDC (http://forum.dlang.org/post/mailman.3.1387377012.2938.d.gnu@puremagic.com) that allowed me to reduce my object.d to 140 lines, and with an accompanying malloc and free, I was able to create classes. I don't know what the change was, but it was most beneficial (Thanks Iain!). I hope the LDC folks can do the same, but I probably need to file an enhancement request and make a case for it.

I'm sorry I can't share my code at the moment; I haven't decided yet where to put it.  I was studying Adam Ruppe's minimal X86 port last night and found it most useful (Thumbs Up!), but with a 2000 line object.d, it's stretching the word "minimal", at least when compared with C. But if you really want all the cool stuff D has to offer, this is probably what will be required in the end.

All the compilers seem to have been written mostly with the PC in mind, and seem to expect too much of the D runtime accompanying the compiler, which is definitely very different from C/C++ where you only pay for what you use. It also seems some argue that if you aren't using the full runtime, you aren't using D, and they have a point, but only one that limits D's appeal.  The compiler folks have been most helpful so far as I try to "go minimal" with D, but I hope they will see the benefit of an "only require what is actually used" approach. D is, however, different from C, and this may have some consequences as mentioned here ( http://forum.dlang.org/post/lagsn7$2lqc$1@digitalmars.com).

In further constrast with C, much of the language is implemented in the runtime, as you previously alluded to.  Even the switch...case statement seems to be, at least partially, implemented in the runtime (https://github.com/D-Programming-Language/druntime/blob/master/src/rt/switch_.d).  I think this is great, because this means we don't have to know how to build compilers to port the language to a given platform.  And with a "pay as you go" compiler, this could make D suitable for even the tiniest of microcontrollers.

Anyway, if you want to go minimal, go with GDC for now.  I hope to file some enhancement requests with the compilers soon that will help with this very issue, but I don't know how interested they will be in addressing them.  I do see progress being made, so I'm hopeful.

Mike
January 08, 2014
2014/1/8 Mike <none@none.com>:
> On Tuesday, 7 January 2014 at 21:52:54 UTC, Dwhatever wrote:
>>>
>>> What CPU/MCU are you targeting?  Are you building for bare-metal?
>>
>>
>> Yes, for bare metal, no OS, nothing.
>>
>> I think I have to specify my target architecture and CPU otherwise the compiler cannot know that I'm cross compiling for ARM. -march= -mcpu= will not work for me.
>>
>> I'm trying to compile a simple stand alone object file.
>>
>> class TestClass
>> {
>>     ubyte member;
>>
>>     this(ubyte m) { member = m; }
>>     ubyte Get() { return member; }
>> };
>>
>>
>> extern(C) void main()
>> {
>>     // stack class
>>    scope test = new TestClass(0);
>>
>>    // simple inline asm test
>>    __asm("mov r0,#1;
>>           mov r1,#2", "~{r0,r1}");
>> }
>>
>> This test should be simple enough I thought but it turned out that to compile and link this, D requires almost everything from the runtime.
>>
>> So the challenge is, compile and link the simple code above targeting ARM using LDC, no OS allowed.
>
>
> First of all, there's no such thing as a class allocated on the stack in D. See here ( http://dlang.org/deprecate.html#scope for allocating classes on the stack).  You have to go with structs if you want that feature, but there are other ways like Scoped(T), RefeCounted(T), scope(exit), etc...  It feels as little half-ass to do things this way, but D is quite powerful, and an alternate, elegant solution is probably just waiting to be discovered.
>

Yeah, I'd like to block that proposal for deprecation until Scoped(T) doesn't rely on DMD-specific NRVO behaviour.


> Anyway, once you add the word "class" or "struct" you release an avalanche of snowballing required runtime stuff that you are likely not even using, directly or indirectly, in your program. And if using --gc-sections in your linker, it all just gets stripped out in the end. I was trying to articulate that here (http://forum.dlang.org/post/zewevdmburppufkjxdje@forum.dlang.org)
>

If you use a struct, it generates typeinfo and initialiser symbols that go on the comdat on the basis that you *may* access the typeinfo at runtime.

These are weak decls so the linker merges/removes duplicates.  There's currently no solution in which the compiler decides whether to omit sending the symbols to object file, but this can be worked upon.

> IMO this is a problem with the compiler, not D, and LDC suffers from it much more than GDC. Iain Buclaw recently made a change to GDC (http://forum.dlang.org/post/mailman.3.1387377012.2938.d.gnu@puremagic.com) that allowed me to reduce my object.d to 140 lines, and with an accompanying malloc and free, I was able to create classes. I don't know what the change was, but it was most beneficial (Thanks Iain!). I hope the LDC folks can do the same, but I probably need to file an enhancement request and make a case for it.
>

I could have sworn that I spoke to David about this a couple months back, and it was in LDC already - unless they have some rules as to whether a static array literal is loaded on the stack or heap...

> I'm sorry I can't share my code at the moment; I haven't decided yet where to put it.  I was studying Adam Ruppe's minimal X86 port last night and found it most useful (Thumbs Up!), but with a 2000 line object.d, it's stretching the word "minimal", at least when compared with C. But if you really want all the cool stuff D has to offer, this is probably what will be required in the end.
>

So it's only double the size of C runtime (crt.o, crtend.o :-)

I think the best logical steps to go down, is that you should write a
replacement for the core library functions that the compiler
implicitly calls (_d_arrayliteralX, _d_arraycopy, _d_newclass,
_d_newitemT, etc), but omit using the TypeInfo parameter.  Once you
feel that it is ready, then we can add a switch into the compiler
that:
1) Doesn't generate typeinfo
2) Passes a null pointer as the typeinfo parameter to the Druntime
library calls.

After testing and verifying it's all going sound, I'd be happy to omit the typeinfo altogether from the compiler side.

However, before we get there, this will have some interesting hurdles to go over, for instance:

Object _d_newclass(const ClassInfo ci)  ->  Object _d_newclass()

Means that:
1) There's no way to tell the GC what we are allocating (eg: classes
with no pointer fields require no scanning).
However being bare bones, you probably won't mind this.  There is no
stop-the-world GC in the background.

2) The new'd class is not default initialised _d_newclass  (no
typeinfo, no known initialiser).
So either you accept as a reasonable trade-off that there's no default
initialisation of classes in bare-bones, or we alter the compiler
codegen to take care of the default initialisation *after* calling
_d_newclass.

Others will have similar problems to consider.
January 08, 2014
On 1/6/2014 3:47 AM, Dwhatever wrote:
> Compared to C/C++, D is very hard to get to work in the embedded/OS less
> environment because of this.

It's not that hard. Use the -betterC switch to prevent ModuleInfo records and their dependencies from being emitted, and then you can write D code that has zero dependence on druntime or phobos.

I've used this to port D to new platforms that have no druntime or phobos, because I need a working & tested compiler to compile those two.
January 08, 2014
On Wednesday, 8 January 2014 at 00:21:15 UTC, Mike wrote:
> I'm sorry I can't share my code at the moment; I haven't decided yet where to put it.  I was studying Adam Ruppe's minimal X86 port last night and found it most useful (Thumbs Up!), but with a 2000 line object.d, it's stretching the word "minimal", at least when compared with C. But if you really want all the cool stuff D has to offer, this is probably what will be required in the end.

Sorry if I'm late to reply, I'm barely following this thread, just poking in when I see me mentioned :)

But I started with a truly minimal D: the standalone file here was my first go <http://arsdnet.net/dcode/minimal.d> but indeed, that hits limits fast. I'd be ok with it as a "better C"... and the 3KB statically linked elf executable was awesome, but not even structs work, which takes a lot of fun out of things.

So I started adding stuff. Note that about 500 lines of the object.d in there aren't strictly needed, but since I had a custom druntime, I wanted to play a bit :)

Some things are needed so the compiler doesn't complain. Some stuff, typeinfo especially, are there so the linker doesn't complain.

Then classes and exceptions were a lot of code (which I copy/pasted from druntime). About line 900 - line 2000 are these. You could cut a *lot* of that out if you didn't want to use exceptions, but I like them so I wanted that to work. But exceptions need stack unwinding (BTW gdc uses a totally different stack unwinding thing, at least on ARM/raspberry pi. This is dmd's code) and classes so it kinda ballooned the size a bit.

I just fixed this to work with newer dmd btw.
http://arsdnet.net/dcode/minimal.zip

The executable was ~30 KB statically linked, and a good majority of the language worked. So I was pretty happy with that trade off. A lot of lines, but not a huge amount of bloat.



Anywho, let me get it back to the whole "minimal" thing....

But put a single struct and it complains
Error: TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch


even with -betterC :-( :-( :-(


I don't even care about typeinfo; doing my own runtime, I'd be ok with any function that needs it to simply fail to compile. I can do it myself with templates.

Basic structs should really work regardless.


> Even the switch...case statement seems to be, at least partially, implemented in the runtime

Yea, for strings. My thing did a stupid loop for string cases :P

If you don't try to use a string switch though, those references aren't emitted at all.
January 08, 2014
On Wednesday, 8 January 2014 at 01:27:28 UTC, Walter Bright wrote:
> It's not that hard. Use the -betterC switch to prevent ModuleInfo records and their dependencies from being emitted, and then you can write D code that has zero dependence on druntime or phobos.

...until you declare a struct. I find the -betterC switch to be totally useless. If you are just toying, there's no module info anyway:

extern(C) {
	void _d_run_main() {} // why is this required now????
	void* _d_dso_registry;

	void _start() {

	}
}

dmd -c *.d -defaultlib= -debuglib=
gcc -m32 *.o -nostdlib

success. Add "struct Test{}" and:

Error: ModuleInfo not found. object.d may be incorrectly installed or corrupt.

OK, add -betterC:

Error: TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch


If you do use an object.d with it defined to get past the compiler, it doesn't help much as the linker complains anyway:

test.o:(.data._D20TypeInfo_S4test4Test6__initZ+0x0): undefined reference to `_D15TypeInfo_Struct6__vtblZ'


So my verdict is -betterC is pretty useless. If it got past the TypeInfo stuff the same way it gets past ModuleInfo though, then we'd be cooking with gas. That potentially gives a language that is legitimately a better C. But without structs, bah.
January 08, 2014
On Wednesday, 8 January 2014 at 02:03:57 UTC, Adam D. Ruppe wrote:
> OK, add -betterC:
>
> Error: TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch

This is a filthy hack, but it is easy to change this in the compiler. (Isn't -betterC a filthy hack in the first place anyway :) )

In

Expression *Type::getTypeInfo(Scope *sc)

Add
    if(global.params.betterC)
        return NULL;

right to the top.

And same for struct decl

void TypeInfoStructDeclaration::toDt(dt_t **pdt)
{
    if(global.params.betterC)
        return;


Then it compiles with the struct! ~5 KB executable, two line object.d.


....but adding some methods to the struct complain about missing ModuleInfo again. Looks like it wants to do assert(this !is null); and the assert thing takes a module info reference.

Ugh.... that said, adding:

	void _d_assert_msg() {}
	void _d_assertm() {}
	void* _D4test12__ModuleInfoZ;

to my extern(C) boilerplate did manage to work - structs with postblits and dtors yay! - and trimmed the exe down to 1.3K.

Maybe -betterC can stop outputting those references too and then we'd really be cooking.
January 08, 2014
On Wednesday, 8 January 2014 at 01:27:28 UTC, Walter Bright wrote:
> I've used this to port D to new platforms that have no druntime or phobos, because I need a working & tested compiler to compile those two.

But DMD doesn't support ARM in any flavor (Cortex-A nor Cortex-M - thumb), and that is the platform Dwhatever and myself are working on.  Have you tried this with LDC and GDC?  These compilers are quickly improving, but their current in their current state, it's a very different story when compared with C/C++.

> It's not that hard. Use the -betterC switch to prevent ModuleInfo records and their dependencies from being emitted, and then you can write D code that has zero dependence on druntime or phobos.

As the creator of D and a significant author of the runtime, I think you are taking a lot for granted.  I think from your perpective, it probably isn't all that hard, and certainly as I study D and the runtime, it is becoming significantly easier.  But in comparison with C, Dwhatever is right... it's a bear, but I don't necessarily believe that that's bad.

Mostly, it is due to the current expectations of the LDC and GDC compiler.  Currently they require a large part of the runtime, that has no hope of every being called, just to get the simplest thing to compile. GDC has made significant improvement here recently, and I hope LDC will join the trend.  There's some very constructive discussion going on about this right now in other parts of this thread.

Furthtermore, the way the D Runtime is organizized, it's quite difficult to see the abstractions (if there are any). Putting some weight behind this issue (https://d.puremagic.com/issues/show_bug.cgi?id=11666) would certainly help.

The origin of this thread was really about a porting guide; an excellent idea!  You can wait several months for me learn D and the runtime and I'll create one, or you and the other D Runtime authors can create one and show us just how easy it is.  A simple wiki post like this (http://wiki.osdev.org/Porting_Newlib) would be an excellent start.

That being said, Thanks for D.  I'm quite excited about this language.

Mike

January 08, 2014
On 1/7/2014 6:22 PM, Adam D. Ruppe wrote:
> Maybe -betterC can stop outputting those references too and then we'd really be
> cooking.

-betterC does sometimes suffer from "bit rot" as a lot of people work on the front end and inadvertently subvert it. Nevertheless, the idea is sound, and it works, and it doesn't seem to have taken you long to figure it out :-)
January 08, 2014
I took the liberty:

https://d.puremagic.com/issues/show_bug.cgi?id=11881
January 08, 2014
On Wednesday, 8 January 2014 at 02:54:40 UTC, Mike wrote:
> But DMD doesn't support ARM in any flavor (Cortex-A nor Cortex-M - thumb), and that is the platform Dwhatever and myself are working on.  Have you tried this with LDC and GDC?

The switches should still work - the stuff we're talking about here is done with the frontend, which is (mostly) shared across all three compilers.