[m-users.] Dealing with lists of enums as bitflags in C

Zoltan Somogyi zoltan.somogyi at runbox.com
Tue Jul 9 09:15:58 AEST 2019



On Mon, 8 Jul 2019 23:46:14 +0100, emacstheviking <objitsu at gmail.com> wrote:
> By using the --make-target option to poke at the generated code I can see
> that it comes into the C code as MR_Word, not MR_Word*thought and then I
> tracked down the definitions of the MR_is_list_empty macros etc and
> realised pretty quickly that there is no "MR_get_next" as it should be as
> simple as pointer arithmetic but so far it has escaped my best efforts.

The definition of MR_list_tail is right next to MR_list_head in runtime/mercury_tags.h.
It follows the tail pointer field of the cons cell. There is no pointer arithmetic
involved, because assuming contiguity of cons cells wouldn't work in the general case
(since lists can be constructed dynamically).

> have seen that the array is composed as a static array of values from the
> MR_TAG_COMMON but I lost the trail at that point. Here is my code:
> 
> :- pred sdl_createwindow(string::in, int::in, int::in, int::in, int::in,
> list(window_flag)::in, io::di, io::uo) is det.
> :- pragma foreign_proc("C",
>     sdl_createwindow(Title::in, X::in, Y::in, W::in, H::in, Flags::in,
> _IO0::di, _IO::uo),
>     [promise_pure,will_not_call_mercury,does_not_affect_liveness],
> "
> Uint32 flags = 0;
> if (Flags) {
>     MR_Word* flagPtr = &Flags;
>     while(!MR_list_is_empty(*flagPtr)) {
>         Uint32 f = MR_list_head(*flagPtr);
>         flags |= f;
>         printf(""FLAGS: %u\\n"", flags);
>         flagPtr++;
>     }
> }

This is written as C code. In low level grades, the output of the Mercury compiler
*looks* like C code, but it is actually assembly code in C syntax for portability.
This is why (almost) everything has type MR_Word, which means only that
it can be stored in a general purpose register.

To see how you can traverse a list, see e.g. MR_typecheck_arguments in
runtime/mercury_construct.c.

Note that a list of integers or enums is about the most complex data structure
for whose traversal in C the Mercury runtime system has any support for.
For anything more complex, you need to know as much about Mercury's
data representation rules as an implementor.

Even in this case, I would recommend writing the code to OR the flags together
in Mercury. This would require declaring the window_flag type to be a member
of the enum typeclass, using the identity function as the implementation of the
to_int method.)The Mercury compiler should be able to generate just as good
C code as you could write yourself. And the Mercury code should be debuggable
*without* general protection faults.

Zoltan.


More information about the users mailing list