Giter Club home page Giter Club logo

tkchia / gcc-ia16 Goto Github PK

View Code? Open in Web Editor NEW

This project forked from crtc-demos/gcc-ia16

169.0 17.0 12.0 1.85 GB

Fork of Lambertsen & Jenner (& al.)'s IA-16 (Intel 16-bit x86) port of GNU compilers ― added far pointers & more • use https://github.com/tkchia/build-ia16 to build • Ubuntu binaries at https://launchpad.net/%7Etkchia/+archive/ubuntu/build-ia16/ • DJGPP/MS-DOS binaries at https://gitlab.com/tkchia/build-ia16/-/releases • mirror of https://gitlab.com/tkchia/gcc-ia16

License: GNU General Public License v2.0

Emacs Lisp 0.01% Makefile 2.50% C 48.40% Objective-C 0.24% Assembly 0.99% Shell 0.71% M4 0.70% HTML 3.65% Roff 0.04% C++ 19.43% Awk 0.04% Perl 0.08% Python 0.12% Smarty 0.01% Logos 0.05% Ada 18.63% TeX 0.24% Pawn 0.01% GCC Machine Description 4.14% OCaml 0.04%

gcc-ia16's Introduction

This directory contains the GNU Compiler Collection (GCC).

The GNU Compiler Collection is free software.  See the files whose
names start with COPYING for copying permission.  The manuals, and
some of the runtime libraries, are under different terms; see the
individual source files for details.

The directory INSTALL contains copies of the installation information
as HTML and plain text.  The source of this information is
gcc/doc/install.texi.  The installation information includes details
of what is included in the GCC sources and what files GCC installs.

See the file gcc/doc/gcc.texi (together with other files that it
includes) for usage and porting information.  An online readable
version of the manual is in the files gcc/doc/gcc.info*.

See http://gcc.gnu.org/bugs/ for how to report bugs usefully.

Copyright years on GCC source files may be listed using range
notation, e.g., 1987-2012, indicating that every year in the range,
inclusive, is a copyrightable year that could otherwise be listed
individually.

gcc-ia16's People

Contributors

asiekierka avatar iains avatar itszor avatar reenigne avatar tkchia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gcc-ia16's Issues

Linking assembly object files with ia16-elf

ia16-elf-gcc looks great and I know there is a related assembler, ia16-elf-as. But has anyone had any success linking ia16-elf with Nasm?

Nasm reports that it can output the following object formats.

valid output formats for -f are (`*' denotes default):

  • bin flat-form binary files (e.g. DOS .COM, .SYS)
    ith Intel hex
    srec Motorola S-records
    aout Linux a.out object files
    aoutb NetBSD/FreeBSD a.out object files
    coff COFF (i386) object files (e.g. DJGPP for DOS)
    elf32 ELF32 (i386) object files (e.g. Linux)
    elf64 ELF64 (x86_64) object files (e.g. Linux)
    elfx32 ELFX32 (x86_64) object files (e.g. Linux)
    as86 Linux as86 (bin86 version 0.3) object files
    obj MS-DOS 16-bit/32-bit OMF object files
    win32 Microsoft Win32 (i386) object files
    win64 Microsoft Win64 (x86-64) object files
    rdf Relocatable Dynamic Object File Format v2.0
    ieee IEEE-695 (LADsoft variant) object file format
    macho32 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files
    macho64 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files
    dbg Trace of all info passed to output stage
    elf ELF (short name for ELF32)
    macho MACHO (short name for MACHO32)
    win WIN (short name for WIN32)

Segmentation fault when compiling with -O

$ cat tst4.c
void scan(int __far *p)
{
  for(; *p; p++);
}
$ ia16-elf-gcc -O -I../hdr -c tst4.c
tst4.c: In function ‘scan’:
tst4.c:4:1: internal compiler error: Segmentation fault
 }
 ^
0x856168a crash_signal
        ../../gcc-ia16/gcc/toplev.c:333
0x8882ea7 try_combine
        ../../gcc-ia16/gcc/combine.c:4319
0x888511c combine_instructions
        ../../gcc-ia16/gcc/combine.c:1267
0x888511c rest_of_handle_combine
        ../../gcc-ia16/gcc/combine.c:14368
0x888511c execute
        ../../gcc-ia16/gcc/combine.c:14411
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

Thanks to your fix to issue 3 I can compile a lot without optimizations enabled but as soon as I do enable them I get issues. This is the smallest segmentation fault example I could produce.

compile on command line

I try to compile a hello.c program in the elks directory:
"ia16-elf-gcc ../hello.c -o hello -Iia16-elf/lib/elkslibc/include" this results in the message:
"... script dos-mtsl.ld cannot be found"
What do I have to include to get this to compile?

Copying large structure to/from far space crashes GCC

$ cat foo.c
typedef struct { char f[64]; } T;

void f (T __far *p, T __far *q)
{
  *p = *q;
}
$ ia16-elf-gcc -S -O0 foo.c
foo.c: In function ‘f’:
foo.c:6:1: error: unrecognizable insn:
 }
 ^
(insn 16 15 17 2 (set (reg:HI 29)
        (unspec:HI [
                (reg:HI 23)
            ] 1)) foo.c:5 -1
     (nil))
foo.c:6:1: internal compiler error: in extract_insn, at recog.c:2287
0x92cde8 _fatal_insn(char const*, rtx_def const*, char const*, int, char const*)
	../../gcc-ia16/gcc/rtl-error.c:108
0x92ce19 _fatal_insn_not_found(rtx_def const*, char const*, int, char const*)
	../../gcc-ia16/gcc/rtl-error.c:116
0x9027d9 extract_insn(rtx_insn*)
	../../gcc-ia16/gcc/recog.c:2287
0x75fe63 instantiate_virtual_regs_in_insn
	../../gcc-ia16/gcc/function.c:1582
0x75fe63 instantiate_virtual_regs
	../../gcc-ia16/gcc/function.c:1950
0x75fe63 execute
	../../gcc-ia16/gcc/function.c:1999
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

The failure seems to be because there is no existing instruction template for a far ↔ far (or near ↔ far) block move operation, so GCC falls fack on emit_block_move_via_loop (...) in expr.c, which tries to cram a far address into a shortword (HImode) register, which does not work.

If so, we can either tweak emit_block_move_via_loop (...) to handle this case, or write a movmemhi instruction template. (In either case, this might be a good excuse to really figure out how to make %ds available for general register allocation...)

`-nostdlib`, `-nostartfiles`, and `-nodefaultlibs` options do not work as expected

Currently the gcc-ia16 compilation driver interfaces with a linker script on the newlib-ia16 end --- dos-com.ld, dos-exe-small.ld, elks-combined.ld, or elks-separate.ld. Each linker script does everything, from laying out the output sections, to roping in the *crt*.o program startup files and the system library.

Currently -nostdlib will exclude the entire linker script --- and also erroneously lay out the output sections as if linking a 32-bit program. The correct behaviour is to lay out the output sections as appropriate for .com or .exe output (i.e. as usual), but without linking in *crt*.o and -lc -lgcc etc.

Implementing -nostdlib, -nostartfiles, and -nodefaultlibs properly will likely require co-ordination on both the GCC end and Newlib end:

  • For Newlib: factorize each linker script (e.g. dos-com.ld) into several parts.
  • For GCC: update the driver configuration to make use of the factorized scripts.

Initializing far pointer using near pointer.

This code typically compiles with DOS compilers but not ia16-elf-gcc:

$ cat nearfar.c
extern int i;
int __far *j = &i;
$ ia16-elf-gcc -c nearfar.c
nearfar.c:2:16: error: initializer element is not computable at load time
 int __far *j = &i;
                ^

Not sure if this is feasible using GCC?
It can be worked around using explicit segment and offset and a linker symbol (as in the FreeDOS kernel nls.c for nlsPackageHardcoded)..

Issue with far pointers to struct with embedded strings

Hi,

I am playing a little bit with your far pointer support and the freedos kernel. It's getting there, great work, with a few changes but it's modulo bugs. I extracted a minimal example for one of the bugs (compile with -Os):

struct string_int {
  char str[1];
  int number;
};

int p_number_not_zero(struct string_int __far *p)
{
  return p->number != 0;
}
$ ia16-elf-gcc -Os -c tst.c
tst.c: In function ‘p_number_not_zero’:
tst.c:9:1: error: unrecognizable insn:
 }
 ^
(insn 10 9 11 2 (set (subreg:HI (reg:SI 29) 0)
        (plus:HI (plus:HI (plus:HI (reg:HI 26)
                    (unspec:HI [
                            (reg:HI 27)
                        ] 1))
                (const_int 2 [0x2]))
            (const_int 2 [0x2]))) tst.c:8 -1
     (nil))
tst.c:9:1: internal compiler error: in extract_insn, at recog.c:2287
0x852e58f _fatal_insn(char const*, rtx_def const*, char const*, int, char const*)
        ../../gcc-ia16/gcc/rtl-error.c:108
0x852e5cc _fatal_insn_not_found(rtx_def const*, char const*, int, char const*)
        ../../gcc-ia16/gcc/rtl-error.c:116
0x8506f6d extract_insn(rtx_insn*)
        ../../gcc-ia16/gcc/recog.c:2287
0x8363619 instantiate_virtual_regs_in_insn
        ../../gcc-ia16/gcc/function.c:1582
0x8363619 instantiate_virtual_regs
        ../../gcc-ia16/gcc/function.c:1950
0x8363619 execute
        ../../gcc-ia16/gcc/function.c:1999
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

It compiles ok without -Os and also if the str field is removed.

Relocation truncated to fit for far variables.

For some unknown reason I can't get even your test cases to work:

$ ia16-elf-gcc -mcmodel=small far-addr-var-3.c
/tmp/ccrxTi5O.o:(.msdos_mz_reloc.0+0x2): relocation truncated to fit: R_386_RELSEG16 against `.text'
/tmp/ccrxTi5O.o:(.msdos_mz_reloc.1+0x2): relocation truncated to fit: R_386_RELSEG16 against `.text'
/tmp/ccrxTi5O.o:(.msdos_mz_reloc.2+0x2): relocation truncated to fit: R_386_RELSEG16 against `.text'
collect2: error: ld returned 1 exit status

I recompiled everything and made sure all components are up to date. Any idea how to debug this?

Thanks!

Space-consuming 32-bit division/modulo routines in libgcc

It seems that ia16-elf-gcc uses some generic 32-bit routines for __udivsi3, __umodsi3 and friends.
They weigh in heavily:
__udivsi3: 0x633 = 1587 bytes
__umodsi3: 0x58c = 1420 bytes
for 3K total.

There are some alternatives: if you want to stick with C it looks like libgcc/udivmodsi4.c and udivmod.c should generate smaller code. The FreeDOS kernel uses an asm implementation that takes 0x94 = 148 bytes total.
https://github.com/FDOS/kernel/blob/e6d427834fb5f414ecb984b87454d5df39f2f571/kernel/ludivmul.inc

ICE with string in struct, ia16_as_legitimize_address

I get an ICE on this code

struct x2 {
  char x[2];
} psp;

int get_p_x_i(struct x2 __far *p, int i)
{
  return p->x[i];
}

with and without optimization:

$ ia16-elf-gcc  -c tst5.c
tst5.c: In function ‘get_p_x_i’:
tst5.c:7:14: internal compiler error: in ia16_as_legitimize_address, at config/ia16/ia16.c:568
   return p->x[i];
          ~~~~^~~
0x87a6d06 ia16_as_legitimize_address
        ../../gcc-ia16/gcc/config/ia16/ia16.c:568
0x830815c memory_address_addr_space(machine_mode, rtx_def*, unsigned char)
        ../../gcc-ia16/gcc/explow.c:443
0x82f561a change_address_1
        ../../gcc-ia16/gcc/emit-rtl.c:2128
0x82f844b offset_address(rtx_def*, rtx_def*, unsigned long long)
        ../../gcc-ia16/gcc/emit-rtl.c:2370
0x831bb35 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
        ../../gcc-ia16/gcc/expr.c:10392
0x8326546 store_expr_with_bounds(tree_node*, rtx_def*, int, bool, bool, tree_node*)
        ../../gcc-ia16/gcc/expr.c:5409
0x8327ec9 expand_assignment(tree_node*, tree_node*, bool)
        ../../gcc-ia16/gcc/expr.c:5175
0x8253bbe expand_gimple_stmt_1
        ../../gcc-ia16/gcc/cfgexpand.c:3618
0x8253bbe expand_gimple_stmt
        ../../gcc-ia16/gcc/cfgexpand.c:3714
0x8255e1b expand_gimple_basic_block
        ../../gcc-ia16/gcc/cfgexpand.c:5720
0x825abd6 execute
        ../../gcc-ia16/gcc/cfgexpand.c:6335
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

ICE on far pointer + integer arithmetic.

Since commit b898f78 this code does not compile any more:

char __far *inc(char __far *p)
{
  return &p[1];
}
tst3.c: In function ‘inc’:
tst3.c:4:1: error: unrecognizable insn:
 }
 ^
(insn 8 7 13 2 (set (subreg:HI (reg/f:SI 21 [ _2 ]) 2)
        (subreg:HI (mem/f/c:SI (reg/f:HI 15 virtual-incoming-args) [1 p+0 S4 A16]) 2)) tst3.c:3 -1
     (nil))
tst3.c:4:1: internal compiler error: in extract_insn, at recog.c:2287
0x852e50f _fatal_insn(char const*, rtx_def const*, char const*, int, char const*)
        ../../gcc-ia16/gcc/rtl-error.c:108
0x852e54c _fatal_insn_not_found(rtx_def const*, char const*, int, char const*)
        ../../gcc-ia16/gcc/rtl-error.c:116
0x8506eed extract_insn(rtx_insn*)
        ../../gcc-ia16/gcc/recog.c:2287
0x8363599 instantiate_virtual_regs_in_insn
        ../../gcc-ia16/gcc/function.c:1582
0x8363599 instantiate_virtual_regs
        ../../gcc-ia16/gcc/function.c:1950
0x8363599 execute
        ../../gcc-ia16/gcc/function.c:1999
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

ICE in strlen-style code on far pointers with -Os, -O1, -O2

unsigned my_strlen(char __far * fname)
{
  unsigned length = 0;
  while (fname[length]) length++;
  return length;
}

compiled with -Os gives an ICE:

$ ia16-elf-gcc  -Os -c tst8.c
tst8.c: In function ‘my_strlen’:
tst8.c:1:10: internal compiler error: in ia16_as_legitimize_address, at config/ia16/ia16.c:698
 unsigned my_strlen(char __far * fname)
          ^~~~~~~~~
0x87a75a5 ia16_as_legitimize_address
        ../../gcc-ia16/gcc/config/ia16/ia16.c:698
0x830832c memory_address_addr_space(machine_mode, rtx_def*, unsigned char)
        ../../gcc-ia16/gcc/explow.c:465
0x865679c get_address_cost
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:4154
0x865679c get_computation_cost_at
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:5007
0x8657f92 get_computation_cost
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:5070
0x8657f92 determine_use_iv_cost_address
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:5116
0x8657f92 determine_use_iv_cost
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:5703
0x865acb3 determine_use_iv_costs
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:5820
0x865acb3 tree_ssa_iv_optimize_loop
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:7798
0x865acb3 tree_ssa_iv_optimize()
        ../../gcc-ia16/gcc/tree-ssa-loop-ivopts.c:7844
0x8670e9f execute
        ../../gcc-ia16/gcc/tree-ssa-loop.c:548
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

Inefficient long shift without rcl instruction.

unsigned long shl1(unsigned long x)
{
  return x << 1;
}

gives rise to code like this:

       cmpb    $0x80,  %ah
        sbbw    %cx,    %cx
        incw    %cx
        shlw    $1,     %dx
        orw     %cx,    %dx
        shlw    $1,     %ax

where I was expecting this

        shlw    $1,     %ax
        rclw    $1,     %dx

using return x + x; gives code you'd expect using add and adc.

Any chance to package up the ia16 toolchain in an Ubuntu PPA?

Now that FreeDOS has added your ia16 toolchain as a build method for the kernel, perhaps there's the opportunity to expand its availability via an Ubuntu PPA? Having the packages built automatically on every repository change using a 'recipe' would allow users to keep up to date with your current code whilst requiring minimal effort on both your part and theirs.

Medium memory model!

Now that I have got the IA-16 toolchain to support far functions --- and the MZ relocations needed to support them --- it now looks feasible to me to add support for the "medium" memory model, with one data segment and multiple text segments. This should help expand the range of programs we can express and build using gcc-ia16.

The main modifications to the toolchain will be to make sure that all functions are far by default --- even internal libgcc functions such as __udivsi3 --- and to make sure that pointer sizes, stack frame offsets, library routine implementations, etc. all reflect that.

(Unfortunately, it still seems tricky to implement the memory models with multiple data segments, i.e. "compact", "large", and "huge", or even separate data and stack segments for things like callbacks and interrupt handlers. These probably require some more thought.)

stack spilling using `-mregparmcall`

I tried to get an example as small as possible (from fattab.obj in FreeDOS kernel which does save > 2K by using mregparmcall):

struct j {
  char j;
};
struct a {
  unsigned char flag;
  struct j __far *pj;
};
extern struct a __far *fnc(int i, int j);
void foo(struct j __far * pj)
{
  struct a __far *p = fnc(0, pj->j);
  if (p)
  {
    p->flag &= ~1;
    p->pj = pj;
  }
}

if you compile this with -mregparmcall -Os -S you'll notice a weird instruction:
movb %al, -1(%bp) but that location is never read back.

Ubuntu packages for Eoan?

Hi, sorry for troubling you, but I've just upgraded my Lubuntu machine. I just tried to install your ia16-elf-gcc and find you only have packages for the LTS versions, is there any chance you can release some for Eoan, else I'll need to reinstall?

Hope you can help, thanks, Andrew!

Change `regparmcall` ABI for variadic functions to only push `...` arguments onto stack?

Currently the regparmcall calling convention falls back onto pushing all arguments onto the stack when the function being compiled is a variadic function. I am considering changing it so that it will only push the variable arguments --- i.e. the ... arguments --- onto the stack (in addition of course to any named arguments which do not fit into registers).

Since this may affect binary compatibility --- many standard C functions such as printf, open, etc. are variadic --- I would like to get some feedback first on whether this is a good idea.

Thank you!

Optimizations: low hanging fruit?

Background: I managed to compile the FreeDOS kernel now but its size (81K) is bigger than both the Open Watcom C (70K) and Turbo C 2.01 (80K) compiled versions. I am looking for some optimization opportunities.

void incnear(int *a)
{
  (*a)+=2;
}

void incfar(int __far *a)
{
  (*a)+=2;
}

compile using -Os -S

incnear

incnear:
        pushw   %bp
        movw    %sp,    %bp
        movw    4(%bp), %bx
        movw    (%bx),  %ax (*)
        addw    $2,     %ax (*)
        movw    %ax,    (%bx) (*)
        popw    %bp
        ret

here the three (*) can be combined into addw $2, (%bx). The i386 backend does this.

incfar:
        pushw   %es
        pushw   %bp
        movw    %sp,    %bp
        pushw   %ds
        lesw    6(%bp), %bx
        movw    %es:(%bx),      %ax
        addw    $2,     %ax
        movw    8(%bp), %es (**)
        movw    %ax,    %es:(%bx)
        movw    %bp,    %sp
        popw    %bp
        popw    %es
        ret

There is a second issue here in that es is reloaded (**), which may be harder.

For ++ instead of +=2 the code looks fine with a single inc instruction.

Far thunking breaks GCC build

I tried to build your latest commit (bfd61dc), and I got an error:

/mnt/data/usr/src/advantech/cross/build/gcc-build/./gcc/xgcc -B/mnt/data/usr/src/advantech/cross/build/gcc-build/./gcc/ -B/home/mfld/advantech/elks-ia16/cross/ia16-elf/bin/ -B/home/mfld/advantech/elks-ia16/cross/ia16-elf/lib/ -isystem /home/mfld/advantech/elks-ia16/cross/ia16-elf/include -isystem /home/mfld/advantech/elks-ia16/cross/ia16-elf/sys-include    -g -O2 -mrtd -O2  -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition  -isystem ./include   -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -Dinhibit_libc  -I. -I. -I../../.././gcc -I../../../../gcc-src/libgcc -I../../../../gcc-src/libgcc/. -I../../../../gcc-src/libgcc/../gcc -I../../../../gcc-src/libgcc/../include  -DHAVE_CC_TLS -DUSE_EMUTLS -o far-apply-thunk.o -MT far-apply-thunk.o -MD -MP -MF far-apply-thunk.dep  -c ../../../../gcc-src/libgcc/config/ia16/far-apply-thunk.c -fvisibility=hidden -DHIDE_EXPORTS
cc1: attention : le ssytème cible ne supporte pas la sortie pour mise au point
cc1: attention : le ssytème cible ne supporte pas la sortie pour mise au point
cc1: attention : le ssytème cible ne supporte pas la sortie pour mise au point
../../../../gcc-src/libgcc/config/ia16/far-apply-thunk.c:28:23: erreur fatale : sys/types.h : Aucun fichier ou dossier de ce type
 #include <sys/types.h>
                       ^
compilation terminée.
make[5]: *** [../../../../gcc-src/libgcc/static-object.mk:17: far-apply-thunk.o] Error 1

GCC is built that way (from ELKS tools/Makefile):

cd gcc-build && ../gcc-src/configure --target=ia16-elf --prefix="$(CROSSDIR)" --without-headers --enable-languages=c --disable-libssp --without-isl
make -C gcc-build

I guess the root cause is not linked to #40, so I opened a distinct issue for this one.

Allow output of code which can run in protected mode

Currently, gcc-ia16 outputs code which may not be suitable for running in 80286 protected mode, because the generated code may use %es and %ds to hold arbitrary values, and protected mode does not allow this.

I have been trying to implement a -mprotected-mode option, which --- if it works --- should make the output code use only %es and %ds when dereferencing pointers (and perhaps when explicitly specified as an __asm operand). The resulting code should thus be able to work even in protected mode.

Actually implementing this in GCC seems far from straightforward, however.

Possible optimization opportunities

Here is a little example:

extern int foo(int);
int bar(int a, int b)
{       int baz = foo(b);
        return a || baz < b;
}

if I compile with -Os -mregparmcall I get 43 bytes, but with Open Watcom 25 bytes (using -os -s)
A pattern in there that could be avoided is the last line in

   0:   56                      push   si
   1:   55                      push   bp
   2:   89 e5                   mov    bp,sp
   4:   1e                      push   ds
   5:   96                      xchg   si,ax
   6:   89 d0                   mov    ax,dx
   8:   89 56 fe                mov    WORD PTR [bp-0x2],dx

you see here that ds is pushed (dummy value) but later dx is put in the same place. So dx could be pushed directly instead thereby eliminating the need for the frame pointer.

If you compile with -fno-caller-saves it uses si instead of the stack entry, and di instead of si so the code size goes down to 31 bytes (and bp is no longer used). However the above pattern occurs with -fno-caller-saves too in more complex code.

Debugging output is not supported.

When running ./build.sh gcc1 or anything that is compiled natively for ia16 from the build-ia16 repository, there are about ~1000 warnings that target system does not support debug output. How hard would it be to implement this? May I help?

Spurious warning with -mfar-function-if-far-return-type

Found this while trying to eliminate as many ifdef GNUC's as possible in the FreeDOS kernel source:

$ cat farfunc.c
extern void __far foo(void);

void bar(void)
{
  foo();
}

$ ia16-elf-gcc -mcmodel=small -mfar-function-if-far-return-type -c farfunc.c 
farfunc.c: In function ‘bar’:
farfunc.c:5:3: warning: function with qualified void return type called
   foo();
   ^~~

this seems to be a very general warning without a -W switch for it. It can easily be worked around using the syntax that does not need that switch extern void foo(void) __far;

Feature request: -mrtd

It would be nice and may not be too hard to implement -mrtd (as already implemented for i386) where functions issue "ret n" instructions, so the callee pops the stack. The FreeDOS kernel saves space using that.

Most DOS compilers implement this via the Pascal calling convention which also reverts the order and capitalizes symbols but that would be another project and more difficult I think. Capitalizing symbols is easily done using asm("SYMBOLNAME") but I don't know if GCC is set up at all for reversing stack argument order.

All functions called as if cdecl with `-mrtd`

In the following:

extern char *strdup(const char *);
char *Estrdup(const char * const str)
{
	return strdup(str);
}

compiling with -mrtd -S, you see a addw $2, %sp generated that should not be there.
This seems to be a regression in c97e8cc; 95fbd1f still works properly.

How does gcc-ia16 differ from 4.9.x's `-m16` flag?

Excuse my ignorance, but how does differ gcc-ia16 from 4.9.x's -m16 flag? Is the point to create more of the supporting libs, language features & memory models a DOS C program expects? Is the hope to support the FD Kernel better than OW?

ES register preserved by function calls

In the traditional DOS cdecl ABI, ES is clobbered by function calls. ia16-elf-gcc preserves it now unless you give GCC the option -fcall-used-es. Though I managed to cause an ICE with that option: I'll submit a test case later.

Increasing field in far struct: unable to find a register to spill

Another optimizer issue turned up now:

$ cat tst9.c
struct int_struct
{
  int i;
};

void incp(struct int_struct __far *p)
{
  p->i++;
}
$ ia16-elf-gcc -Os -c tst9.c
tst9.c: In function ‘incp’:
tst9.c:9:1: error: unable to find a register to spill
 }
 ^
tst9.c:9:1: error: this is the insn:
(insn 23 22 29 2 (set (reg:HI 35)
        (mem/f/c:HI (plus:HI (reg/f:HI 14 argp)
                (const_int 6 [0x6])) [3 p+2 S2 A16])) tst9.c:8 7 {*movhi}
     (expr_list:REG_DEAD (reg:HI 14 argp)
        (nil)))
tst9.c:9: confused by earlier errors, bailing out

snprintf problem

Hi @tkcia, does gcc-ia16 support snprintf()? This example will not compile:

compile with: ia16-elf-gcc -o snprintf snprintf.c -melks-libc -mcmodel=small

#include <stdio.h>

int main ()
{
  char buffer [100];
  int cx;

  cx = snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );

  if (cx>=0 && cx<100)      // check returned value

    snprintf ( buffer+cx, 100-cx, ", and the half of that is %d.", 60/2/2 );

  puts (buffer);

  return 0;
}

[question] No use of DS & ES at all

Hello @tkchia,

Sorry to come back again to something that has already been discussed many times (including about the "protected mode" in #21), but I really need for ELKS the compiler to NOT touch at all to the current DS et ES registers, except when dealing with far pointers.

This would allow me to implement a "segment checking" in the EMU86 tool, to break execution when moving back & forth from kernel to user space, and / or catching accesses to specific segments, to ease my current debugging. If the compiler still uses ES & DS for other things than far pointers, it makes that feature hard to design.

Is this behavior exactly what the option "-protected-mode" implies ? Or could it be possible to have this behavior when using the existing '-elks' option, to not impact the other GCC-IA16 users ?

regparm

Hi,

I saw your regparm changes with interest and noticed the issues with -Os. Maybe it is better to backtrack a little and borrow from the regular i386 regparm (as in https://gcc.gnu.org/onlinedocs/gcc-6.4.0/gcc/x86-Function-Attributes.html#x86-Function-Attributes) and exclude bx? Compatibility with OpenWatcom is not very important at all, since the 4 reg calling convention is very specific to that compiler. Other DOS compilers had different regparm conventions (see page 17 here: https://www.agner.org/optimize/calling_conventions.pdf)

Secondly I found out years ago that just using ax, dx, cx can actually produce smaller code with OW (I put a pragma aux in the FD kernel to do just that, i.e. #pragma aux default parm [ax dx cx] modify [ax dx es fs]). After all. bx is special since it can be used to address memory.

Far functions with data and stack separate (was: Need sane way to define and handle far functions (callable from outside code))

There is currently no support for far functions in gcc-ia16, which is a rather bad thing, because the FreeDOS kernel relies a lot on far functions to work.

To properly support far functions, I see two things that need to be done:

  • First is a simple way to specify that a function is far, i.e. returns with lret rather than a near ret. This can be done by inventing a new function attribute (something like __attribute__ ((callfar))). If another C routine (in the same program) calls this function, GCC should arrange to add a pushw %cs before a near call instruction.
  • The second thing to do is trickier: a way for the far function to address data items in the program's data space (.rodata, .data, .bss). Currently GCC assumes that %ss points to this program data space, but this is likely not the case if the far function is called from outside code. My current idea to "work around" this is to arrange for a far function to "switch" to a designated stack area in .bss, but this has its own share of complexities...

gcc-ia16 crashes when compiling a _fmemcpy function which uses C99 variable-length arrays

$ cat foo.c
void
_fmemcpy (void __far *dest, const void __far *src, unsigned n)
{
  typedef struct __attribute__ ((packed))
    {
      char x[n];
    } buf_t;
  * (buf_t __far *) dest = * (const buf_t __far *) src;
}
$ ia16-elf-gcc -Os -S foo.c
trying to convert pointer or address in address space 0
with unexpected mode:
(reg/v/f:SI 24 [ dest ])
foo.c: In function ‘_fmemcpy’:
foo.c:8:26: internal compiler error: in convert_memory_address_addr_space_1, at explow.c:315
   * (buf_t __far *) dest = * (const buf_t __far *) src;
   ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x70be2f convert_memory_address_addr_space_1(machine_mode, rtx_def*, unsigned char, bool, bool)
	../../gcc-ia16/gcc/explow.c:315
0x70bf75 convert_memory_address_addr_space(machine_mode, rtx_def*, unsigned char)
	../../gcc-ia16/gcc/explow.c:417
0x70bf75 memory_address_addr_space(machine_mode, rtx_def*, unsigned char)
	../../gcc-ia16/gcc/explow.c:431
0x630fe3 get_memory_rtx
	../../gcc-ia16/gcc/builtins.c:1241
0x636fba expand_builtin_memcpy_args
	../../gcc-ia16/gcc/builtins.c:2930
0x63ca0d expand_builtin_memcpy
	../../gcc-ia16/gcc/builtins.c:2991
0x63ca0d expand_builtin(tree_node*, rtx_def*, rtx_def*, machine_mode, int)
	../../gcc-ia16/gcc/builtins.c:5965
0x720cec expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../gcc-ia16/gcc/expr.c:10639
0x653fbd expand_expr
	../../gcc-ia16/gcc/expr.h:256
0x653fbd expand_call_stmt
	../../gcc-ia16/gcc/cfgexpand.c:2660
0x653fbd expand_gimple_stmt_1
	../../gcc-ia16/gcc/cfgexpand.c:3548
0x653fbd expand_gimple_stmt
	../../gcc-ia16/gcc/cfgexpand.c:3714
0x65551e expand_gimple_tailcall
	../../gcc-ia16/gcc/cfgexpand.c:3761
0x65551e expand_gimple_basic_block
	../../gcc-ia16/gcc/cfgexpand.c:5697
0x65982e execute
	../../gcc-ia16/gcc/cfgexpand.c:6335
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

ICE with embedded string in far struct

Here's another issue, independent of the optimizer:

extern void farstr(char __far * s);

struct string1 {
  char str[1];
};

void call_farstr(struct string1 __far *p)
{
  farstr(p->str);
}

gives me

trying to convert pointer or address in address space 0
with unexpected mode:
(mem/f/c:SI (reg/f:HI 15 virtual-incoming-args) [1 p+0 S4 A16])
test2.c: In function ‘call_farstr’:
test2.c:9:10: internal compiler error: in convert_memory_address_addr_space_1, at explow.c:298
   farstr(p->str);
          ^
0x8307e51 convert_memory_address_addr_space_1(machine_mode, rtx_def*, unsigned char, bool, bool)
        ../../gcc-ia16/gcc/explow.c:298
0x8307e79 convert_memory_address_addr_space(machine_mode, rtx_def*, unsigned char)
        ../../gcc-ia16/gcc/explow.c:400
0x831ccae expand_expr_addr_expr
        ../../gcc-ia16/gcc/expr.c:7810
0x831ccae expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
        ../../gcc-ia16/gcc/expr.c:10867
0x8326576 store_expr_with_bounds(tree_node*, rtx_def*, int, bool, bool, tree_node*)
        ../../gcc-ia16/gcc/expr.c:5409
0x8327ef9 expand_assignment(tree_node*, tree_node*, bool)
        ../../gcc-ia16/gcc/expr.c:5175
0x8253bbe expand_gimple_stmt_1
        ../../gcc-ia16/gcc/cfgexpand.c:3618
0x8253bbe expand_gimple_stmt
        ../../gcc-ia16/gcc/cfgexpand.c:3714
0x8255e1b expand_gimple_basic_block
        ../../gcc-ia16/gcc/cfgexpand.c:5720
0x825abd6 execute
        ../../gcc-ia16/gcc/cfgexpand.c:6335
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

ICE for fmemcpy with -Os, -O2

This "fmemcpy" causes trouble with -Os and -O2, but is ok with -O1.

$ cat fmemcpy.c
void _fmemcpy(void __far *s1, const void __far *s2, unsigned length)
{       char __far *p;
        const char __far *q;

        if(length) {
                p = s1;
                q = s2;
                do *p++ = *q++;
                while(--length);
        }
}
$ ia16-elf-gcc -Os fmemcpy.c -c
fmemcpy.c: In function ‘_fmemcpy’:
fmemcpy.c:11:1: error: unable to find a register to spill
 }
 ^
fmemcpy.c:11:1: error: this is the insn:
(insn 38 90 91 3 (set (reg:QI 52)
        (mem:QI (plus:HI (unspec:HI [
                        (reg:HI 51 [orig:49 s2+2 ] [49])
                    ] 1)
                (reg:HI 40 [ q ])) [0 *q_3+0 S1 A8 AS1])) fmemcpy.c:8 9 {*movqi}
     (expr_list:REG_DEAD (reg:HI 51 [orig:49 s2+2 ] [49])
        (nil)))
fmemcpy.c:11: confused by earlier errors, bailing out

Using gcc-ia16 for ELKS

Hello, I am MFLD, currently working on ELKS to port it to a 8086-based SBC. With the maintainers, we are considering switching from the obsolete BCC to gcc-ia16, and it is nice to see that this fork is alive, and moreover you started to implement far pointers: thank you for this feature that would help a lot.

As your fork is currently moving fast, could you please point out the latest "stable" version in your history, so that we could base our work on it ?

Wrong comparison to zero with '-Os'

Hello @tkchia,

I am wondering if GCC-IA16 generates the right code for one routine in the ELKS source.

From https://github.com/jbruchon/elks/blob/master/elkscmd/file_utils/cat.c:

static int dumpfile(int fd)
{
	int nred;

	while ((nred = read(fd, readbuf, CAT_BUF_SIZE)) > 0) {
		write(STDOUT_FILENO, readbuf, nred);
	}
	if (nred < 0) return -1;
	return 0;
}

Generated code:

3615:0000  56                 PUSH    SI
3615:0001  55                 PUSH    BP
3615:0002  89 E5              MOV     BP,SP
3615:0004  B8 00 10           MOV     AX,1000h
3615:0007  50                 PUSH    AX
3615:0008  BE AE 00           MOV     SI,00AEh
3615:000B  56                 PUSH    SI
3615:000C  FF 76 06           PUSH    [BP+6h]
3615:000F  E8 B3 12           CALL    12C5h
3615:0012  83 C4 06           ADD     SP,6h
3615:0015  21 C0              AND     AX,AX
3615:0017  7F 08              JG      0021h
3615:0019  F5                 CMC
3615:001A  19 C0              SBB     AX,AX
3615:001C  89 EC              MOV     SP,BP
3615:001E  5D                 POP     BP
3615:001F  5E                 POP     SI
3615:0020  C3                 RET
3615:0021  50                 PUSH    AX
3615:0022  56                 PUSH    SI
3615:0023  B8 01 00           MOV     AX,0001h
3615:0026  50                 PUSH    AX
3615:0027  E8 A1 12           CALL    12CBh
3615:002A  83 C4 06           ADD     SP,6h
3615:002D  EB D5              JMP     0004h

I cannot see any path where the routine could return 0 ?

The source is compiled that way:

ia16-elf-gcc -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -mtune=i8086 -Wall -Os  -I/mnt/data/home/mfld/advantech/elks-ia16/include -I/mnt/data/home/mfld/advantech/elks-ia16/libc/include -I/mnt/data/home/mfld/advantech/elks-ia16/elks/include -D__ELKS__ -DELKS_VERSION=\"0.2.0-prei86\" -c -o cat.o cat.c

Too long comparison code with '-Os' ?

I am getting mad while debugging the comparisons generated by gcc-ia16 😄 !

Latest thing I don't understand: from https://github.com/jbruchon/elks/blob/switch-to-gcc/libc/misc/strtol.c:

unsigned long int
strtoul(const char *nptr, char **endptr, int base)
{
  unsigned long int number;

  /* Sanity check the arguments */
  if (base==1 || base>36 || base<0)
    base=0;

Generated code:

1CB7:1F8C  56                 PUSH    SI
1CB7:1F8D  57                 PUSH    DI
1CB7:1F8E  55                 PUSH    BP
1CB7:1F8F  89 E5              MOV     BP,SP
1CB7:1F91  83 EC 06           SUB     SP,6h
1CB7:1F94  83 7E 0C 01        CMP     [BP+Ch],1h
1CB7:1F98  9F                 LAHF
1CB7:1F99  D0 E4              SHL     AH,01h
1CB7:1F9B  99                 CWD
1CB7:1F9C  F6 DA              NEG     DL
1CB7:1F9E  83 7E 0C 25        CMP     [BP+Ch],25h
1CB7:1FA2  18 C0              SBB     AL,AL
1CB7:1FA4  FE C0              INC     AL
1CB7:1FA6  08 C2              OR      DL,AL
1CB7:1FA8  80 FA 01           CMP     DL,01h
1CB7:1FAB  19 C0              SBB     AX,AX
1CB7:1FAD  21 46 0C           AND     [BP+Ch],AX

Built that way:

ia16-elf-gcc -mtune=i8086 -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -melks -I/mnt/data/home/mfld/advantech/elks-ia16/include -I/mnt/data/home/mfld/advantech/elks-ia16/libc/include -I/mnt/data/home/mfld/advantech/elks-ia16/elks/include -D__LIBC__ -D__LIBC_VER__='"elks-0.0"' -D__HAS_NO_FLOATS__ -Wall -O1 -c -o strtol.o strtol.c

Link as86 object file with gcc-ia16?

I am used to write assembler code in Intel syntax. NASM supports the "-f as86" output format. I could link this output format with bcc and run the program with ELKS. This is documented in the "elks/Documentation/html/user/writing_apps_in_assembler.html" file. Is there a way to do that with gcc-ia16 too? Here is the section from the NASM manual:

7.12 as86: Minix/Linux as86 Object Files

The Minix/Linux 16-bit assembler as86 has its own non-standard object file format. Although its
companion linker ld86 produces something close to ordinary a.out binaries as output, the object
file format used to communicate between as86 and ld86 is not itself a.out.

NASM supports this format, just in case it is useful, as as86. as86 provides a default output file-
name extension of .o.

as86 is a very simple object format (from the NASM user's point of view). It supports no special
directives, no use of SEG or WRT, and no extensions to any standard directives. It supports only
the three standard section names .text, .data and .bss. The only special symbol supported is ..start.

ICE with -Os on far pointer passing

Variation of #6 :

struct x2 {
  char x[2];
} psp;

extern void foo(char __far *p);

void foo_p_x_i(struct x2 __far *p, int i)
{
  foo(&p->x[i]);
}

This compiles ok without any optimization and with -Og but not with -O, -Os etc.

tst6.c: In function ‘foo_p_x_i’:
tst6.c:9:3: internal compiler error: in ia16_expand_weird_pointer_plus_expr, at config/ia16/ia16.c:586
   foo(&p->x[i]);
   ^~~~~~~~~~~~~
0x87a4b34 ia16_expand_weird_pointer_plus_expr(tree_node*, tree_node*, rtx_def*, machine_mode, unsigned int)
        ../../gcc-ia16/gcc/config/ia16/ia16.c:586
0x832e3eb expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier)
        ../../gcc-ia16/gcc/expr.c:8283
0x831e9eb expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
        ../../gcc-ia16/gcc/expr.c:9593
0x8244df1 expand_expr
        ../../gcc-ia16/gcc/expr.h:256
0x8244df1 store_one_arg
        ../../gcc-ia16/gcc/calls.c:4820
0x824849c expand_call(tree_node*, rtx_def*, int)
        ../../gcc-ia16/gcc/calls.c:3203
0x831d556 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
        ../../gcc-ia16/gcc/expr.c:10636
0x82542a0 expand_expr
        ../../gcc-ia16/gcc/expr.h:256
0x82542a0 expand_call_stmt
        ../../gcc-ia16/gcc/cfgexpand.c:2660
0x82542a0 expand_gimple_stmt_1
        ../../gcc-ia16/gcc/cfgexpand.c:3548
0x82542a0 expand_gimple_stmt
        ../../gcc-ia16/gcc/cfgexpand.c:3714
0x8255e6b expand_gimple_basic_block
        ../../gcc-ia16/gcc/cfgexpand.c:5720
0x825ac26 execute
        ../../gcc-ia16/gcc/cfgexpand.c:6335
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

It can be worked around using a "noinline" helper function to get &p->x[i].

Incompatibility in __far syntax vs DOS compilers.

This little piece of code:

int main(void)
{
  char __far *a, *b;
  return sizeof(a) == sizeof(b);
}

returns 1 for gcc-ia16 (both a and b are far pointers) but 0 for Open Watcom (only a is a far pointer). In OW you need to declare:
char __far *a, __far *b;
to make both far. This syntax is rejected by gcc-ia16.
It's easy to work around, just a somewhat annoying incompatibility. Perhaps the GCC parser really is not set up for this: the restrict keyword binds similarly but comes after the *.

ICE in reload_combine_note_use with -Os

This funny piece of code (because it's been shrunk) causes an ICE with -Os

const char __far *get_end(const char __far * fname, unsigned length)
{
  while (length && *++fname)
    length--;
  return fname;
}

void pad_spaces(char __far *s)
{
  int i;
  /* pad with spaces */
  for (i = 10; s[i] == '\0'; i--)
    s[i] = ' ';
}

$ ia16-elf-gcc -Os -c tst10.c
tst10.c: In function ‘pad_spaces’:
tst10.c:14:1: internal compiler error: in reload_combine_note_use, at postreload.c:1536
}
^
0x84eac48 reload_combine_note_use
../../gcc-ia16/gcc/postreload.c:1536
0x84eaa32 reload_combine_note_use
../../gcc-ia16/gcc/postreload.c:1598
0x84ea9f7 reload_combine_note_use
../../gcc-ia16/gcc/postreload.c:1603
0x84ec5ca reload_combine
../../gcc-ia16/gcc/postreload.c:1386
0x84ed53f reload_cse_regs
../../gcc-ia16/gcc/postreload.c:68
0x84ed53f execute
../../gcc-ia16/gcc/postreload.c:2343
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See http://gcc.gnu.org/bugs.html for instructions.

frame pointer use with `-mregparmcall`

I see the standard prologue (push %bp; mov %sp,%bp etc.) /epilogue used with -fomit-frame-pointer, even if the function does not actually use bp. This is particularly relevant with -mregparmcall when the frame is not necessary, although even one-parameter cdecl functions without many local variables can benefit (via %bx and %ss:0x2(%bx) etc).

[question] -mcmodel=small or -mseparate-code-segment ?

Hello @tkchia,

I am reworking some Makefiles using ia16-elf-gcc, and I wonder why the previous contributor used the -mseparate-code-segment in place of -mcmodel=small. Could you please briefly explain what is the difference between the two options ?

Enhancment: far pascal

In some code (typically 16 bit Windows 3.x) code, I've seen references to 'pascal' modifiers.

The pascal 'modifier' as far as I can understand changes the function prolog/epilog generation, because "pascal" functions clean up the stack in the called funciton, whereas ccdecl leave this to the caller.

https://jdebp.eu/FGA/function-calling-conventions.html has some more on this.

See also a section in - https://www.nasm.us/doc/nasmdoc8.html about writing 16 bit code.

Apologies if this is something that's already supported.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.