Bug 21974 – ImportC: support __builtin_va_list, __builtin_va_start, __builtin_va_arg, __builtin_va_end

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-05-25T17:29:56Z
Last change time
2022-01-22T01:30:34Z
Keywords
ImportC, rejects-valid
Assigned to
No Owner
Creator
Iain Buclaw
See also
https://issues.dlang.org/show_bug.cgi?id=22307, https://issues.dlang.org/show_bug.cgi?id=22589, https://issues.dlang.org/show_bug.cgi?id=22597

Comments

Comment #0 by ibuclaw — 2021-05-25T17:29:56Z
On C compilers, the library never defines the va_list type itself, the compiler always provides the full definition. In D, we already generate the va_list type internally (Target.tvalist), this can be exposed to importC as a `__builtin_valist` keyword to support stdio.h and stdarg.h, which have these definitions: --- typedef __builtin_va_list va_list; typedef __builtin_va_list __gnuc_va_list; ---
Comment #1 by ibuclaw — 2021-05-25T17:39:51Z
On a note of hindsight, the original location of tvalist being in Type was in-fact a good thing, and moving the type to Target will result in a bit of manoeuvring to keep the dmd.cparse happily isolated.
Comment #2 by ibuclaw — 2021-07-05T18:15:47Z
Current workaround is to add `typedef` declarations in the "wrapper" sources.
Comment #3 by bugzilla — 2021-07-16T08:47:36Z
What is the typedef you've added to the wrapper sources?
Comment #4 by bugzilla — 2021-07-16T09:14:14Z
As you say, it's problematic to add the __builtin_va_list to cparse, as cparse does not have access to the types. A simple approach is to have the semantic routines start by adding the declaration for it, rather than cparse.
Comment #5 by ibuclaw — 2021-07-16T09:40:35Z
(In reply to Walter Bright from comment #3) > What is the typedef you've added to the wrapper sources? For testing purposes. --- /* Provide user declarations of the built-in va_list type. */ #if defined(__i386__) typedef char* __builtin_va_list; #elif defined(__x86_64__) typedef struct { unsigned gp_offset; unsigned fp_offset; void *overflow_arg_area; void *reg_save_area; } __builtin_va_list[1]; #else #error "unsupported" #endif --- It's not the only `__builtin_` that I've written something to provide for. e.g: --- #define __builtin_bswap16(x) \ ((u_int16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) #define __builtin_bswap32(x) \ ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \ | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) #define __builtin_bswap64(x) \ ((((x) & 0xff00000000000000ull) >> 56) \ | (((x) & 0x00ff000000000000ull) >> 40) \ | (((x) & 0x0000ff0000000000ull) >> 24) \ | (((x) & 0x000000ff00000000ull) >> 8) \ | (((x) & 0x00000000ff000000ull) << 8) \ | (((x) & 0x0000000000ff0000ull) << 24) \ | (((x) & 0x000000000000ff00ull) << 40) \ | (((x) & 0x00000000000000ffull) << 56)) --- I'm currently on the fence really whether we should open the gates for handling `__builtin_` symbols.
Comment #6 by bugzilla — 2021-07-17T06:47:46Z
Those last three look like they were added before gcc could handle inline functions.
Comment #7 by bugzilla — 2021-07-17T07:09:57Z
One theory is if a declaration can be supplied by the library or some source file, it should *not* be built in to the compiler. This: 1. reduces the complexity of the compiler 2. makes it editable by the user 3. means updates can be done without altering the compiler 4. makes it unnecessary to get it to match every version of every C compiler out there We do this in D by automatically importing object.d. I already believe we'll have to supply such a file anyway simply to deal with all the 400 predefines that gcc generates.
Comment #8 by ibuclaw — 2021-07-18T20:42:26Z
(In reply to Walter Bright from comment #6) > Those last three look like they were added before gcc could handle inline > functions. More like, it existed before gcc recognized bswap as an intrinsic. The original code from bits/byteswap.h: --- static __inline __uint32_t __bswap_32 (__uint32_t __bsx) { #if __GNUC_PREREQ (4, 3) return __builtin_bswap32 (__bsx); #else return __bswap_constant_32 (__bsx); #endif } ---
Comment #9 by bugzilla — 2021-09-28T06:19:46Z
These also need to be added per https://issues.dlang.org/show_bug.cgi?id=22307 : __builtin_va_start __builtin_va_arg __builtin_va_end
Comment #10 by bugzilla — 2021-09-28T06:20:56Z
*** Issue 22307 has been marked as a duplicate of this issue. ***
Comment #11 by bugzilla — 2021-09-28T06:24:05Z
The following code: #include <stdarg.h> #define MAXARGS 31 int execl(const char *file, const char *args, ...) { va_list ap; char *array[MAXARGS +1]; int argno = 0; va_start(ap, args); while (args != 0 && argno < MAXARGS) { array[argno++] = args; args = va_arg(ap, const char *); } array[argno] = (char *) 0; va_end(ap); return execv(file, array); } when compiled with gcc -E test.c produces: # 1 "test.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "test.c" # 1 "/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h" 1 3 4 # 40 "/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h" 3 4 typedef __builtin_va_list __gnuc_va_list; # 98 "/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h" 3 4 typedef __gnuc_va_list va_list; # 2 "test.c" 2 int execl(const char *file, const char *args, ...) { va_list ap; char *array[31 +1]; int argno = 0; __builtin_va_start(ap,args); while (args != 0 && argno < 31) { array[argno++] = args; args = __builtin_va_arg(ap,const char *); } array[argno] = (char *) 0; __builtin_va_end(ap); return execv(file, array); }
Comment #12 by dave287091 — 2021-09-28T06:30:49Z
There’s also __builtin_va_copy for va_copy.
Comment #13 by bugzilla — 2021-09-28T07:48:24Z
https://github.com/dlang/dmd/pull/13107 solves the specific __builtin_va_list problem, but not the general problem. The general problem could be addressed by importing core.stdc.stdarg into the C semantic routines and thereby hijacking the D implementation for use with the C code.
Comment #14 by bugzilla — 2021-10-20T09:09:50Z
https://github.com/dlang/dmd/pull/13205 adds support for __builtin_va_start and __builtin_va_end
Comment #15 by bugzilla — 2022-01-22T01:30:34Z