Calling inline C routine

Is there a recipe for calling an inline Chapel routine which itself calls an inline C routine (which will actually have an __asm__ statement in it). I assume it will only work with clang which may give me grief when testing for floating point exceptions but we will cross that bridge when I come to it.

Thanks - Damian

@damianmoz -- what have you tried so far? I expect that the usual interop will work, including the setups where you use gcc / C backend.

extern proc myExternProc();
inline proc myChapelProc() { myExternProc(); }

Chapel will use whatever C prototype for myExternProc you provide in the header file, it will not generate its own prototype.

I agree with Vass — If the external C routine is defined as a static inline routine in its header file, for example, I believe it should be fully inlined using the pattern above.

-Brad

Thanks. I did not RTFM properly. Once I used static in the C code, it worked. I do not quite understand what a static inline piece of C is, but it delivers results and I assume it is inline'd and has no subroutine jump overhead. I still cannot figure out how to read the assembler produced by the Chapel compiler. Before I go playing around a

c_float

a C type, the equivalent of a real(32), for use in a C program or is it a Chapel type that matches a float for use in a Chapel program. The manual infers the former but I get errors when I try and use them. Is there some include file I am missing in the chunk of C code?

Thanks - Damian

c_float is available for use in Chapel code. The static in the C code just means it's only for use within a C file (which is admittedly a bit weird since you are using it within Chapel code) but it's relatively normal in C code for static inline to go together.

I still cannot figure out how to read the assembler produced by the Chapel compiler.

Right, we have this issue to talk about that Assembler Output of individual code chunks - Desirable / Low Priority · Issue #15043 · chapel-lang/chapel · GitHub .

Thanks for that insight.

I have been using inline routines for 35 years in C++ (albeit far less in C) but I have never combined that with static. Anyway, let's discuss Chapel and not my seemingly poor C knowledge. Why wont it compile until I put static in there? Just curious? My code is

extern
{
        #include        <stdio.h>
        #include        <math.h>

        static int turkey = 7;

        int qfred(int j) { return turkey; };

        double zround(double x) { return round(x); }

        static inline float roundevenf (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $8, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }

        static inline float roundbelowf (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $9, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }

        static inline float roundabovef (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $10, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }
}
extern
{
        #include        <stdio.h>
        #include        <math.h>

        static int turkey = 7;

        int qfred(int j) { return turkey; };

        double zround(double x) { return round(x); }

        static inline float roundevenf (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $8, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }

        static inline float roundbelowf (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $9, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }

        static inline float roundabovef (const float x)
        {
          float r;

          __asm__ __volatile__ ("roundss $10, %1, %0" : "=x" (r) : "xm" (x));

          return r;
        }
}

proc main
{
        const x = t:real(32);

        writeln("away round of ", t, " is ", zround(t));
        writeln("even round of ", t, " is ", roundevenf(x));
        writeln("ceil x .... ", t, " is ", roundabovef(x));
        writeln("floor x ... ", t, " is ", roundbelowf(x));
}

Thanks.

I will get back to that Gihub issue later in the week on Github (rather than here in Discourse).

(This post is my understanding -- I didn't try to compile these)

You'll get an error about needing a prototype if you don't have static. You can add static like this:

static int qfred(int j) { return turkey; };

or you can add a prototype like this:

int qfred(int j);
int qfred(int j) { return turkey; };

but the first of these communicates to the C compiler that it need not consider that the function will be called outside of the compilation unit. I think our interop documentation probably could be improved to clarify that it works as if these extern blocks end up in the same compilation unit as the Chapel module that they are contained within.

Thanks. Now Vass's email makes more sense. But I cannot understand why you need a prototype as well as the definition. That seems redundant. But I am sure I will learn why soon.

Anyway, I might ask a few more dumb questions later in the week and once I get my head around it, I might make some suggestions/enhancements regarding the said documentation. Having Discourse+Github means that the odd hole in the documentation gets plugged pretty quickly. The only hiccup is the weekend. And of course, for some us who have a separate day job, that is when we work on our Chapel research.

thanks for the help V+B+M

I cannot understand why you need a prototype as well as the definition.

Or maybe it is called "declaration" in addition to the definition. Frankly, I do not understand either and am not hoping to learn any time soon—this warning/error has been around for a long time so it is more of "a fact of life" to me.

My best guess is that you are supposed to use a given function in one of two ways. (A) locally to the current file, in which case you should mark it "static". (B) across compilation units, in which case you should put its declaration in a header file that will be used across multiple compilations. This declaration would be in addition to the definition that goes into a .c file. The warning shows up when your function does not fit into (A) or (B).

1 Like

My sense is similar to Vass's, with a dash of "C wanting to support single-pass, top-to-bottom compilation" mixed in.

-Brad

Thanks. All a lot clearer now. What was great was that once I got the definition/declaration/whatever right, it all just worked as it was designed to do. Thanks for the help. I will look at the description and see it I can make some suggestions on changes to wording that would have made things clearer to me.

-- Damian

Thank you, Damian.

So we have a C interoperability section in the Primer and a more comprehensive one in the Tech Notes that need to be addressed. Anywhere else? Where is the master of those pages. Is it chpldoc and if so, where do I find the latest documentation on that tool? Can I correct the English please while I am there?

-- Damian

I cannot understand why you need a prototype as well as the definition.

They're both needed for non-static functions because of the clang flag -Wmissing-prototypes, which comes from compiler/llvm/clangUtil.cpp runClang() clang_warn[]. So clang is warning about it because it's been asked to, and turning that warning into an error because -Werror tells it to.

With the -Wmissing-prototypes removed from clang_warn[] the example turkey code above doesn't hit that warning/error (though it does hit others).

Since it hasn't been spelled out here, the warnings/errors I'm talking about are the ones of the form

In file included from <built-in>:2:
foo.chpl:8:13: error: no previous prototype for function 'qfred' [-Werror,-Wmissing-prototypes]
        int qfred(int j) { return turkey; };
            ^
foo.chpl:8:9: note: declare 'static' if the function is not intended to be used outside of this translation unit
        int qfred(int j) { return turkey; };
        ^
        static 

There is surely a terminology question here. GCC would call it "error: no previous declaration" -Werror=missing-declarations.

The problem is worse than that. Without static, you get the error, i.e. not a warning,

/tmp/chpl-damianm.deleteme-qlPYgQ/chpl__module.o: In function `chpl_user_main':
root:(.text+0x7f70f): undefined reference to `roundabovef'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
error: Make Binary - Linking

There is no executable produced.

@damianmoz here are some doc pages that I found (including your finds) that relate to C interop:
https://chapel-lang.org/docs/main/language/spec/interoperability.html
https://chapel-lang.org/docs/main/modules/standard/CTypes.html
https://chapel-lang.org/docs/main/primers/interopWithC.html
https://chapel-lang.org/docs/main/technotes/extern.html
https://chapel-lang.org/docs/main/technotes/libraries.html

Their sources are here:

$CHPL_HOME/doc/rst/language/spec/interoperability.rst
$CHPL_HOME/modules/standard/CTypes.chpl
$CHPL_HOME/test/release/examples/primers/interopWithC.chpl
$CHPL_HOME/doc/rst/technotes/extern.rst
$CHPL_HOME/doc/rst/technotes/libraries.rst

Chpldoc is used to generate module documentation, CTypes in this case. See chpldoc — Chapel Documentation 1.29

To generate online documentation, go to $CHPL_HOME and run make docs. This will run chpldoc as well. As it will tell you at the end, it will place the webpages in $CHPL_HOME/doc/html.

Yes, feel free to correct the English and whatever other glitches you come across.

Looking at

https://chapel-lang.org/docs/main/modules/standard/CTypes.html

This looks pretty clear/consistent/complete except that the definition of c_uint defines this as

The Chapel type corresponding to the C ‘uint’ type

For consistency with every other definition of the form c_u..., shouldn't this be

The Chapel type corresponding to the C ‘unsigned int’ type

My 2c.

From where can I grab the 1.29 distribution. I figure hacking even 1.28.0 docs is not productive.

Thanks - Damian

Sorry. I meant the pre-release because that is what comes up when you go to some of those URLs. I should have been more precise.