Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.compilers > #1049 > unrolled thread
| Started by | Martin Ward <martin@gkc.org.uk> |
|---|---|
| First post | 2013-11-20 10:29 +0000 |
| Last post | 2014-01-14 14:16 +0000 |
| Articles | 12 — 6 participants |
Back to article view | Back to comp.compilers
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
| From | Martin Ward <martin@gkc.org.uk> |
|---|---|
| Date | 2013-11-20 10:29 +0000 |
| Subject | Implementation 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]
| From | Joshua Cranmer 🐧 <Pidgeot18@verizon.net> |
|---|---|
| Date | 2013-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]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2013-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]
| From | Martin Ward <martin@gkc.org.uk> |
|---|---|
| Date | 2014-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]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2013-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]
| From | Martin Ward <martin@gkc.org.uk> |
|---|---|
| Date | 2014-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]
| From | Ivan Godard <ivan@ootbcomp.com> |
|---|---|
| Date | 2014-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]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-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]
| From | Ivan Godard <ivan@ootbcomp.com> |
|---|---|
| Date | 2014-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]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2014-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]
| From | Ivan Godard <ivan@ootbcomp.com> |
|---|---|
| Date | 2014-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]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2014-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