Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.compilers > #1049 > unrolled thread

Implementation dependent behaviour (WAS: Re: Programming language and IDE design)

Started byMartin Ward <martin@gkc.org.uk>
First post2013-11-20 10:29 +0000
Last post2014-01-14 14:16 +0000
Articles 12 — 6 participants

Back to article view | Back to comp.compilers


Contents

  Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Martin Ward <martin@gkc.org.uk> - 2013-11-20 10:29 +0000
    Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Joshua Cranmer 🐧 <Pidgeot18@verizon.net> - 2013-11-23 01:06 -0600
      Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2013-11-24 21:51 +0000
      Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Martin Ward <martin@gkc.org.uk> - 2014-01-06 19:23 +0000
    Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Kaz Kylheku <kaz@kylheku.com> - 2013-12-17 23:07 +0000
      Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Martin Ward <martin@gkc.org.uk> - 2014-01-06 19:32 +0000
    Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Ivan Godard <ivan@ootbcomp.com> - 2014-01-08 09:02 -0800
      Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Kaz Kylheku <kaz@kylheku.com> - 2014-01-08 18:21 +0000
        Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Ivan Godard <ivan@ootbcomp.com> - 2014-01-10 09:11 -0800
        Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2014-01-10 23:08 +0000
          Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) Ivan Godard <ivan@ootbcomp.com> - 2014-01-13 12:47 -0800
          Re: Implementation dependent behaviour (WAS: Re: Programming language and IDE design) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2014-01-14 14:16 +0000

#1049 — Implementation dependent behaviour (WAS: Re: Programming language and IDE design)

FromMartin Ward <martin@gkc.org.uk>
Date2013-11-20 10:29 +0000
SubjectImplementation dependent behaviour (WAS: Re: Programming language and IDE design)
Message-ID<13-11-025@comp.compilers>
On Tuesday 19 Nov 2013 at 00:02, George Neuner <gneuner2@comcast.net> wrote:
> I simply said that your assertion:
>
>   (2) Absolutely no behaviour should be "implementation dependent"
>       or "undefined". Every syntactically valid program should have
>       a single semantically valid meaning (even if that meaning
>       is "halt with an error message").
>
> is not plausible.  I did not offer an alternative.

Your only counter-example is "execution time": but programming
language specification documents have never included execution time as
part of the specification of a language (whether defined as
"implementation dependent" or otherwise).  Execution time is not part
of the specification of the language.  Neither have they specified the
power consumption or temperature of the CPU: although these properties
can be just as important as execution time for certain applications!
They are also not considered to be part of the definition of the
language.

Apart from these cases: do you still disagree with the assertion?
Is there any (semantic) behaviour which should be left as
"implementation dependent"?

The usual reason for "implementation dependent" behaviour is that code
compiles to one behaviour more efficiently one one CPU, and to some
other behaviour more efficiently on some other CPU.  So, rather than
"penalise" one CPU, the language designers give way to lobbying from
the CPU manufacturers and allow either behaviour (or any behaviour).
The result:

(1) If you want to be sure of the behaviour of your program,
you have to avoid the "implementation dependent" features:
so now your program executes inefficiently on *all* CPUs; OR

(2) If you happen to know that your program will run on a certain CPU,
and efficiency is important to you, then you may just go ahead
and rely on the actual behaviour of your program when it is technically
"undefined".  (Unless you are a language semantics expert who
spends your spare time reading language specification documents,
you may well be doing this already without realising it!)
Now, your program is not portable: it may break as soon as you move
it to another CPU. Even worse: it may break with the next update
of the compiler! The compiler writers have no compulsion
to preserve the old behaviour when the language definition states
that it is "undefined".

On the other hand: suppose the language designers pick on a certain
behaviour and define *that* as the exact semantics of the programming
construct in question. The result:

(1) Compilers for CPUs on which the selected choice is the "native" behaviour
can generate more efficient code. Compilers for other CPUs may have
to generate extra code to implement this feature. So certain programs
will run faster on some CPUs than on others. But the programs
will at least produce identical outputs on *all* CPUs.
(Note: if you don't care what output your program produces,
as long as it produces it quickly: well, incorrect output can be generated
in no time at all!)

(2) CPU designers may choose to implement that behaviour in hardware
on the next iteration of the CPU. Now the programs run fast on *all* CPUs.

Everybody wins.

--
			Martin

Dr Martin Ward STRL Principal Lecturer and Reader in Software Engineering
martin@gkc.org.uk  http://www.cse.dmu.ac.uk/~mward/  Erdos number: 4
G.K.Chesterton web site: http://www.cse.dmu.ac.uk/~mward/gkc/
Mirrors:  http://www.gkc.org.uk  and  http://www.gkc.org.uk/gkc
[In my experience, if you overspecify the semantics of a language, you end up
simulating the warts of whatever CPU happened to be familiar to the language's
designer on every other CPU.  You also lose most optimizations if you try to
specify the contents of storage as seen from a routine that handles arithmetic
exceptions. -John]

[toc] | [next] | [standalone]


#1052

FromJoshua Cranmer 🐧 <Pidgeot18@verizon.net>
Date2013-11-23 01:06 -0600
Message-ID<13-11-028@comp.compilers>
In reply to#1049
On 11/20/2013 4:29 AM, Martin Ward wrote:
> Apart from these cases: do you still disagree with the assertion?
> Is there any (semantic) behaviour which should be left as
> "implementation dependent"?

1. The size of a pointer variable.
2. The size of an integer variable intended to be the same size as a
pointer.
3. The reinterpretation of a function pointer as a data pointer.
4. The accuracy of non-fundamental floating point computations (e.g.,
exp). I think it would be reasonable to constrain them, though.
5. The contents of a memory location in the presence of a data race.
6. The correctness of floating point numbers in denormalized situations.
(I know NVIDIA GPUs used to not do denormalized correctly, and I think
some SSE implementations don't either).
7. The order, size, etc. of functions (this is observable if you can
take the address of a function and compare or subtract pointers).
8. The order of variables either in global memory, heap-allocated
memory, or stack-allocated memory.
9. If you allow type punning, semantics that would require a specific
endianness of types.

> The usual reason for "implementation dependent" behaviour is that code
> compiles to one behaviour more efficiently one one CPU, and to some
> other behaviour more efficiently on some other CPU.  So, rather than
> "penalise" one CPU, the language designers give way to lobbying from
> the CPU manufacturers and allow either behaviour (or any behaviour).
> The result:

The worst impacts of undefined or implementation-defined behavior are
not because the underlying hardware is unreliable, it's because the
optimizers gleefully trash the intent of your code in an attempt to make
it faster. Strict aliasing in C is perhaps the worst offender in this
regard.


> On the other hand: suppose the language designers pick on a certain
> behaviour and define *that* as the exact semantics of the programming
> construct in question. The result:

Or, you can get extremely inefficient computation on all CPUs. Suppose
you had a language that required you to trap on arithmetic overflows,
and that required you to trap at a very specific place in computation.
This language means you have to prove range analysis on all variables to
prove that they cannot overflow before you can do any code motion or
code elimination--effectively negating the most powerful optimizations a
compiler can do.

If you allow a little bit of undefined behavior, if you let compilers
choose to trap before the value would be observed as overflowed, you
again allow code elimination and code motion without the range analysis,
while achieving very nearly the same result.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

[toc] | [prev] | [next] | [standalone]


#1054

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2013-11-24 21:51 +0000
Message-ID<13-11-030@comp.compilers>
In reply to#1052
Joshua Cranmer ? <Pidgeot18@verizon.net> wrote:

(snip, someone wrote)

>> On the other hand: suppose the language designers pick on a certain
>> behaviour and define *that* as the exact semantics of the programming
>> construct in question. The result:

> Or, you can get extremely inefficient computation on all CPUs. Suppose
> you had a language that required you to trap on arithmetic overflows,
> and that required you to trap at a very specific place in computation.

In some cases, the hardware is designed to satisfy language
requirements.

> This language means you have to prove range analysis on all variables to
> prove that they cannot overflow before you can do any code motion or
> code elimination--effectively negating the most powerful optimizations a
> compiler can do.

I believe that this is at least slightly true for Java. The exception
model restricts some code movements that other compilers might do.

> If you allow a little bit of undefined behavior, if you let compilers
> choose to trap before the value would be observed as overflowed, you
> again allow code elimination and code motion without the range analysis,
> while achieving very nearly the same result.

I suppose you missed the days of imprecise interrupts. The IBM 360/91
does out of order processing, including out of order retire. In the case
of an exception, it has to complete processing of all instructions in
the pipeline, at least those logically before the last retired
instruction.

Even more, there is "multiple imprecise interrupt" when more exceptions
occur while flushing the pipeline. In most cases you don't have the
address of the exception.  But in many cases, people would rather
have the speed.

Most imprecise interrupts went away with virtual storage, as you need to
at least do things right in the case of a page fault.

-- glen

[toc] | [prev] | [next] | [standalone]


#1070

FromMartin Ward <martin@gkc.org.uk>
Date2014-01-06 19:23 +0000
Message-ID<14-01-003@comp.compilers>
In reply to#1052
On Saturday 23 Nov 2013 at 07:06, Joshua Cranmer p' <Pidgeot18@verizon.net>
wrote:
> 1. The size of a pointer variable.
> 2. The size of an integer variable intended to be the same size as a
> pointer.
> 3. The reinterpretation of a function pointer as a data pointer.

One purpose of a high-level language is to abstract away from the
low-level details of the machine. For example, the same source code
should work on both big-endian and little-endian machines. Similarly,
high level code should not depend on the size of a pointer.
Overwriting code with data should simply not be possible (with the
possible exception of a JIT compiler).  How many security holes are
caused by buffer overflows which allow a malicious user to overwrite
code or execute data?

A pointer is the data equivalent of a goto: using pointers one can
emulate any complex data structure (lists, trees, graphs etc.)  just
as using a (conditional) goto one can emulate any control structure.
But it has long been recognised that having a suitable rich set of
control structures and eliminating gotos makes for better code.

> 4. The accuracy of non-fundamental floating point computations (e.g.,
> exp). I think it would be reasonable to constrain them, though.

I think you will find that most numerical analysts would disagree: the
whole purpose of the IEEE floating point standard is to eliminate this
class of implementation defined behaviour.

Suppose I update my compiler to the latest version, run my regression
tests and get different results. Is there a bug in the compiler? A bug
in my code?  Hardware failure? Or is it just that the compiler writers
decided to change some random implementation dependent behaviour
(which I might not even be aware of)? Detecting the possibility of
such behaviour in my program might be a non-computable problem: so I
cannot even complain that the compiler gave no warning. The real
problem is with the language definition: which allowed implementation
dependent behaviour in the first place.

> 5. The contents of a memory location in the presence of a data race.
> 6. The correctness of floating point numbers in denormalized situations.
> 7. The order, size, etc. of functions (this is observable if you can
> take the address of a function and compare or subtract pointers).

You can also write self-modifying code: copy the code for function A
over the code for function B. Next time function B is called, the code
for function A gets executed. I would definitely regard self-modifying code
as an undesirable feature for any programming language.

> 8. The order of variables either in global memory, heap-allocated
> memory, or stack-allocated memory.
> 9. If you allow type punning, semantics that would require a specific
> endianness of types.

See above.

> The worst impacts of undefined or implementation-defined behavior are
> not because the underlying hardware is unreliable, it's because the
> optimizers gleefully trash the intent of your code in an attempt to make
> it faster. Strict aliasing in C is perhaps the worst offender in this
> regard.

Designing the language to prevent all aliasing allows all the optimisations
to take place without breaking any code.

> Or, you can get extremely inefficient computation on all CPUs. Suppose
> you had a language that required you to trap on arithmetic overflows,
> and that required you to trap at a very specific place in computation.
> This language means you have to prove range analysis on all variables to
> prove that they cannot overflow before you can do any code motion or
> code elimination--effectively negating the most powerful optimizations a
> compiler can do.
>
> If you allow a little bit of undefined behavior, if you let compilers
> choose to trap before the value would be observed as overflowed, you
> again allow code elimination and code motion without the range analysis,
> while achieving very nearly the same result.

If you eliminate the code, then no trap occurs at all!
If the trap was included specifically to prevent some disaster occurring,
then the disaster would occur. So we have two cases:

(1) The language allows the compiler to trap earlier than necessary,
or even to (effectively) ignore the overflow altogether.
A programmer who *needs* to know if the operation overflowed
then has to write a lot of complex explicit tests (while somehow
trying to stop the compiler from optimising them away)
in *every* place where an overflow test is needed.
In other words: the overflow trap mechanism is useless!

(2) The language enforces the trap to appear exactly when the overflow
occurs in the program as written. A programmer who needs the trap
just enables traps wherever needed: no extra code is required.
A programmer who doesn't care about overflows disables traps
where they are not needed: allowing the compiler to optimise
to its heart's content. The trap mechanism is now useful when needed
and doesn't get in the way when it is not needed.

--
			Martin

Dr Martin Ward STRL Principal Lecturer and Reader in Software Engineering
martin@gkc.org.uk  http://www.cse.dmu.ac.uk/~mward/  Erdos number: 4
G.K.Chesterton web site: http://www.cse.dmu.ac.uk/~mward/gkc/
Mirrors:  http://www.gkc.org.uk  and  http://www.gkc.org.uk/gkc

[toc] | [prev] | [next] | [standalone]


#1064

FromKaz Kylheku <kaz@kylheku.com>
Date2013-12-17 23:07 +0000
Message-ID<13-12-009@comp.compilers>
In reply to#1049
On 2013-11-20, Martin Ward <martin@gkc.org.uk> wrote:
> On Tuesday 19 Nov 2013 at 00:02, George Neuner <gneuner2@comcast.net> wrote:
>> I simply said that your assertion:
>>
>>   (2) Absolutely no behaviour should be "implementation dependent"
>>       or "undefined". Every syntactically valid program should have
>>       a single semantically valid meaning (even if that meaning
>>       is "halt with an error message").
>>
>> is not plausible.  I did not offer an alternative.
>
> Your only counter-example is "execution time": but programming
> language specification documents have never included execution time as
> part of the specification of a language (whether defined as
> "implementation dependent" or otherwise).  Execution time is not part
> of the specification of the language.  Neither have they specified the
> power consumption or temperature of the CPU: although these properties
> can be just as important as execution time for certain applications!
> They are also not considered to be part of the definition of the
> language.

Indeed, if what is defined by the language specification is only what bits are
transformed into what other bits, then there is no reason not to have
a language that has no implementation-dependent behaviors.

There is still the issue of resources: the bits are transformed into other
bits in the requird way on platform A, and on platform B we get "out of memory".
But under no circumstances do we get a different string of bits.

Since highly portable programs that produce bit-exact results on multiple
platforms can be written in languages that have implementation-defined
behaviors, there is no reason why languages cannot themselves provide this,
at least with regard to their internal data structures.

There are practical concerns that stand in the way, at least one of
which is damning of the idea, however.

For instance, if you want bit-exact, platform-independent floating-point, you
may have to do it in software, at least in some implementations. This is going
to suck badly, performance wise. The practical approach is to design
application to have numerical stability in the face of differences in the
floating point system, which can be hard.

Operating system interfacing will be another sticky area, and I don't
just mean in particular things like POSIX signal handling, but even
basics like file handling.

For instance a text file on Windows contains carriage returns, but on
Unix it does not.

We generally *WANT* the text stream library of a programming language
to produce the correct text file representation externally, and
we want to use some platform-independent abstraction internally.

So, it is not sensible to to require a text stream library to be free of
implementation-defined behavior; it inherently embodies
implementation-dependent behavior. It's also not sensible not to have a text
stream library in a programming language. By doing that you can avoid the issue
in the language-definining document, but then programs have to insert carriage
returns explicitly when targetting Windows.

In other words, programs that produce text necessarily produce a different
bit string on different platforms: although those different bit strings
satisfy an equivalence relation based on normalizing to some common text
format: they are equal modulo text stream representation.

Never mind carriage returns; there are also character sets. Freedom from
platform-dependent behavior means that a program cannot print the letter
A. It must output an exact, platform-indepenent bit string, such as one
denoting the number 65, which will look like A on an ASCII or Unicode system.

I think that if you want maximal platform independence in a language, it is
best to focus that in the internal semantics of computation, and not insist on
total platform independence which encompasses the program's interaction with
the environment. There lies folly. (Or Java, but I repeat myself).

[toc] | [prev] | [next] | [standalone]


#1071

FromMartin Ward <martin@gkc.org.uk>
Date2014-01-06 19:32 +0000
Message-ID<14-01-004@comp.compilers>
In reply to#1064
On Tuesday 17 Dec 2013 at 23:07, Kaz Kylheku <kaz@kylheku.com> wrote:
> Since highly portable programs that produce bit-exact results on multiple
> platforms can be written in languages that have implementation-defined
> behaviors, there is no reason why languages cannot themselves provide this,
> at least with regard to their internal data structures.
>
> There are practical concerns that stand in the way, at least one of
> which is damning of the idea, however.

Kaz gives two examples, the first is floating point, which I have
already discussed.

The second is operating system interfacing: specifically text file
representations. Here, the issue is that the program is not operating
on a set of bits but on a higher-level structure called a "text file".
The same program should produce identical text files on any operating
system (with any version of the compiler). The exact representation of
the text file in each operating system is a different issue. This
means than on opening a file the language needs to specify whether
this is a binary or text file (or a file containing some other type of
data) and if it is text.  what encoding to use (ASCII, Unicode, EBCDIC
etc.)

This means that the same program should generate the same text file
(which may well be a different binary file) on an ASCII or EBCDIC
system, for example.
--
			Martin

Dr Martin Ward STRL Principal Lecturer and Reader in Software Engineering
martin@gkc.org.uk  http://www.cse.dmu.ac.uk/~mward/  Erdos number: 4
G.K.Chesterton web site: http://www.cse.dmu.ac.uk/~mward/gkc/
Mirrors:  http://www.gkc.org.uk  and  http://www.gkc.org.uk/gkc

[toc] | [prev] | [next] | [standalone]


#1074

FromIvan Godard <ivan@ootbcomp.com>
Date2014-01-08 09:02 -0800
Message-ID<14-01-007@comp.compilers>
In reply to#1049
On 11/20/2013 2:29 AM, Martin Ward wrote:

<snip>

> (2) CPU designers may choose to implement that behaviour in hardware
> on the next iteration of the CPU. Now the programs run fast on *all*
> CPUs.
>
> Everybody wins.
>
> -- Martin

I am such a CPU designer. We faced the "undefined" issue in our Mill
family of general-purpose CPUs (ootbcomp.com). Not only are languages
under-constraining, they are also sometimes over-constraining: signed
integer overflow is undefined in C but required to wrap in Java.

Our solution was to offer four hardware "overflow-behavior" options for
every operation for which overflow is possible: modulo (wraparound),
excepting, saturating, and double-width result (which cannot overflow).
It is up to the compiler to choose the behavior to match the desired or
mandated semantics. The other behaviors are also available via intrinsics.

We also have a tool-chain option to force all non-explicit overflow
behaviors to excepting throughout the program. It is truly astonishing
how often "working" programs experience unanticipated (and previously
unknown) overflow. For some value of "working".

Ivan

[toc] | [prev] | [next] | [standalone]


#1075

FromKaz Kylheku <kaz@kylheku.com>
Date2014-01-08 18:21 +0000
Message-ID<14-01-008@comp.compilers>
In reply to#1074
On 2014-01-08, Ivan Godard <ivan@ootbcomp.com> wrote:
> On 11/20/2013 2:29 AM, Martin Ward wrote:
>
><snip>
>
>> (2) CPU designers may choose to implement that behaviour in hardware
>> on the next iteration of the CPU. Now the programs run fast on *all*
>> CPUs.
>>
>> Everybody wins.
>
> I am such a CPU designer. We faced the "undefined" issue in our Mill
> family of general-purpose CPUs (ootbcomp.com). Not only are languages
> under-constraining, they are also sometimes over-constraining: signed
> integer overflow is undefined in C but required to wrap in Java.

It's only undefined on paper. In reality, if you don't make it wrap in C like
in Java, unknown numbers of C programs will break, and not all of them doing it
by accident.

> Our solution was to offer four hardware "overflow-behavior" options for
> every operation for which overflow is possible: modulo (wraparound),
> excepting, saturating, and double-width result (which cannot overflow).
> It is up to the compiler to choose the behavior to match the desired or
> mandated semantics. The other behaviors are also available via intrinsics.

This kind of thing is quite useful for optimizing certain code. For instance,
fixed-point implementations of codecs, in which reproducing bit-exact results
over the test vectors requires "saturation" treatment of overflow. Clamping
the results in software adds many additional cycles.

--
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List:  http://www.kylheku.com/mp1

[toc] | [prev] | [next] | [standalone]


#1077

FromIvan Godard <ivan@ootbcomp.com>
Date2014-01-10 09:11 -0800
Message-ID<14-01-010@comp.compilers>
In reply to#1075
On 1/8/2014 10:21 AM, Kaz Kylheku wrote:
> On 2014-01-08, Ivan Godard <ivan@ootbcomp.com> wrote:
>> On 11/20/2013 2:29 AM, Martin Ward wrote:
>>
>> <snip>
>>
>>> (2) CPU designers may choose to implement that behaviour in hardware
>>> on the next iteration of the CPU. Now the programs run fast on *all*
>>> CPUs.
>>>
>>> Everybody wins.
>>
>> I am such a CPU designer. We faced the "undefined" issue in our Mill
>> family of general-purpose CPUs (ootbcomp.com). Not only are languages
>> under-constraining, they are also sometimes over-constraining: signed
>> integer overflow is undefined in C but required to wrap in Java.
>
> It's only undefined on paper. In reality, if you don't make it wrap in C like
> in Java, unknown numbers of C programs will break, and not all of them doing it
> by accident.

Or one may say that unknown numbers of C programs are already broken.

And the reality is that the program cannot even in practice depend on
wrapping; see http://www.airs.com/blog/archives/120, or just Google
"signed integer overflow in C".

[toc] | [prev] | [next] | [standalone]


#1078

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2014-01-10 23:08 +0000
Message-ID<14-01-011@comp.compilers>
In reply to#1075
Kaz Kylheku <kaz@kylheku.com> wrote:
> On 2014-01-08, Ivan Godard <ivan@ootbcomp.com> wrote:

(snip)
>> I am such a CPU designer. We faced the "undefined" issue in our Mill
>> family of general-purpose CPUs (ootbcomp.com). Not only are languages
>> under-constraining, they are also sometimes over-constraining: signed
>> integer overflow is undefined in C but required to wrap in Java.

> It's only undefined on paper. In reality, if you don't make it
> wrap in C like in Java, unknown numbers of C programs will break,
> and not all of them doing it by accident.

Well, C has unsigned with defined wrap on overflow. C still allows for
ones complement or sign magnitude along with the more usual twos
complement. As I understand it, Unisys still sells some ones
complement machines. I am still waiting for a C compiler for the 7090
to test out sign magnitude in C.

Java doesn't have the unsigned types, except for 16 bit char.  Some
that might have been done unsigned in C, can be done with that
appropriate wrap of twos complement Java.

>> Our solution was to offer four hardware "overflow-behavior" options for
>> every operation for which overflow is possible: modulo (wraparound),
>> excepting, saturating, and double-width result (which cannot overflow).

It has been hardware tradition for a long time to offer double width
product on multiply and dividend on divide, but rare for high-level
languages to allow for its use.

I believe that gcc recognizes casts to (long long) on the operands of
multiply to generate a single multiply instruction with a double
length product. (That is, it doesn't do the three multiplies by zero
that the casts imply.) I don't know about divide.

I have at times needed to multiply two 32 bit values, for a 64 bit
product, then divide by another 32 bit value. I sometimes hope that
the compiler figures it out.

(snip)

> This kind of thing is quite useful for optimizing certain code.
> For instance, fixed-point implementations of codecs, in which
> reproducing bit-exact results over the test vectors requires
> "saturation" treatment of overflow. Clamping the results in
> software adds many additional cycles.

I have also worked on some dynamic programming algorithms that require
saturating arithmetic. I believe that Intel SSE allows for it, but it
is rare for normal CPU instructions.

-- glen

[toc] | [prev] | [next] | [standalone]


#1079

FromIvan Godard <ivan@ootbcomp.com>
Date2014-01-13 12:47 -0800
Message-ID<14-01-012@comp.compilers>
In reply to#1078
On 1/10/2014 3:08 PM, glen herrmannsfeldt wrote:
> Kaz Kylheku <kaz@kylheku.com> wrote:
>> On 2014-01-08, Ivan Godard <ivan@ootbcomp.com> wrote:
>
> (snip)
>>> I am such a CPU designer. We faced the "undefined" issue in our Mill
>>> family of general-purpose CPUs (ootbcomp.com). Not only are languages
>>> under-constraining, they are also sometimes over-constraining: signed
>>> integer overflow is undefined in C but required to wrap in Java.
>
>> It's only undefined on paper. In reality, if you don't make it
>> wrap in C like in Java, unknown numbers of C programs will break,
>> and not all of them doing it by accident.
>
> Well, C has unsigned with defined wrap on overflow. C still allows for
> ones complement or sign magnitude along with the more usual twos
> complement. As I understand it, Unisys still sells some ones
> complement machines. I am still waiting for a C compiler for the 7090
> to test out sign magnitude in C.

Unisys sells *both* one's complement (Univac 1100 descendants) and
sign-magnitude (Burroughs B6500 descendants).
[Wow. Is it custom hardware, or really funky simulators on normal chips? -John]

[toc] | [prev] | [next] | [standalone]


#1080

Fromanton@mips.complang.tuwien.ac.at (Anton Ertl)
Date2014-01-14 14:16 +0000
Message-ID<14-01-013@comp.compilers>
In reply to#1078
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:
>It has been hardware tradition for a long time to offer double width
>product on multiply and dividend on divide, but rare for high-level
>languages to allow for its use.
>
>I believe that gcc recognizes casts to (long long) on the operands of
>multiply to generate a single multiply instruction with a double
>length product. (That is, it doesn't do the three multiplies by zero
>that the casts imply.) I don't know about divide.

Yes, gcc does that for multiplication (suitably written in C, posted
elsewhere in this thread).  It cannot do this for divide, because
there is no way to express the operation in C (boundary conditions
like overflow don't match).

>I have at times needed to multiply two 32 bit values, for a 64 bit
>product, then divide by another 32 bit value. I sometimes hope that
>the compiler figures it out.

No, it won't.  Better use a language that can express this.  Forth has
*/, which does exactly this sequence of operations; it also has
double-by-single division words, as well as
single-by-single-giving-double multiplication words.

- anton
--
M. Anton Ertl
anton@mips.complang.tuwien.ac.at
http://www.complang.tuwien.ac.at/anton/

[toc] | [prev] | [standalone]


Back to top | Article view | comp.compilers


csiph-web