In article <1185722378.498383.20...@d55g2000hsg.googlegroups.com>, William Hughes <wpihug...@hotmail.com> wrote:
>On Jul 29, 10:19 am, Randy Yates <ya...@ieee.org> wrote: >> Phil Carmody <thefatphil_demun...@yahoo.co.uk> writes: >> > [...] >> > But of course that's the programmer taking control. >> To some extent it is, but if you need to "take control," and >> you must delve into architecture specifics and write non-portable >> C code (at least C code that won't run _fast_ on multiple platforms), >A far cry from non-portable code.
Consider the badly designed C function frexp. If executed as a function call AT ALL, the function call is likely to be more costly in time and space than inlining it using assembler instructions, on whatever machine it is to be executed. It also should not use the C language; this is one clear place where an adequate HLL would have to have more than one argument to the left of the replacement call.
Another bad example is the switch operator. It requires an argument for the switch process, and also requires a return to the switch operator even if one knows where to go. In this case, the "argument" should be kept in the location ONLY; this removes an argument assignment, using a multibranch test on argument, as well as a simple transfer when a simple transfer would do as well. This CAN be avoided in C by a liberal use of goto's, which the HLL advocates demean.
A semi-HLL assembler can be produced which is easy to read and write, and almost as concise as a HLL. One could include important instructions which HLLs handle badly. How one carries out multiple precision operations depends heavily on the architecture, and architectures are declining in their ability to do this well. -- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
> A semi-HLL assembler can be produced which is easy to > read and write, and almost as concise as a HLL. One > could include important instructions which HLLs handle > badly. How one carries out multiple precision operations > depends heavily on the architecture, and architectures > are declining in their ability to do this well.
There have been a few examples of high-level assembler languages, PL/360 as one. Consider the PL/360 statement.
R1:=R1+R1+R1;
You might think that it would triple the value in R1 (that is, register one), but it quadruples it. The effect of the first addition takes place immediately, there are no temporary registers.
That is, in some sense, the difference between a high level language and an assembler level language.
> In article <1185722378.498383.20...@d55g2000hsg.googlegroups.com>, > William Hughes <wpihug...@hotmail.com> wrote:
> >On Jul 29, 10:19 am, Randy Yates <ya...@ieee.org> wrote: > >> Phil Carmody <thefatphil_demun...@yahoo.co.uk> writes: > >> > [...] > >> > But of course that's the programmer taking control. > >> To some extent it is, but if you need to "take control," and > >> you must delve into architecture specifics and write non-portable > >> C code (at least C code that won't run _fast_ on multiple platforms), > >A far cry from non-portable code.
> Consider the badly designed C function frexp. If executed > as a function call AT ALL, the function call is likely to > be more costly in time and space than inlining it using > assembler instructions, on whatever machine it is to be > executed. It also should not use the C language; this is > one clear place where an adequate HLL would have to have > more than one argument to the left of the replacement call.
I fail to see your point. When the compiler sees the function frexp it can emit the appropriate machine code without a function call. Compilers can always use compiler magic on a library fuction. [Sure I can force the compiler to use a function call and this will slow things down. So what? There are lots of stupid things I can do to defeat optimization]
Or is your point that the compiler cannot store the exponent in a register. This is simply false. The abstract machine cannot store the exponent in a register but the abtract machine does not have the concept of register. The compiler can use a register for any variable it wants. (If the address of this variable is taken then the compiler has to be able to determine that the address is not actually needed, trivial here). True you cannot use a "register" qualifier for the variable used to store the exponent, but in theory we are allowed to assume that the compiler is as good or better than a good assembly programmer at chosing which variable should go into registers (the fact that this is true in practice is only icing on the cake)
> Another bad example is the switch operator. It requires > an argument for the switch process, and also requires a > return to the switch operator even if one knows where to > go. In this case, the "argument" should be kept in the > location ONLY; this removes an argument assignment, using > a multibranch test on argument, as well as a simple > transfer when a simple transfer would do as well. This > CAN be avoided in C by a liberal use of goto's, which > the HLL advocates demean.
There is nothing to stop the compiler from recognizing when a switch construct can be simplified in the way you describe and doing exactly what you describe. Again you seem to think that if there is an assignment in the abstract machine, the compiler must use and assignment. This is nonsense.
> A semi-HLL assembler can be produced which is easy to > read and write, and almost as concise as a HLL.
But no where near as portable.
> One > could include important instructions which HLLs handle > badly. How one carries out multiple precision operations > depends heavily on the architecture and architectures > are declining in their ability to do this well.
You provide no argument that a compiler coud not chose the appropriate way of carrying out multiple precision operations depending on the architecture.
Here are some examples which give great difficulties in even semi-efficient programs in HLLs.
For x > 0, let x = \sum a_i/2^i be the binary expansion. Define f(x) = \sum i*a_i/2^i; this includes the negative i's as well if x is at least 2. Given x in a "standard" floating point form, how can one compute f(x) efficiently?
Here is one which would be rather useful if it could be carried out somewhat efficiently. I do have a way of doing it in C, but whether in can be reasonably done or not depends on the architecture. It might well need an fpga to carry out one step, which I will assume done.
So let me describe the algorithm as a fixed point algorithm; it does work on floating point. At any time, there are three numbers, q, t, and b. The number p is an ordinary floating point number, and is computed as stated. Suppose the binary expansion of q is \sum r_n/2^n. Then the numbers q, t, and b have the form
The procedure multiplies q by a number z <= 1. If the new q >= t, just accept. If q < b, reject and reset with q=t=1, b=0 (the first time this is used, do the next step with k=0). Let m be the number of bits in a random bit stream to the next 1; set k = k+m. If the new q_k is 1, set things up as before and accept; if it is 0 reject and start over.
The idea here is that one is carrying out acceptance- rejection tests, with the z being the acceptance probability. There is a random number R, whose value is unknown to the programmer, except that at any time, it is uniformly distributed between 0 and q. This means that the test has the desired properties.
However, the machine has gotten some information; R is uniformly distributed between b and t. One can verify that this algorithm has the desired property, and uses far fewer random bits than would be required if R were known. However, it does require more work.
This CAN be programmed in C, as scaling does not affect the algorithm. It works much better if there is a good floating integer part operation and the parity of a such an integer is easily tested. For good algorithms, most of the time the new q will be greater than t.
-- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
In article <46ADC381.51EB0...@bytecraft.com>, Walter Banks <wal...@bytecraft.com> wrote:
>Randy Yates wrote: >> To some extent it is, but if you need to "take control," and >> you must delve into architecture specifics and write non-portable >> C code (at least C code that won't run _fast_ on multiple platforms), >> then assembly provides the ultimate "control." >> I wouldn't use the word "offend" - I consider it an abuse of the >> high level language. >> Hey People, this is ludicrous. All these arguments treat assembly >> as if it were the ultimate evil. It ain't that bad, folks. Honest. >If you need to switch to asm then that specific application will >not be portable. If the HLL can duplicate all of the functionality >that asm has then the advantages of the HLL are not lost. >Regards >Walter Banks
The HLL can duplicate all the functionality of the assembler, for arithmetic by operating on all the bits as the assembler instruction achieves it, not as it does it. For example, there might be an operation which efficiently takes three arguments, multiplies two mxm numbers and adds a third, and places the 2m-length result in appropriate places. Multiple precision arithmetic is difficult on most computers; the present "single precision" should be called "half precision", and the "double precision" single or full.
Now the best the HLL can do in general is to use mxm -> m instructions, and if only the lower part can be gotten, this means that things have to be broken up into size m/2. The advantages of the asm ARE lost.
In some situations, it is even worse. There are many algorithms for producing random variables efficiently, if the appropriate hardware is present, by using Boolean operations on "fixed-point" numbers. These are not integers, but fixed-point reals. Try this in any HLL; it will be difficult, even if the same registers can be used for Boolean and floating operations.
-- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
>Herman Rubin wrote: >(snip) >> A semi-HLL assembler can be produced which is easy to >> read and write, and almost as concise as a HLL. One >> could include important instructions which HLLs handle >> badly. How one carries out multiple precision operations >> depends heavily on the architecture, and architectures >> are declining in their ability to do this well. >There have been a few examples of high-level assembler >languages, PL/360 as one. Consider the PL/360 statement. >R1:=R1+R1+R1; >You might think that it would triple the value in R1 >(that is, register one), but it quadruples it. The effect >of the first addition takes place immediately, there are >no temporary registers. >That is, in some sense, the difference between a high level >language and an assembler level language.
I would not call this an assembler language. It might be a macro added to it, but an assembler instruction is a representation of hardware.
I did produce a reasonable attempt at a readable, slightly high level, assembler language for the VAX. Much of it can be used on any machine. It is a somewhat typed language designed to be easily understood, written, and read.
For example, what is the subtraction instruction in an assembler? I would write
x ={t} y - z
where {t} is the type of subtraction to be used if not the type of x. There would be no promotion of type as in most HLLs; the arguments can be typed, but used as they are stored, in memory or registers.
Now what is needed in most assemblers? One would have to write
subT a, b, c
where T is a type declaration, and a, b, c are x, y, z in some order, although I have never seen x in the middle. THAT is what is hard to work with.
-- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
Herman Rubin wrote: > In some situations, it is even worse. There are many > algorithms for producing random variables efficiently, > if the appropriate hardware is present, by using Boolean > operations on "fixed-point" numbers. These are not > integers, but fixed-point reals. Try this in any HLL; > it will be difficult, even if the same registers can > be used for Boolean and floating operations.
C99 and ISO/IEC 18037 have real fixed point numbers (accums) can you send me a example of this type of algorithm.
hru...@odds.stat.purdue.edu (Herman Rubin) writes: > In article <46ADC381.51EB0...@bytecraft.com>, > Walter Banks <wal...@bytecraft.com> wrote:
> >Randy Yates wrote:
> >> To some extent it is, but if you need to "take control," and > >> you must delve into architecture specifics and write non-portable > >> C code (at least C code that won't run _fast_ on multiple platforms), > >> then assembly provides the ultimate "control."
> >> I wouldn't use the word "offend" - I consider it an abuse of the > >> high level language.
> >> Hey People, this is ludicrous. All these arguments treat assembly > >> as if it were the ultimate evil. It ain't that bad, folks. Honest.
> >If you need to switch to asm then that specific application will > >not be portable. If the HLL can duplicate all of the functionality > >that asm has then the advantages of the HLL are not lost.
> >Regards
> >Walter Banks
> The HLL can duplicate all the functionality of the > assembler, for arithmetic by operating on all the bits as > the assembler instruction achieves it, not as it does it. > For example, there might be an operation which efficiently > takes three arguments, multiplies two mxm numbers and adds > a third, and places the 2m-length result in appropriate > places. Multiple precision arithmetic is difficult on most > computers; the present "single precision" should be called > "half precision", and the "double precision" single or full.
Potayto, potahto.
> Now the best the HLL can do in general is to use mxm -> m > instructions, and if only the lower part can be gotten, > this means that things have to be broken up into size m/2. > The advantages of the asm ARE lost.
OK, there's no muladd on x86, but there is a 32x32->64 multiply, and gcc's perfectly capable of using that:
The actual 32x32->64 multiply has been turned into a single instruction.
What advantage would asm have had over that?
> In some situations, it is even worse. There are many > algorithms for producing random variables efficiently, > if the appropriate hardware is present, by using Boolean > operations on "fixed-point" numbers. These are not > integers, but fixed-point reals. Try this in any HLL; > it will be difficult, even if the same registers can > be used for Boolean and floating operations.
Care to show an actual example of a high level language performing badly in such a case?
There's definitely a case for the use of assembly in some tight corner cases, don't get me wrong. It's just that from what I've seen of (in particular chip-vendor's) development tools, many of the obvious and annoying flaws that HLLs suffered from years ago are fixed.
Phil -- Dear aunt, let's set so double the killer delete select all. -- Microsoft voice recognition live demonstration
>On Jul 30, 2:02 pm, hru...@odds.stat.purdue.edu (Herman Rubin) wrote: >> In article <1185722378.498383.20...@d55g2000hsg.googlegroups.com>, >> William Hughes <wpihug...@hotmail.com> wrote: >> >On Jul 29, 10:19 am, Randy Yates <ya...@ieee.org> wrote: >> >> Phil Carmody <thefatphil_demun...@yahoo.co.uk> writes: >> >> > [...] >> >> > But of course that's the programmer taking control. >> >> To some extent it is, but if you need to "take control," and >> >> you must delve into architecture specifics and write non-portable >> >> C code (at least C code that won't run _fast_ on multiple platforms), >> >A far cry from non-portable code. >> Consider the badly designed C function frexp. If executed >> as a function call AT ALL, the function call is likely to >> be more costly in time and space than inlining it using >> assembler instructions, on whatever machine it is to be >> executed. It also should not use the C language; this is >> one clear place where an adequate HLL would have to have >> more than one argument to the left of the replacement call. >I fail to see your point. When the compiler sees the >function frexp it can emit the appropriate machine >code without a function call. >Compilers can always use compiler magic on >a library fuction. [Sure I can force the compiler to use >a function call and this will slow things down. >So what? There are lots of stupid things I can do to >defeat optimization]
The form of frexp was b = frexp(a, &m), which meant that, unless a = 0, .5 <= |b| < 1, and a = 2^m*b. The form of this statement forces m into memory. To avoid this, one would have to write
b, m = frexp(a)
>Or is your point that the compiler cannot store the >exponent in a register. This is simply false. >The abstract machine cannot store the exponent in a register >but the abtract machine does not have the concept of register.
Alas, the abstract machine needs the concept of a register.
>The compiler can use a register for any variable >it wants. (If the address of this variable is taken >then the compiler has to be able to determine that >the address is not actually needed, trivial here).
Not if the address of the variable is explicitly given.
True you
>cannot use a "register" qualifier for the variable >used to store the exponent, but in theory we are >allowed to assume that the compiler is as good or better >than a good assembly programmer >at chosing which variable should go into registers >(the fact that this is true in practice is only icing >on the cake)
It is true in practice? Not to my knowledge.
>> Another bad example is the switch operator. It requires >> an argument for the switch process, and also requires a >> return to the switch operator even if one knows where to >> go. In this case, the "argument" should be kept in the >> location ONLY; this removes an argument assignment, using >> a multibranch test on argument, as well as a simple >> transfer when a simple transfer would do as well. This >> CAN be avoided in C by a liberal use of goto's, which >> the HLL advocates demean. >There is nothing to stop the compiler from recognizing >when a switch construct can be simplified in the way >you describe and doing exactly what you describe. >Again you seem to think that if there is an assignment >in the abstract machine, the compiler must use >and assignment. This is nonsense.
I doubt that the compiler will be able to recognize that the switch variable is ONLY going to be used in the switch statement, nor will it recognize that a setup like that may call for additional entries from outside the subroutine. I have not noticed additional entries to a function or subroutine in any HLL since early versions of Fortran, and few assemblers even have them. One problem is the return statement.
>> A semi-HLL assembler can be produced which is easy to >> read and write, and almost as concise as a HLL. >But no where near as portable.
More portable than you think.
>> One >> could include important instructions which HLLs handle >> badly. How one carries out multiple precision operations >> depends heavily on the architecture and architectures >> are declining in their ability to do this well. >You provide no argument that a compiler coud not chose >the appropriate way of carrying out multiple precision >operations depending on the architecture. > - William Hughes
I have not seen the language alternatives which allow for it. In addition, different hardwares will have different possibilities, so this provides additional problems. The problem is complicated by the fact that if one wants 200 bits of precision, the size of the hardware constructs is such that 212 may be easier to get than 200; PLI did not allow for this.
-- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
In article <46AE4CA1.CB8A3...@bytecraft.com>, Walter Banks <wal...@bytecraft.com> wrote:
>Herman Rubin wrote: >> In some situations, it is even worse. There are many >> algorithms for producing random variables efficiently, >> if the appropriate hardware is present, by using Boolean >> operations on "fixed-point" numbers. These are not >> integers, but fixed-point reals. Try this in any HLL; >> it will be difficult, even if the same registers can >> be used for Boolean and floating operations. >C99 and ISO/IEC 18037 have real fixed point >numbers (accums) can you send me a example >of this type of algorithm. >Many Thanks >Walter Banks..
The easiest one of these is the density 2x from 0 to 1.
In a random bit stream, find the distance to the first one; call it K. Change the K-th bit of a uniform random variable to 1.
A slightly more complicated one is density 6x(1-x) in the unit interval. Here, get the distance K to the first one as before, and the distance M from that to the next. Let J = K/2, rounded up. Replace the J+M-th bit by the complement of the J-th bit.
-- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
>hru...@odds.stat.purdue.edu (Herman Rubin) writes: >> In article <46ADC381.51EB0...@bytecraft.com>, >> Walter Banks <wal...@bytecraft.com> wrote: >> >Randy Yates wrote: >> >> To some extent it is, but if you need to "take control," and >> >> you must delve into architecture specifics and write non-portable >> >> C code (at least C code that won't run _fast_ on multiple platforms), >> >> then assembly provides the ultimate "control." >> >> I wouldn't use the word "offend" - I consider it an abuse of the >> >> high level language. >> >> Hey People, this is ludicrous. All these arguments treat assembly >> >> as if it were the ultimate evil. It ain't that bad, folks. Honest. >> >If you need to switch to asm then that specific application will >> >not be portable. If the HLL can duplicate all of the functionality >> >that asm has then the advantages of the HLL are not lost. >> >Regards >> >Walter Banks >> The HLL can duplicate all the functionality of the >> assembler, for arithmetic by operating on all the bits as >> the assembler instruction achieves it, not as it does it. >> For example, there might be an operation which efficiently >> takes three arguments, multiplies two mxm numbers and adds >> a third, and places the 2m-length result in appropriate >> places. Multiple precision arithmetic is difficult on most >> computers; the present "single precision" should be called >> "half precision", and the "double precision" single or full. >Potayto, potahto. >> Now the best the HLL can do in general is to use mxm -> m >> instructions, and if only the lower part can be gotten, >> this means that things have to be broken up into size m/2. >> The advantages of the asm ARE lost. >OK, there's no muladd on x86, but there is a 32x32->64 multiply, >and gcc's perfectly capable of using that:
Not all machines have that capability. What should be done on those which do not? In fact, many machines have such poor fixed point multiplication that it is necessary to simulate it with floating point.
Having fixed and floating in the same registers has many advantages. Converting fixed to floating is not difficult, but the other way is. They did add such an instruction to the POWER architecture, but it only stores in memory, losing much of the advantages of registers, which are in fact a limited type of memory.
>... > uint32_t x=atol(argv[1]); > uint32_t y=atol(argv[2]); > uint64_t z=(uint64_t)y*x; > printf("%llu\n",z); >... >gcc-4.1 -> >... > call __strtol_internal > movl $.LC0, (%esp) > mull %esi > movl %eax, 4(%esp) > movl %edx, 8(%esp) > call printf >... >The actual 32x32->64 multiply has been turned into a single >instruction. >What advantage would asm have had over that?
As I said, not all languages have that capability.
>> In some situations, it is even worse. There are many >> algorithms for producing random variables efficiently, >> if the appropriate hardware is present, by using Boolean >> operations on "fixed-point" numbers. These are not >> integers, but fixed-point reals. Try this in any HLL; >> it will be difficult, even if the same registers can >> be used for Boolean and floating operations. >Care to show an actual example of a high level language >performing badly in such a case?
I have posted some examples of it.
>There's definitely a case for the use of assembly in some >tight corner cases, don't get me wrong. It's just that from >what I've seen of (in particular chip-vendor's) development >tools, many of the obvious and annoying flaws that HLLs >suffered from years ago are fixed.
Hardware operations have disappeared because of the HLLs. Double precision multiplication is one of them; not all hardware has it. Normalized floats are another pain; that extra bit of precision makes it difficult to do multiple precision. -- This address is for information only. I do not claim that these views are those of the Statistics Department or of Purdue University. Herman Rubin, Department of Statistics, Purdue University hru...@stat.purdue.edu Phone: (765)494-6054 FAX: (765)494-0558
hru...@odds.stat.purdue.edu (Herman Rubin) writes: > The form of frexp was b = frexp(a, &m), which > meant that, unless a = 0, .5 <= |b| < 1, and > a = 2^m*b. The form of this statement forces > m into memory.
Only in the abstract model. The implementation's permitted to not go via memory. Alas, I can't seem to persuade gcc to demonstrate this, as it appears that frexp isn't an intrinsic.
> >Or is your point that the compiler cannot store the > >exponent in a register. This is simply false. > >The abstract machine cannot store the exponent in a register > >but the abtract machine does not have the concept of register.
> Alas, the abstract machine needs the concept of a register.
> >The compiler can use a register for any variable > >it wants. (If the address of this variable is taken > >then the compiler has to be able to determine that > >the address is not actually needed, trivial here).
> Not if the address of the variable is explicitly given.
The compiler is permitted to recognise that the address isn't needed if it uses a suitable intrinsic, and use a register. Whether compilers actually do this is not a language issue, it's a QoI issue.
> True you > >cannot use a "register" qualifier for the variable > >used to store the exponent, but in theory we are > >allowed to assume that the compiler is as good or better > >than a good assembly programmer > >at chosing which variable should go into registers > >(the fact that this is true in practice is only icing > >on the cake)
> It is true in practice? Not to my knowledge.
For simple number-crunching tasks, on the whole I find modern compilers are fairly good, even without feedback-driven optimisation. Some still have grave annoyances such as Apple's Xcode (gcc-based) not letting there be 32 floating point registers in use within a function. One always seems to go unused (and it's not always the same one). If you're unrolling and parallelising by 4, and you need 8 registers per stream, then things like that can be very annoying. But that again's just QoI.
Phil -- Dear aunt, let's set so double the killer delete select all. -- Microsoft voice recognition live demonstration
hru...@odds.stat.purdue.edu (Herman Rubin) writes: > Phil Carmody <thefatphil_demun...@yahoo.co.uk> wrote: > >OK, there's no muladd on x86, but there is a 32x32->64 multiply, > >and gcc's perfectly capable of using that:
> Not all machines have that capability. What should be done > on those which do not?
In almost all cases I'd just recommend
uint64_t z=(uint64_t)y*x;
and see what the compiler decides to do with it. Complain to your compiler vendor if it does something stupid.
Phil -- Dear aunt, let's set so double the killer delete select all. -- Microsoft voice recognition live demonstration
> In article <1185822779.498334.240...@r34g2000hsd.googlegroups.com>, > William Hughes <wpihug...@hotmail.com> wrote:
> >On Jul 30, 2:02 pm, hru...@odds.stat.purdue.edu (Herman Rubin) wrote: > >> In article <1185722378.498383.20...@d55g2000hsg.googlegroups.com>, > >> William Hughes <wpihug...@hotmail.com> wrote: > >> >On Jul 29, 10:19 am, Randy Yates <ya...@ieee.org> wrote: > >> >> Phil Carmody <thefatphil_demun...@yahoo.co.uk> writes: > >> >> > [...] > >> >> > But of course that's the programmer taking control. > >> >> To some extent it is, but if you need to "take control," and > >> >> you must delve into architecture specifics and write non-portable > >> >> C code (at least C code that won't run _fast_ on multiple platforms), > >> >A far cry from non-portable code. > >> Consider the badly designed C function frexp. If executed > >> as a function call AT ALL, the function call is likely to > >> be more costly in time and space than inlining it using > >> assembler instructions, on whatever machine it is to be > >> executed. It also should not use the C language; this is > >> one clear place where an adequate HLL would have to have > >> more than one argument to the left of the replacement call. > >I fail to see your point. When the compiler sees the > >function frexp it can emit the appropriate machine > >code without a function call. > >Compilers can always use compiler magic on > >a library fuction. [Sure I can force the compiler to use > >a function call and this will slow things down. > >So what? There are lots of stupid things I can do to > >defeat optimization]
> The form of frexp was b = frexp(a, &m), which > meant that, unless a = 0, .5 <= |b| < 1, and > a = 2^m*b. The form of this statement forces > m into memory.
No, as I point out the fact that it looks like m has an address, does not mean that m cannot be a register.
> To avoid this, one would have > to write
> b, m = frexp(a)
> >Or is your point that the compiler cannot store the > >exponent in a register. This is simply false. > >The abstract machine cannot store the exponent in a register > >but the abtract machine does not have the concept of register.
> Alas, the abstract machine needs the concept of a register.
Nonsense. We obviously do not share the same concept of abstract machine.
> >The compiler can use a register for any variable > >it wants. (If the address of this variable is taken > >then the compiler has to be able to determine that > >the address is not actually needed, trivial here).
> Not if the address of the variable is explicitly given.
If the address of the variable is explicitly given then things are not quite as trivial, but the compiler can still determine that the address of the variable is only used to determine where to store the variable.
> True you
> >cannot use a "register" qualifier for the variable > >used to store the exponent, but in theory we are > >allowed to assume that the compiler is as good or better > >than a good assembly programmer > >at chosing which variable should go into registers > >(the fact that this is true in practice is only icing > >on the cake)
> It is true in practice? Not to my knowledge.
Not to my direct knowledge. It is frequently asserted. In any case, whether it is true or not in practice is beside the point. The point is that it can be considered to be true in theory.
> >> Another bad example is the switch operator. It requires > >> an argument for the switch process, and also requires a > >> return to the switch operator even if one knows where to > >> go. In this case, the "argument" should be kept in the > >> location ONLY; this removes an argument assignment, using > >> a multibranch test on argument, as well as a simple > >> transfer when a simple transfer would do as well. This > >> CAN be avoided in C by a liberal use of goto's, which > >> the HLL advocates demean. > >There is nothing to stop the compiler from recognizing > >when a switch construct can be simplified in the way > >you describe and doing exactly what you describe. > >Again you seem to think that if there is an assignment > >in the abstract machine, the compiler must use > >and assignment. This is nonsense.
> I doubt that the compiler will be able to recognize that > the switch variable is ONLY going to be used in the > switch statement, nor will it recognize that a setup > like that may call for additional entries from outside > the subroutine.
I do not know about existing compilers. There is certainly no theoretical barrier
> I have not noticed additional entries > to a function or subroutine in any HLL since early > versions of Fortran, and few assemblers even have them. > One problem is the return statement.
Explicit entry points are not needed. If the compiler can determine that such entry points are useful and it can create them. I see no theoretical barrier to the compiler determining that such entry points are useful.
Phil Carmody wrote: > hru...@odds.stat.purdue.edu (Herman Rubin) writes: >>Phil Carmody <thefatphil_demun...@yahoo.co.uk> wrote: >>>OK, there's no muladd on x86, but there is a 32x32->64 multiply, >>>and gcc's perfectly capable of using that: >>Not all machines have that capability. What should be done >>on those which do not? > In almost all cases I'd just recommend > uint64_t z=(uint64_t)y*x;
I have seen gcc do this right, but g95 I believe generates three multiplies. I think g95 did better with higher -O, though.
"William Hughes" <wpihug...@hotmail.com> wrote in message
news:1185831281.136214.163410@q75g2000hsh.googlegroups.com... : On Jul 30, 4:58 pm, hru...@odds.stat.purdue.edu (Herman Rubin) wrote: : > In article <1185822779.498334.240...@r34g2000hsd.googlegroups.com>, : > William Hughes <wpihug...@hotmail.com> wrote: : > : > : > : > >On Jul 30, 2:02 pm, hru...@odds.stat.purdue.edu (Herman Rubin) wrote: : > >> In article <1185722378.498383.20...@d55g2000hsg.googlegroups.com>, : > >> William Hughes <wpihug...@hotmail.com> wrote: : > >> >On Jul 29, 10:19 am, Randy Yates <ya...@ieee.org> wrote: : > >> >> Phil Carmody <thefatphil_demun...@yahoo.co.uk> writes: : > >> >> > [...] : > >> >> > But of course that's the programmer taking control. : > >> >> To some extent it is, but if you need to "take control," and : > >> >> you must delve into architecture specifics and write non-portable : > >> >> C code (at least C code that won't run _fast_ on multiple platforms), : > >> >A far cry from non-portable code. : > >> Consider the badly designed C function frexp. If executed : > >> as a function call AT ALL, the function call is likely to : > >> be more costly in time and space than inlining it using : > >> assembler instructions, on whatever machine it is to be : > >> executed. It also should not use the C language; this is : > >> one clear place where an adequate HLL would have to have : > >> more than one argument to the left of the replacement call. : > >I fail to see your point. When the compiler sees the : > >function frexp it can emit the appropriate machine : > >code without a function call. : > >Compilers can always use compiler magic on : > >a library fuction. [Sure I can force the compiler to use : > >a function call and this will slow things down. : > >So what? There are lots of stupid things I can do to : > >defeat optimization] : > : > The form of frexp was b = frexp(a, &m), which : > meant that, unless a = 0, .5 <= |b| < 1, and : > a = 2^m*b. The form of this statement forces : > m into memory. : : No, as I point out the fact that it looks like : m has an address, does not mean that m cannot : be a register. : : > To avoid this, one would have : > to write : > : > b, m = frexp(a) : > : > >Or is your point that the compiler cannot store the : > >exponent in a register. This is simply false. : > >The abstract machine cannot store the exponent in a register : > >but the abtract machine does not have the concept of register. : > : > Alas, the abstract machine needs the concept of a register. : : Nonsense. We obviously do not share the same concept of : abstract machine. : : > : > >The compiler can use a register for any variable : > >it wants. (If the address of this variable is taken : > >then the compiler has to be able to determine that : > >the address is not actually needed, trivial here). : > : > Not if the address of the variable is explicitly given. : > : : If the address of the variable is explicitly given then : things are not quite as trivial, but the compiler can : still determine that the address of the variable is only : used to determine where to store the variable. : : > True you : > : > >cannot use a "register" qualifier for the variable : > >used to store the exponent, but in theory we are : > >allowed to assume that the compiler is as good or better : > >than a good assembly programmer : > >at chosing which variable should go into registers : > >(the fact that this is true in practice is only icing : > >on the cake) : > : > It is true in practice? Not to my knowledge. : : Not to my direct knowledge. It is frequently asserted. : In any case, whether it is true or not in practice is : beside the point. The point is that it can be considered : to be true in theory. : : > : > >> Another bad example is the switch operator. It requires : > >> an argument for the switch process, and also requires a : > >> return to the switch operator even if one knows where to : > >> go. In this case, the "argument" should be kept in the : > >> location ONLY; this removes an argument assignment, using : > >> a multibranch test on argument, as well as a simple : > >> transfer when a simple transfer would do as well. This : > >> CAN be avoided in C by a liberal use of goto's, which : > >> the HLL advocates demean. : > >There is nothing to stop the compiler from recognizing : > >when a switch construct can be simplified in the way : > >you describe and doing exactly what you describe. : > >Again you seem to think that if there is an assignment : > >in the abstract machine, the compiler must use : > >and assignment. This is nonsense. : > : > I doubt that the compiler will be able to recognize that : > the switch variable is ONLY going to be used in the : > switch statement, nor will it recognize that a setup : > like that may call for additional entries from outside : > the subroutine. : : I do not know about existing compilers. There : is certainly no theoretical barrier
: > I have not noticed additional entries : > to a function or subroutine in any HLL since early : > versions of Fortran, and few assemblers even have them. : > One problem is the return statement. : : Explicit entry points are not needed. If the compiler : can determine that such entry points are useful and : it can create them.
<syntax error 234> Unexpected statement terminator. "then" statement expected after "if" statement followed by "and" statement. Compilation terminated, unrecoverable error.
If you can't write normal English syntax how the fuck do you expect a compiler to translate and assemble your code?
> >>>OK, there's no muladd on x86, but there is a 32x32->64 multiply, > >>>and gcc's perfectly capable of using that:
> >>Not all machines have that capability. What should be done > >> on those which do not?
> > In almost all cases I'd just recommend
> > uint64_t z=(uint64_t)y*x;
> I have seen gcc do this right, but g95 I believe generates three > multiplies. I think g95 did better with higher -O, though.
If one of the languages copes, and another doesn't, then that implies it's done at the HLL level, and that gcc explicitly knows that this construct is actually working with int-sized inputs, and only requiring double-width for its output.
It should, however, be possible to perform this optimisation at a lower level, rather than having explicit knowledge of that HLL construct. There's nothing preventing the compiler from generating an initial 3-multiply sequence of terms some of which it knows are zeroes. Those then get optimised away with a generic num*0=0 and num+0=num replacement. It's entirely possible different versions of the compiler have taken different approaches, as I know that gcc's changed quite a bit since 3.0 days.
Phil -- Dear aunt, let's set so double the killer delete select all. -- Microsoft voice recognition live demonstration
Herman Rubin wrote: > In article <ObidnWOaJvBvszPbnZ2dnUVZ_hKdn...@comcast.com>, > glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
(snip)
>>There have been a few examples of high-level assembler >>languages, PL/360 as one. Consider the PL/360 statement. >>R1:=R1+R1+R1; >>You might think that it would triple the value in R1 >>(that is, register one), but it quadruples it. The effect >>of the first addition takes place immediately, there are >>no temporary registers.
(snip)
> I would not call this an assembler language. It might > be a macro added to it, but an assembler instruction is > a representation of hardware.
I am not sure of the right name, either. It is, though, a representation of the hardware. R1 means register 1. The allowed operations are machine specific.
On Mon, 30 Jul 2007 12:00:55 -0400, Herman Rubin wrote: > In article <b1Jqi.83$jO...@nlpi070.nbdc.sbc.com>, <h...@40th.com> wrote: > One can easily give examples where the current languages > are poor, and one can produce better instruction sets. One > case, lacking in all computer languages to my knowledge > (LISP may be an exception, but it is too clumsy) is the > ability to have a list of results to the left of the > replacement operator; this utility of this cannot be > achieved by a struct.
Unfortunately many of these are fairly limited about how the multiple returned values can be used. Matlab and python will let you have multiple left-hand-side values on function return (as in: (a, b) = twoRetVal()), but this isn't sufficiently symmetrical with function arguments to allow you to pass two returned values as two arguments in an expression like twoArgs(twoRetVal()). This use is possible in scheme and common lisp, and the syntax isn't too bad, but I can understand why you might find it verbose. Forth and postscript get this behaviour for free, of course, with no syntax to speak of...
I'm not sufficiently familiar with the ML and Hascal clan of functional languages to know whether they can do this or not. I'd guess that they can, since they're modern languages, but I'm hoping that someone more knowledgeable will chime in.
>> Tim has regular comment [in] c.l.f., fortran being a common extension of >> C. As such, it has a standard.
>> My experience in assembly would lead me to believe that it just might not >> have a standard, as it is so close to many OS/hardware questions. I have >> two questions:
>> 1) Does assembly have a standard?
> Assembly is the human readable representation of the operations for > a specific processor. It is different for each type of processor, > or even for each revision of a processor. (Though not always very > different.) Even then it isn't standard. The GNU assemblers often > use different notation than the ones supplied by the manufacturer > of the processor.
Yet the fellow mentioned ISO/IEC 18037. So they have some form of standards. I think that they do not have a standard as does the C Programming Language. Therein we learn that Fortran is a common C extension.
>> 2) If fortran binds C, and C binds assembly, does Fortran bind assembly?
> In terms of "high level languages", C is considered lower level than > many others. It is a little more natural to allow mixing of assembler > and C.
The only 2 reasons I can think of that you couldn't use fortran to call assembly through C are 1) The C Standard prohibits it. 2) The Fortran Standard prohibits it. -- Wade Ward
Wade Ward wrote: > "glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
(snip)
>>>2) If fortran binds C, and C binds assembly, does Fortran bind assembly? >>In terms of "high level languages", C is considered lower level than >>many others. It is a little more natural to allow mixing of assembler >>and C. > The only 2 reasons I can think of that you couldn't use fortran to call > assembly through C are 1) The C Standard prohibits it. 2) The Fortran > Standard prohibits it.
Many C compilers allow inline assembly such as:
x=3; #asm mov 4,x #endasm
You can write assembly routines callable from C or Fortran, C callable ones should be callable with C interoperability.
I don't know of Fortran compilers with inline assembly, but it should be possible.
glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote: > Wade Ward wrote: > > The only 2 reasons I can think of that you couldn't use fortran to call > > assembly through C are 1) The C Standard prohibits it. 2) The Fortran > > Standard prohibits it.
No, There is no such prohibition in the Fortran standard (and I doubt in the C standard either). To the contrary, the Fortran standard is quite explicit about allowing calls to procedures written in other languages. Of course, it doesn't say anything about what you would do to make such calls work (except for the f2003 C interp stuff). But it is quite explicit about allowing calls to non-Fortran procedures. The f2003 C interop stuff is also explicit about it being allowed to use it with languages other than C; it requires only that the procedure be "describable by a C interface" (plus some conditions on that interface). That somewhat roundabout wording is deliberate and carefully avoids saying that the procedure must be written in C.
I assume that your wording above is intended to be speculation, although you don't quite say so. In any case, it is completely wrong.
> I don't know of Fortran compilers with inline assembly, but > it should be possible.
DPB mentions OpenWatcom,which I don't have direct experience with. But there used to be other Fortran compilers that allowed such a thing. I think I recall it on an old SDS machine circa 1973. I'm sure I saw such inline assembly on something around then; I'm not so sure about it being the SDS.
-- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
glen herrmannsfeldt wrote: > Wade Ward wrote: >> "glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message > (snip)
>>>> 2) If fortran binds C, and C binds assembly, does Fortran bind >>>> assembly?
>>> In terms of "high level languages", C is considered lower level than >>> many others. It is a little more natural to allow mixing of assembler >>> and C.
>> The only 2 reasons I can think of that you couldn't use fortran to >> call assembly through C are 1) The C Standard prohibits it. 2) The >> Fortran Standard prohibits it.
> Many C compilers allow inline assembly such as:
> x=3; > #asm > mov 4,x > #endasm
> You can write assembly routines callable from C or Fortran, > C callable ones should be callable with C interoperability.
> I don't know of Fortran compilers with inline assembly, but > it should be possible.
That was the format for embedded assembly language in the original K&R version of C. Its pretty rare to find a compiler which understands #asm/#endasm today. They usually use something similar to the GCC syntax. The better ones let you achieve nice integration, with good communication between the C and assembly language code, like the following code for GCC:
static inline int top_bit(unsigned int bits) { int res;
Sadly, many compilers provide only a subset of this functionality. They provide some means to embed lines of assembler code, with a similar syntax to the above. However, they lack the ability for the assembly language parts to detect the registers allocated for variables, and work with them in place, as the code above does.
For many applications, even on the desktop, embedding a few strategic fragments of assembly language in C makes a world of difference to performance. I consider any compiler not taking this as seriously as GCC to be seriously second rate.
> That was the format for embedded assembly language in the original K&R > version of C. Its pretty rare to find a compiler which understands > #asm/#endasm today. They usually use something similar to the GCC > syntax. The better ones let you achieve nice integration, with good > communication between the C and assembly language code, like the > following code for GCC:
(snip)
In most cases I have needed assembly access from C, I write a simple function in C, compile it with the -S option to get the generated assembly code, then modify that as needed.
The last time I did mixed C/asm code was with Dynamic C for the Rabbit processor (pretty much a 30 MHz Z80 with 256K RAM and 256K flash ROM). Dynamic C, which is still being supported, uses the #asm/#endasm form.
>> In particular, one could imagine a high-level language specifically >> designed to be extensible to add new high-level constructs that make >> available the low-level constructs of a particular platform. > You don't need to imagine it. Forth has always done that. But no HLL can > do it portably across all platforms. For example, checking the carry > flag: the Alpha doesn't have one.
IBM S/360 (and successors) don't have a carry bit either, but the appropriate information can be obtained when needed. Alpha does do things a little differently.
"carry flag" implies sequential execution of instructions, such that the flags from one are available to the next. What is needed is the ability to detect unsigned overflow in addition. (Or for signed overflow the overflow flag.)
In the cases where Alpha does need to supply flag information, such as the CMPLE (compare signed quadword less than or equal) it is generated in a register. Another example is CMPBGE which does unsigned compare between each byte of two 64 bit registers generating eight result bits.
To generate carry, it seems that taking the ones complement of one operand and then doing an unsigned compare against the other operand should give the appropriate result.
One wants to detect A+B > 2**n-1, equivalently A > 2**n-1-B, where 2**n-1-B is the ones complement of B using the ORNOT instruction with zero (R31).
For S/360, the Add Logical instruction (AL) generates the appropriate condition code, and a conditional branch is used to generate the appropriate value.