compiler warnings

93 views
Skip to first unread message

Mike Jones

unread,
Oct 29, 2015, 9:58:05 AM10/29/15
to ats-lang-users
My application has lots of warnings like shown below. Should I be trying to remove these or are they typical of ATS application and to be ignored? Are there some standard compiler flags that would turn off things that should be ignored?

To take a particular case, the first error about const, I have the following C declarations:

uint8_t packetIn[127];
const uint8_t *packetInCount      = packetIn;
const uint8_t *packetInHeader     = packetIn + 1;

The idea being there are some pointers into a block of data that never change.

And, I assume arrayref does some kind of implicit cast and then there is a warning. Note, I am not a C compiler expert, so I'm doing some guessing here.

DATS/frames_dats.c: In function ‘process_smbus_frame_command_138’:
DATS/frames_dats.c:9714:1: warning: passing argument 1 of ‘ATSLIB_056_prelude__arrayref_get_at_gint__20__5’ discards ‘const’ qualifier from pointer target type [enabled by default]
 ATSINSmove(tmp356, ATSLIB_056_prelude__arrayref_get_at_gint__20__5(ATSPMVextval(packetInContents), ATSPMVi0nt(0))) ;
 ^
DATS/frames_dats.c:861:1: note: expected ‘atstype_ptrk’ but argument is of type ‘const uint8_t *’
 ATSLIB_056_prelude__arrayref_get_at_gint__20__5(atstkind_type(atstype_ptrk), atstkind_t0ype(atstype_int)) ;
 ^
patsopt -o DATS/main_dats.c.tmp -d DATS/main.dats
mv DATS/main_dats.c.tmp DATS/main_dats.c
avr-gcc -g -Wall -O2 -mmcu=atmega328p -DF_CPU=16000000UL  -std=c99 -D_XOPEN_SOURCE -D_ATSTYPE_VAR_SIZE_=0X000F -D_ATS_CCOMP_EXCEPTION_NONE_ -D_ATS_CCOMP_RUNTIME_NONE_ -D_ATS_CCOMP_PRELUDE_NONE_ -D_ATS_CCOMP_PRELUDE_USER_=\"/home/mike/linti/libs/arduino-ats/avr_prelude/kernel_prelude.cats\" -Wno-unused-variable -Wno-unused-label -Wno-unused-but-set-variable -I. -I/opt/ATS/ATS2-Postiats-0.2.4 -I/opt/ATS/ATS2-Postiats-0.2.4/ccomp/runtime -I/home/mike/linti/libs/arduino-ats/_arduino -I/home/mike/linti/libs/arduino-ats/_dummy -I/home/mike/linti/libs/arduino-ats -c -o DATS/main_dats.o DATS/main_dats.c
DATS/main_dats.c:333:1: warning: ‘output_high_1’ defined but not used [-Wunused-function]
 output_high_1(atstkind_t0ype(atstype_int) arg0)
 ^
DATS/main_dats.c:363:1: warning: ‘input_2’ defined but not used [-Wunused-function]
 input_2(atstkind_t0ype(atstype_int) arg0)



gmhwxi

unread,
Oct 29, 2015, 11:07:48 AM10/29/15
to ats-lang-users
You should be able to find proper compiler options to suppress such warning messages.

But there are a few programming style issues that I'd like to mention here.

Try to use templates extensively. Say you have foo1.dats, foo2.dats and main.dats.
Usually, the idea is to have only templates inside foo1.dats and foo2.dats. In main.dats,
you have

staload "foo1.dats"
staload "foo2.dats"

Think of it this way: foo1.dats and foo2.dats are here to generate C code used in main.dats.

If there are functions in foo1.dats that are not templates, you can add the following code in
main.dats:

local
#include "foo1.dats"
in (*nothing*) end

The idea is to generate only one file containing all the C code you want. In this way, gcc/clang
can optimize to the fullest extent when compiling the generated C code.


I will talk about the 'const' issue in a separate message.

gmhwxi

unread,
Oct 29, 2015, 1:58:14 PM10/29/15
to ats-lang-users

The 'const' qualifier in C has no counterpart in ATS
for the moment.

In any case, exporting global variables in C for use in ATS
can and should probably be avoided. For instance, you example
may be done as follows:

%{^
//

uint8_t packetIn[127];
const uint8_t *packetInCount      = packetIn;
const uint8_t *packetInHeader     = packetIn + 1;
//
#define packetInCount_get() (packetInCount[0])
#define packetInHeader_get_at(i) (packetInHeader[i])
//
%}

extern
fun packetInCount_get(): uint8 = "mac#"
extern
fun packetInHeader_get_at(natLt(126)): uint8 = "mac#"


On Thursday, October 29, 2015 at 9:58:05 AM UTC-4, Mike Jones wrote:

Barry Schwartz

unread,
Oct 29, 2015, 7:19:21 PM10/29/15
to ats-lan...@googlegroups.com
gmhwxi <gmh...@gmail.com> skribis:
> The 'const' qualifier in C has no counterpart in ATS
> for the moment.
>
> In any case, exporting global variables in C for use in ATS
> can and should probably be avoided. For instance, you example
> may be done as follows:

I’ve gotten around the compiler warning problem _in foreign function
calls_ by simply declaring an $extype. :)

Can be a problem with C functions that return values by reference.

Barry Schwartz

unread,
Oct 29, 2015, 7:37:30 PM10/29/15
to ats-lan...@googlegroups.com
This actually makes no sense. I forget what caused the problem. :)

Anyway, I used an $extype"const whatever" and some casts.

Mike Jones

unread,
Oct 30, 2015, 9:13:02 AM10/30/15
to ats-lang-users
I see the point about full optimization, but now I have to consider that if I break a large application into multiple files, I have dependencies like:

A depends B == a -> B

so

C -> G
D -> G
M -> C && D

So there is then no way to get all the templates to expand in M (Main)

The same would happen when using a library in prelude or contrib in a multiple application.

Given that, if all functions in G are templates, and all functions in C and D are templates, will all the template expansions end up in M like you recommend?

If so, I can have my cake and eat it :-)


gmhwxi

unread,
Oct 30, 2015, 9:19:22 AM10/30/15
to ats-lang-users

>>Given that, if all functions in G are templates, and all functions in C and D are templates, will all the template expansions end up in M like you recommend?

Yes, all the template expansions end up in M as can be expected.

>>If so, I can have my cake and eat it :-)

Yes, both :)

By the way, the 'and' in the above sentence is linear (as in linear logic).

gmhwxi

unread,
Oct 30, 2015, 9:21:50 AM10/30/15
to ats-lang-users
I just want to add that you can actually have a situation where

C depends on D and D depends on C.

Mutual dependency is not a problem as far as template instantiation is of the concern.

Mike Jones

unread,
Oct 30, 2015, 5:12:31 PM10/30/15
to ats-lang-users
And if you use templates everywhere, it global optimizes, but the image is bigger due to inlining. Correct?

Hongwei Xi

unread,
Oct 30, 2015, 5:28:03 PM10/30/15
to ats-lan...@googlegroups.com
That is correct.


On Fri, Oct 30, 2015 at 5:12 PM, Mike Jones <proc...@gmail.com> wrote:
And if you use templates everywhere, it global optimizes, but the image is bigger due to inlining. Correct?

--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/400a6d0b-7c22-4baf-8c15-d7de7de21f36%40googlegroups.com.

Hongwei Xi

unread,
Oct 30, 2015, 5:39:01 PM10/30/15
to ats-lan...@googlegroups.com
As a programmer, you can have precise control over template instantiation.

Of course, to stop inlining, you need to have control over the C compiler you use as well.

Mike Jones

unread,
Oct 30, 2015, 7:26:51 PM10/30/15
to ats-lang-users
Ok, so you are saying using templates enables inlining, but does not enforce it. You can always find a compiler setting to prevent it.

I am basing this on a comment in another thread where I had a function like u73 that clamped a value, and you suggested templates so that it would be inlined.

Barry Schwartz

unread,
Oct 30, 2015, 7:46:41 PM10/30/15
to ats-lan...@googlegroups.com
Mike Jones <proc...@gmail.com> skribis:
> Ok, so you are saying using templates enables inlining, but does not
> enforce it. You can always find a compiler setting to prevent it.

Indeed, inlining by the C compiler is such a big boost in the
performance of ATS code (and I think unlikely to be a serious
hindrance to debugging) that I am having my autoconf scripts turn on
GCC’s inlining optimizations aggressively when compiling ATS code,
even when other optimizations are turned off by the user. (I usually
use -Og for my own code. It’s not very aggressive.)

gmhwxi

unread,
Oct 30, 2015, 7:59:18 PM10/30/15
to ats-lang-users

One consequence of template instantiation is bringing the definition of a template to the place where
the template is used. In this way, it creates an opportunity of the C compiler to actually perform inlining.

A non-template function is still while a function template is mobile (in the sense that its code gets moved
around by the ATS compiler).

gmhwxi

unread,
Oct 30, 2015, 8:06:24 PM10/30/15
to ats-lang-users

Yes! ATS code would run rather slowly if it is not eventually being
optimized aggressively by C. Patsopt, the ATS compiler, creates
opportunities for the subsequently called C compiler but it itself does
not actually perform any optimizations (except for tail-call optimization,
which is indispensable for a language that strongly advocates the use
of tail-recursion to replace loops).

Barry Schwartz

unread,
Oct 30, 2015, 8:27:21 PM10/30/15
to ats-lan...@googlegroups.com
gmhwxi <gmh...@gmail.com> skribis:
> Yes! ATS code would run rather slowly if it is not eventually being
> optimized aggressively by C. Patsopt, the ATS compiler, creates
> opportunities for the subsequently called C compiler but it itself does
> not actually perform any optimizations (except for tail-call optimization,
> which is indispensable for a language that strongly advocates the use
> of tail-recursion to replace loops).

Indeed. A single ATS function shows up as multiple C functions. Try
passing --gline to patsopt and compiling the C without optimization,
then (one way or another) load an execution state into gdb.

gmhwxi

unread,
Nov 1, 2015, 1:46:44 PM11/1/15
to ats-lang-users

It should probably be emphasized that facilitating inlining is just
a by-product of templates. Moving a template around allows the template
to be re-interpreted in different contexts, and re-interpretation is really the
key to code reuse.

Mike Jones

unread,
Nov 1, 2015, 7:41:21 PM11/1/15
to ats-lang-users
Here is a metric from my code:

The original code used 13K of program space. By using templates everywhere, it increased size by 37% to 18K.

Given the Atmega328 has a 32K program space, this is pretty painful.

If functions in ATS require 2-3 C functions this may become a practical limit to use of ATS in very small embedded systems. So while the statics go away, the this overhead does not.

The non-template version is not limited by code speed, but by IO, most of the time. But different parts of the code have different needs. Given that some functions will be shared between time critical and space critical parts of the code, what is needed is a way to annotate the code to tell the ATS when to instantiate a template, and when to use a shared function. Thus, being able to use templates in time critical areas, and not in others

Given the above, is there a way to put a wrapper around each template such that when used, it uses a shared function, but does not add even more C function call overhead? The idea being a template is instantiated once as a shared function, with no additional overhead in the generated code, or at least a very small overhead like one pointer dereference, etc.

gmhwxi

unread,
Nov 1, 2015, 9:18:16 PM11/1/15
to ats-lang-users

Here is some code showing how to control template instantiation.

Try

patscc -ccats foo.dats
patscc -DATS FOO_TEMPLATE_NONE foo.dats

And you will see the difference.

(* ****** ****** *)
//
extern
fun
{} foo(int): void
//
extern
fun foo_
: $d2ctype(foo<>)
implement foo_
(x) = foo(x)
//
#ifdef
FOO_TEMPLATE_NONE
#define foo foo_
#endif
//
val
() = foo(0)
val
() = foo(1)
//
(* ****** ****** *)

gmhwxi

unread,
Nov 1, 2015, 9:46:56 PM11/1/15
to ats-lang-users

In case you want to go the other direction, that is, downsizing your code,
you can make use of higher-order functions in ATS in the absence of dynamic
memory allocation. There is an example in the following paper showing how
this is actually done:

http://www.metasepi.org/doc/metasepi-icfp2015-arduino-ats.pdf


On Sunday, November 1, 2015 at 7:41:21 PM UTC-5, Mike Jones wrote:

Mike Jones

unread,
Nov 1, 2015, 10:01:52 PM11/1/15
to ats-lang-users
A nice piece of magic.

Mike Jones

unread,
Nov 1, 2015, 10:20:10 PM11/1/15
to ats-lang-users
Is the resulting object code similar in size and performance to writing a tail recursive loop? The implementation in the prelude looks like it might have more overhead in terms of generated code, etc.

gmhwxi

unread,
Nov 1, 2015, 11:12:21 PM11/1/15
to ats-lang-users

The hope is that the resulting code is smaller in size. It may be slower but not necessarily.

In this particular case, the loop is just too simple. But it should not be hard to imagine a scenario
where using a higher-order function allows the code size to go down.

Mike Jones

unread,
Nov 2, 2015, 12:23:56 AM11/2/15
to ats-lang-users
ATS does not allow currying, correct? 

The most you can do is capture a value from the outer context I think. But if a lambda does capture a value, can you return the lambda from a function without boxing/malloc? That would allow making a creator function that returns curried functions. Even better if you can return them in a datatype.

The example I am thinking of is opening a handle, and hiding it in a data type of lambdas, where the datatype is like an interface, and an open function returns the datatype with the handle hidden. 

This would reuse context and make the code faster because the handle does not need to be passed on every function call. In a loop context, the lambda could be used with a map, fold, etc.

Barry Schwartz

unread,
Nov 2, 2015, 1:00:56 AM11/2/15
to ats-lan...@googlegroups.com
Mike Jones <proc...@gmail.com> skribis:
> ATS does not allow currying, correct?

Not allowing currying (which would be hard to do) is not the same as
not encouraging currying when more efficient notations are
available. :) Something I had to adapt myself to mentally when moving
from OCaml to Scheme (before learning any ATS).

SML conventions, unlike those of OCaml, favor multiple arguments over
currying, I have learned since, even though (ignoring ‘practical’
factors) it is completely arbitrary to prefer one system over another.

Just my useless two cents. :)

Hongwei Xi

unread,
Nov 2, 2015, 1:01:04 AM11/2/15
to ats-lan...@googlegroups.com

ATS supports currying. It is just that currying is of little use in ATS as
ATS already supports functions of multiple arguments.

Instead of writing 'foo(x)(y)', you write foo(x, y); so 'foo(x)' is lam(x) => foo(x, y).

Returning a closure-function without malloc means the caller needs to provide memory
for storing the returned closure-function; often the memory is in the frame of the caller.


>>The example I am thinking of is opening a handle, and hiding it in a data type of lambdas, where the datatype is like an interface, and an open function returns the datatype with the handle hidden.

Using closure to hide information is rather awkward:

http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/HTMLTOC/x1509.html

I would suggest using abstract types to hide information. If you can provide some pseudo code, I will have
a better idea about what you said above.


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.

Mike Jones

unread,
Nov 2, 2015, 9:07:31 AM11/2/15
to ats-lang-users
wrt Haskell

See this for background:


A specific example sets up a data type as an interface:

data SMBus = SMBus {
  sendByte :: Address -> Command -> IO (Either SMBusStatus ()),
  writeByte :: Address -> Command -> Word8 -> IO (Either SMBusStatus ()),
  readByte :: Address -> Command -> IO (Either SMBusStatus Word8),
  writeWord :: Address -> Command -> Word16 -> IO (Either SMBusStatus ()),
  readWord :: Address -> Command -> IO (Either SMBusStatus Word16),
  readBlock :: Address -> Command -> Size -> IO (Either SMBusStatus [Char]),
  readString :: Address -> Command -> Size -> IO (Either SMBusStatus String),
  probe :: () -> IO (Maybe [Address]),
  close :: () -> IO (),
}

And there are multiple instances with one partial example here:

smbusAardvark = do
  devices <- devices -- From USB API
  handle <- A.openDevice (head devices) -- Don't get hung up on how dangerous this is to assume the first device, yes it is
  return $ SMBus { 
    sendByte = \address command -> do
      (status, numWritten) <- i2cWriteExt (fromIntegral handle) (fromIntegral address) I2cNoFlags [(fromIntegral command)] 1
      ss <- toStatus status
      if ss == SMBusOk then return $ Right () else return $ Left ss,

And calling code creates an instance for a particular hardware interface, such that it returns a SMBus datatype with the handle and operations hidden behind it.

The goal is to instance whatever hardware is being used.

smbus <- smbusAardvark

runI2cTest :: SMBus -> IO ()
runI2cTest smbus@SMBus{..} = do

    s <- writeByte 0x30 0x00 0x00


In my current application context, it might mean the code listens to some interface, then makes decisions about what interface to frame over, then instance an interface for it. This means all code that consumes the interface is the same.

That said, because it is embedded, I would like to avoid boxed types. Passing in memory from an outer frame, such that it remains on the stack might be ok, but it would be better to be static. One issue is that depending on the instance chosen, the memory size changes. So if the choice was to preallocate space with C, it would be nice to have a way for the code to statically calculate a maximum so that there are no accidental overflows, or to specify its size, and use statics to prevent code from instantiating something bigger than what was pre-allocated.

RecordWildCards are not necessary, they just pretty up the code so it reads out loud better.

Hongwei Xi

unread,
Nov 2, 2015, 10:01:47 AM11/2/15
to ats-lan...@googlegroups.com

I think I completely understand what you want here.

In ATS, this sort thing can be done based templates, requiring no use of boxed types.

abstype devtype // for SMBus

extern
fun{devtype}
sendByte : (Address, Command, err: &int >> _): SMBusStatus

implement
sendByte<SMBus> (A, C, err) = ...



--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.

Mike Jones

unread,
Nov 2, 2015, 10:14:57 AM11/2/15
to ats-lang-users
So, I assume there will be one implement statement for each bus type? If not, then the the structure of the code has to be the same for all passed in types, like the way templates work in C++ where the passed in type, say int or double, has operators that work for both. In the SMBus case, the interfaces to the lower SMBus layer, say Aardvark vs. other hardware, may have significant differences so there needs to be one implementation for each one.

The next issue is how to call. The Haskell solution has one statement that picks the type of hardware, then the code is the same. In the template case, how do you do that?

If the function has to be called as sendByte<SMBus>(0x30, 0x01, err) then there will be conditionals everywhere, because the call has to give the type.

Is there a simple way to pick the instance, and call as sendByte(0x30, 0x01, err)?

The final problem is the instance has to capture a handle, which is returned from an IO call. Templates are instantiated at compile time, not run time, so I don't think they can capture the value. Which leads me to believe I will still have to pass a moniker to every call.

 

Mike Jones

unread,
Nov 2, 2015, 10:17:28 AM11/2/15
to ats-lang-users
I think that ultimately, a closure is required to capture a moniker used by an implementation of an interface, to do what the Haskell example does.

Hongwei Xi

unread,
Nov 2, 2015, 11:22:52 AM11/2/15
to ats-lan...@googlegroups.com
Well, the point of using a template-based approach is to obviate the need
for building closures. If closures had to be built at run-time, then I would use
higher-order functions (instead of templates).

On Mon, Nov 2, 2015 at 10:17 AM, Mike Jones <proc...@gmail.com> wrote:
I think that ultimately, a closure is required to capture a moniker used by an implementation of an interface, to do what the Haskell example does.

--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.

gmhwxi

unread,
Nov 2, 2015, 11:39:02 AM11/2/15
to ats-lang-users
I took another look at your example.

Here is what I would do:

abstype Aardvark
abstype SMBus(a:type) // abstract type for handles

extern
fun{a:type}
sendByte (handle: !SMBus(a), Address, Command, err: &int): SMBusStatus

implement
sendByte<Aardvark> (Handle, Address, Command) = ...

val Handle = SMBus_Aardvark_open(...)

val SMBusStatus = sendByte(Handle, Address, Command, ...)

val ((*closed*)) = SMBus_Aardvark_close(Handle).

gmhwxi

unread,
Nov 2, 2015, 12:48:16 PM11/2/15
to ats-lang-users
>>In my current application context, it might mean the code listens to some interface, then makes decisions about what interface to frame over, then instance an interface for it. This means all code that consumes the interface is the same.

This sounds good but reality may not be so compliant. Often one interface cannot be fit all.
The datatype-based approach (as is shown in your Haskell code) is what I call a 'closed-world' approach,
which you can certainly do in ATS. However, the template-based approach is an "open-world" approach, which
I think is far superior.

On Monday, November 2, 2015 at 9:07:31 AM UTC-5, Mike Jones wrote:
wrt HaskellI

Mike Jones

unread,
Nov 2, 2015, 9:34:10 PM11/2/15
to ats-lang-users
The template approach will allow more or lesser number of functions rather than requiring a fixed interface, with possible throwing of exceptions for the unimplemented. This does have merit, so I will give this a go.

The Haskell approach was in reaction to several attempts that failed in one way or another and this was the best of multiple alternatives. I'm not stuck on it if there is a better approach.

Hongwei Xi

unread,
Nov 2, 2015, 9:47:26 PM11/2/15
to ats-lan...@googlegroups.com
>>with possible throwing of exceptions for the unimplemented.

This happens at compile-time (after typechecking).

Currently, a failed template instantiation results in
a message (issued by the C compiler) that reads like:

<source-code-location> error: ‘PMVtmpltcstmat’ undeclared

On Mon, Nov 2, 2015 at 9:34 PM, Mike Jones <proc...@gmail.com> wrote:
The template approach will allow more or lesser number of functions rather than requiring a fixed interface, with possible throwing of exceptions for the unimplemented. This does have merit, so I will give this a go.

The Haskell approach was in reaction to several attempts that failed in one way or another and this was the best of multiple alternatives. I'm not stuck on it if there is a better approach.

--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
Reply all
Reply to author
Forward
0 new messages