Greetings,
I am a long-time C programmer (close to 30 years) with very little C++
experience. I don't keep up with the standards process but there are
two features that I've long thought needed. It might be that C++
already has these features or that the upcoming standards for C or C++
have these features. I suppose I'm just asking and if they are not
there already, I'm suggesting their addition. They are as follows:
1. Computed goto
It would be very useful to have a computed goto. This would involve two
things. First you should be able to use labels as read-only variables.
Second, you should be able to branch assign the label to an array and
branch to it via indexing into the array as follows:
lbl1:
...
lbl2:
...
void *labels[] = {lbl1, lbl2};
goto labels[x];
The labels should not have to appear before the assignment, and there
should be a way of making this runtime assignment to labels once.
The use of this feature is in virtual machines. VM's typically process
op-codes. These op-codes can be treated as indexes into the branch
array. This would be very, very fast. I know C can use arrays of
function pointers that can be indexed into and executed but the problem
is that you have the (often huge) function overhead associated with each
instruction. The other probable response is a case statement. The
problem is that a case statement must do a lot of time-consuming
compares in order get to the correct case. In index and branch is much
faster. (I know case statement are optimized to a point but I don't
think they are guaranteed to be as fast as an index and branch).
2. Function goto instead of call
When you call a function (typically) a call stack is created. When the
function returns the return goes to the calling function. Some C
compilers can do tail call elimination in certain circumstances but it
is never guaranteed to support tail calls in all obvious conditions. C
is often used as an intermediate language for other languages compilers
(like Lisp, Scheme, etc.). Languages such as Scheme require tail call
optimization. Coding in assembler is very un-portable. Using C as a
portable assembler is great but not being able to eliminate tail calls
is a big problem. Scheme compilers often use a set of tricks to make C
eliminate tail calls but these tricks are very slow compared to what is
really needed. If C had the ability to "goto" a function rather than
"call" a function, other compiler writers can take advantage of this
feature to give their languages tail call elimination without costly
tricks or having to resort to assembler.
Does anyone know if these facilities are in upcoming C or C++ standards?
Have there been any discussion or even mention of these issues?
Thanks.
Blake McBride
blake@mcbride.name
http://blake.mcbride.name
|
|
0
|
|
|
|
Reply
|
blake (64)
|
1/6/2009 5:13:08 PM |
|
Blake McBride wrote:
) The use of this feature is in virtual machines. VM's typically process
) op-codes. These op-codes can be treated as indexes into the branch
) array. This would be very, very fast. I know C can use arrays of
) function pointers that can be indexed into and executed but the problem
) is that you have the (often huge) function overhead associated with each
) instruction. The other probable response is a case statement. The
) problem is that a case statement must do a lot of time-consuming
) compares in order get to the correct case. In index and branch is much
) faster. (I know case statement are optimized to a point but I don't
) think they are guaranteed to be as fast as an index and branch).
Case statements were *invented* to be turned into index-and-branch.
Do you agree that computed gotos would be a moot point if compilers
would *guarantee* that a case statement (perhaps with some restrictions,
such as only with successive integers) would be turned into an
index-and-branch ? Then why not ask for such a guarantee ?
That would be ten times easier.
) 2. Function goto instead of call
)
) When you call a function (typically) a call stack is created. When the
) function returns the return goes to the calling function. Some C
) compilers can do tail call elimination in certain circumstances but it
) is never guaranteed to support tail calls in all obvious conditions. C
) is often used as an intermediate language for other languages compilers
) (like Lisp, Scheme, etc.). Languages such as Scheme require tail call
) optimization. Coding in assembler is very un-portable. Using C as a
) portable assembler is great but not being able to eliminate tail calls
) is a big problem. Scheme compilers often use a set of tricks to make C
) eliminate tail calls but these tricks are very slow compared to what is
) really needed. If C had the ability to "goto" a function rather than
) "call" a function, other compiler writers can take advantage of this
) feature to give their languages tail call elimination without costly
) tricks or having to resort to assembler.
Again. If a compiler were to *guarantee* that it does tail call
elimination (perhaps with certain restrictions) then this point
becomes moot.
So, perhaps you should go looking for a compiler that makes such
guarantees.
SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
|
|
0
|
|
|
|
Reply
|
willem (1478)
|
1/6/2009 5:26:43 PM
|
|
Blake McBride <blake@mcbride.name> writes:
> I am a long-time C programmer (close to 30 years) with very little C++
> experience. I don't keep up with the standards process but there are
> two features that I've long thought needed. It might be that C++
> already has these features or that the upcoming standards for C or C++
> have these features. I suppose I'm just asking and if they are not
> there already, I'm suggesting their addition. They are as follows:
>
> 1. Computed goto
>
[snip]
>
> 2. Function goto instead of call
>
[snip]
>
> Does anyone know if these facilities are in upcoming C or C++
> standards? Have there been any discussion or even mention of these
> issues?
I've never heard of either of them being seriously considered.
If you want to propose changes to future versions of the C or C++
standard, the best place to start is comp.std.c and/or comp.std.c++.
Neither newsgroup has any official standing with the respective
committees, but they're better places to discuss revisions than the
language groups.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
|
|
0
|
|
|
|
Reply
|
kst-u (21464)
|
1/6/2009 5:33:32 PM
|
|
Willem wrote:
>
> So, perhaps you should go looking for a compiler that makes such
> guarantees.
Depending on a specific compiler destroys the whole reason for using C
as a portable assembler. It must be a standards change.
>
>
> SaSW, Willem
|
|
0
|
|
|
|
Reply
|
blake (64)
|
1/6/2009 5:47:59 PM
|
|
In article <4rWdnbFJbuLTBP7UnZ2dnUVZ_tjinZ2d@supernews.com>,
Blake McBride <blake@mcbride.name> wrote:
>Willem wrote:
>>
>> So, perhaps you should go looking for a compiler that makes such
>> guarantees.
>
>Depending on a specific compiler destroys the whole reason for using C
>as a portable assembler. It must be a standards change.
That's not really true if, say, the specific compiler is gcc or
something from MS. I have no real problem depending on gcc for my
programs, since gcc is implemented just about everywhere.
And, coincidentally enough, gcc does things along the lines of which you
speak (I don't want to speak to specifics, but you get the drift).
|
|
0
|
|
|
|
Reply
|
gazelle3 (1598)
|
1/6/2009 6:04:42 PM
|
|
"Blake McBride" <blake@mcbride.name> wrote in message
news:DsGdnRMsU8S5DP7UnZ2dnUVZ_ojinZ2d@supernews.com...
> 1. Computed goto
>
> It would be very useful to have a computed goto. This would involve two
> things. First you should be able to use labels as read-only variables.
> Second, you should be able to branch assign the label to an array and
> branch to it via indexing into the array as follows:
>
> lbl1:
> ...
> lbl2:
> ...
> void *labels[] = {lbl1, lbl2};
>
> goto labels[x];
I think something like this is available on the gcc compiler. You use &&lbl1
to obtain the address of a label. Not sure what the corresponding goto
looked like.
> 2. Function goto instead of call
>
> When you call a function (typically) a call stack is created. When the
....
> really needed. If C had the ability to "goto" a function rather than
> "call" a function, other compiler writers can take advantage of this
> feature to give their languages tail call elimination without costly
> tricks or having to resort to assembler.
I tried to do something like this once, using the address of a function,
combined with a goto to what it thought was a label. But the gcc insisted on
putting strange prologues and other code around a function, even if it had
no local variables.
I was trying to do this for possibly the same reasons as you. In the end I
just used asm for the portions of my application that were critical enough
to need this.
> Does anyone know if these facilities are in upcoming C or C++ standards?
Sounds unlikely.
--
Bartc
|
|
0
|
|
|
|
Reply
|
bartc (783)
|
1/6/2009 6:12:56 PM
|
|
On Jan 6, 12:47=A0pm, Blake McBride <bl...@mcbride.name> wrote:
> Willem wrote:
>
> > So, perhaps you should go looking for a compiler that makes such
> > guarantees.
>
> Depending on a specific compiler destroys the whole reason for using C
> as a portable assembler. =A0It must be a standards change.
Except the problems you are seeking to solve would not be solved by a
standards change.
C++ does not place performance requirements on the code that compilers
generate. Adding computed gotos and function gotos would *not*
guarantee that you get jump tables and lightweight function jumps.
That is simply outside the scope of the language. You would still end
up relying on a specific compiler that optimized those constructs the
way you wanted them to be optimized.
The standard will never include wording that mandates, for example,
that "function gotos" be implemented with tail call optimizations.
Those details will always be implementation defined.
Also, while such "optimized" (quoted because C++ would not guarantee
any optimization) constructs are certainly useful in a VM application,
their use in such a specialized type of application, IMHO, is not
sufficient motivation for a language change.
By the way, the place to discuss the standard is comp.std.c++; it is a
moderated group and usually more appropriate (although it was down for
a while recently, but seems to be happily up and running now).
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/6/2009 6:14:00 PM
|
|
On Jan 6, 12:26=A0pm, Willem <wil...@stack.nl> wrote:
> Case statements were *invented* to be turned into index-and-branch.
Incidentally, since you mention it, I did observe on at least one
occasion MSVC turning a switch statement into a jump table. I have a
hard time reproducing that behavior at will, though. IIRC it was in a
fairly old version of the compiler, VC 4.0 maybe.
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/6/2009 6:16:08 PM
|
|
Blake McBride wrote:
> 1. Computed goto
>
> It would be very useful to have a computed goto. This would involve two
> things. First you should be able to use labels as read-only variables.
> Second, you should be able to branch assign the label to an array and
> branch to it via indexing into the array as follows:
>
> lbl1:
> ...
> lbl2:
> ...
> void *labels[] = {lbl1, lbl2};
>
> goto labels[x];
>
> The labels should not have to appear before the assignment, and there
> should be a way of making this runtime assignment to labels once.
GCC already has this; see:
http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
Most new features in the C standard come from existing,
commonly-implemented extensions in compilers. I don't know how many
other compilers implement this one, but it seems like a logical candidate.
> The use of this feature is in virtual machines. VM's typically process
> op-codes. These op-codes can be treated as indexes into the branch
> array. This would be very, very fast. I know C can use arrays of
> function pointers that can be indexed into and executed but the problem
> is that you have the (often huge) function overhead associated with each
> instruction. The other probable response is a case statement. The
> problem is that a case statement must do a lot of time-consuming
> compares in order get to the correct case. In index and branch is much
> faster. (I know case statement are optimized to a point but I don't
> think they are guaranteed to be as fast as an index and branch).
If your compiler is any good, it _will_ optimize a case statement into
an index into a jump table when that is faster than doing compares. No
additional syntax is required.
However, there are other uses for computed gotos which cannot be
similarly optimized. However, given the general disdain for "goto" in
the first place, I'm not optimistic. It's fairly rare that "goto" is
the correct solution, and it makes other parts of optimization harder.
> 2. Function goto instead of call
>
> When you call a function (typically) a call stack is created. When the
> function returns the return goes to the calling function. Some C
> compilers can do tail call elimination in certain circumstances but it
> is never guaranteed to support tail calls in all obvious conditions. C
> is often used as an intermediate language for other languages compilers
> (like Lisp, Scheme, etc.). Languages such as Scheme require tail call
> optimization. Coding in assembler is very un-portable. Using C as a
> portable assembler is great but not being able to eliminate tail calls
> is a big problem. Scheme compilers often use a set of tricks to make C
> eliminate tail calls but these tricks are very slow compared to what is
> really needed. If C had the ability to "goto" a function rather than
> "call" a function, other compiler writers can take advantage of this
> feature to give their languages tail call elimination without costly
> tricks or having to resort to assembler.
Tail call elimination is a useful feature, and if a compiler is going to
support the feature, it's easy enough to do so without requiring new
syntax. The usual case is "return foo();", where foo() has the same
return type as the calling function. It'd be very difficult for a
compiler to do it in most other scenarios.
Also, the C standard folks generally avoid telling implementors that
they _must_ support a particular optimization; the usual process is to
write the standard so that various optimizations are _possible_, and
then most implementors will go do as many of them as they can. I do not
see any need to change that in this case.
> Does anyone know if these facilities are in upcoming C or C++ standards?
> Have there been any discussion or even mention of these issues?
I think the newsgroup you are looking for is comp.std.c.
S
|
|
0
|
|
|
|
Reply
|
stephen (1122)
|
1/6/2009 6:59:37 PM
|
|
[comp.lang.c++ dropped]
Blake McBride <blake@mcbride.name> writes:
> 1. Computed goto
>
> It would be very useful to have a computed goto.
Are you aware that GCC already has such an extension?
> The other probable response is a case
> statement. The problem is that a case statement must do a lot of
> time-consuming compares in order get to the correct case. In index
> and branch is much faster. (I know case statement are optimized to a
> point but I don't think they are guaranteed to be as fast as an index
> and branch).
Most decent compilers will use a branch table whenever it can be
done efficiently.
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
|
|
0
|
|
|
|
Reply
|
blp (3953)
|
1/6/2009 7:02:47 PM
|
|
On Jan 6, 10:16=A0am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> On Jan 6, 12:26=A0pm, Willem <wil...@stack.nl> wrote:
>
> > Case statements were *invented* to be turned into index-and-branch.
>
> Incidentally, since you mention it, I did observe on at least one
> occasion MSVC turning a switch statement into a jump table. I have a
> hard time reproducing that behavior at will, though. IIRC it was in a
> fairly old version of the compiler, VC 4.0 maybe.
Heck, on an old Z8000 ZEUS compiler, switch statements were converted
into jump tables. This was back in the mid-80s.
|
|
0
|
|
|
|
Reply
|
redfloyd (276)
|
1/6/2009 7:11:47 PM
|
|
jason.cipriani@gmail.com wrote:
> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
>> Case statements were *invented* to be turned into index-and-branch.
>
> Incidentally, since you mention it, I did observe on at least one
> occasion MSVC turning a switch statement into a jump table. I have a
> hard time reproducing that behavior at will, though. IIRC it was in a
> fairly old version of the compiler, VC 4.0 maybe.
The easiest way to persuade your compiler to do this optimization is to
have a long list of cases with sequential values. Large holes in the
sequence cause the jump table to get excessively large, and if the list
is too short, the compiler may decide that it's faster to use some other
method (like a binary search).
This optimization is especially useful when every case consists of a
single function call (all of the same signature, including the same
parameters if any) and then a break. The compiler can turn the entire
thing into one indirect call via the jump table. For less uniform
cases, all it can do is turn it into an indirect goto. You can directly
write the former yourself if you want to be sure that's what you get,
but you can't do the latter in standard C.
S
|
|
0
|
|
|
|
Reply
|
stephen (1122)
|
1/6/2009 7:17:01 PM
|
|
red floyd wrote:
> On Jan 6, 10:16 am, "jason.cipri...@gmail.com"
> <jason.cipri...@gmail.com> wrote:
>> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
>>
>>> Case statements were *invented* to be turned into index-and-branch.
>> Incidentally, since you mention it, I did observe on at least one
>> occasion MSVC turning a switch statement into a jump table. I have a
>> hard time reproducing that behavior at will, though. IIRC it was in a
>> fairly old version of the compiler, VC 4.0 maybe.
>
>
> Heck, on an old Z8000 ZEUS compiler, switch statements were converted
> into jump tables. This was back in the mid-80s.
I wonder whether any modern compilers turn if/else trees into jump
tables (when logically equivalent).
|
|
0
|
|
|
|
Reply
|
jeff34 (1594)
|
1/6/2009 7:19:26 PM
|
|
Stephen Sprunk wrote:
> jason.cipriani@gmail.com wrote:
>> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
>>> Case statements were *invented* to be turned into index-and-branch.
>>
>> Incidentally, since you mention it, I did observe on at least one
>> occasion MSVC turning a switch statement into a jump table. I have a
>> hard time reproducing that behavior at will, though. IIRC it was in a
>> fairly old version of the compiler, VC 4.0 maybe.
>
> The easiest way to persuade your compiler to do this optimization is to
> have a long list of cases with sequential values. Large holes in the
> sequence cause the jump table to get excessively large, and if the list
> is too short, the compiler may decide that it's faster to use some other
> method (like a binary search).
You'll typically get at least one comparison to see whether
the index is in the range of covered cases. An explicit array-
of-labels construct could avoid this comparison, at the cost of
exchanging defined behavior (do `default' case or skip the entire
`switch' body) for undefined behavior (out-of-bounds array access)
if the index happens to be weird.
IMHO the opportunity for optimization is pretty slight unless
*very* little work is being done in each `case', and a language
feature probably needs a stronger justification than "It makes a
corner case just a little faster, maybe." This is doubly true
of a language feature that encourages more `goto' statements ...
If there are other, more compelling use cases I'd be interested to
read about them -- just out of curiosity, not implying that I'd
get to vote on their adoption.
--
Eric.Sosman@sun.com
|
|
0
|
|
|
|
Reply
|
Eric.Sosman (4228)
|
1/6/2009 8:02:37 PM
|
|
On Jan 6, 9:13=A0am, Blake McBride <bl...@mcbride.name> wrote:
> Greetings,
>
> I am a long-time C programmer (close to 30 years) with very little C++
> experience. =A0I don't keep up with the standards process but there are
> two features that I've long thought needed. =A0It might be that C++
> already has these features or that the upcoming standards for C or C++
> have these features. =A0I suppose I'm just asking and if they are not
> there already, I'm suggesting their addition. =A0They are as follows:
>
> 1. =A0Computed goto
>
> It would be very useful to have a computed goto. =A0This would involve tw=
o
> things. =A0First you should be able to use labels as read-only variables.
> =A0 Second, you should be able to branch assign the label to an array and
> branch to it via indexing into the array as follows:
>
> lbl1:
> =A0 =A0 =A0 =A0 ...
> lbl2:
> =A0 =A0 =A0 =A0 ...
> void *labels[] =3D {lbl1, lbl2};
>
> goto labels[x];
>
> The labels should not have to appear before the assignment, and there
> should be a way of making this runtime assignment to labels once.
Just use an array of function pointers. Easier to understand and
debug. And if you really need to exchange them, exchange them.
Computed gotos are a tangled mess when used without discipline. I
shudder at some old Fortran I had to maintain in the 70's that used
them. Eventually, I rewrote the entire mess into PL/1.
[snip]
|
|
0
|
|
|
|
Reply
|
dcorbit (2696)
|
1/6/2009 8:05:55 PM
|
|
On January 6, 2009 15:05, in comp.lang.c, user923005 (dcorbit@connx.com=
)
wrote:
> On Jan 6, 9:13=A0am, Blake McBride <bl...@mcbride.name> wrote:
>> Greetings,
>>
>> I am a long-time C programmer (close to 30 years) with very little C=
++
>> experience. =A0I don't keep up with the standards process but there =
are
>> two features that I've long thought needed. =A0It might be that C++
>> already has these features or that the upcoming standards for C or C=
++
>> have these features. =A0I suppose I'm just asking and if they are no=
t
>> there already, I'm suggesting their addition. =A0They are as follows=
:
>>
>> 1. =A0Computed goto
>>
>> It would be very useful to have a computed goto. =A0This would invol=
ve two
>> things. =A0First you should be able to use labels as read-only varia=
bles.
>> Second, you should be able to branch assign the label to an array an=
d
>> branch to it via indexing into the array as follows:
>>
>> lbl1:
>> ...
>> lbl2:
>> ...
>> void *labels[] =3D {lbl1, lbl2};
>>
>> goto labels[x];
>>
>> The labels should not have to appear before the assignment, and ther=
e
>> should be a way of making this runtime assignment to labels once.
>=20
> Just use an array of function pointers.=20
[snip]
A dumb question: Aren't "computed gotos" already implicit in the langua=
ge,
in that they could be easily implemented (at a source-code level) using=
already-existing language constructs? I'm thinking of something like..=
..
{
lbl: /* do something */
lbl2: /* do something else */
switch (x)
{
case 0: goto lbl1;
case 1: goto lbl2;
}
}
which gives the same results (AFAICT) as the OP's example.
--=20
Lew Pitcher
Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by requ=
est
---------- Slackware - Because I know what I'm doing. ---=
---
|
|
0
|
|
|
|
Reply
|
lpitcher2 (869)
|
1/6/2009 8:37:16 PM
|
|
In article <1231272028.168873@news1nwk>,
Eric Sosman <Eric.Sosman@sun.com> wrote:
> You'll typically get at least one comparison to see whether
>the index is in the range of covered cases.
This was one of the disappointments of C89: many people had assumed
that enum types would be sufficiently constrained that a switch-on-enum
would not need such a check.
> IMHO the opportunity for optimization is pretty slight unless
>*very* little work is being done in each `case'
But there is an important use case in which this is true: implementing
virtual machines.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
|
|
0
|
|
|
|
Reply
|
richard91 (3683)
|
1/6/2009 9:34:06 PM
|
|
Lew Pitcher wrote:
> On January 6, 2009 15:05, in comp.lang.c, user923005 (dcorbit@connx.com)
> wrote:
>
>> On Jan 6, 9:13 am, Blake McBride <bl...@mcbride.name> wrote:
>>> Greetings,
>>>
>>> I am a long-time C programmer (close to 30 years) with very little C++
>>> experience. I don't keep up with the standards process but there are
>>> two features that I've long thought needed. It might be that C++
>>> already has these features or that the upcoming standards for C or C++
>>> have these features. I suppose I'm just asking and if they are not
>>> there already, I'm suggesting their addition. They are as follows:
>>>
>>> 1. Computed goto
>>>
>>> It would be very useful to have a computed goto. This would involve two
>>> things. First you should be able to use labels as read-only variables.
>>> Second, you should be able to branch assign the label to an array and
>>> branch to it via indexing into the array as follows:
>>>
>>> lbl1:
>>> ...
>>> lbl2:
>>> ...
>>> void *labels[] = {lbl1, lbl2};
>>>
>>> goto labels[x];
>>>
>>> The labels should not have to appear before the assignment, and there
>>> should be a way of making this runtime assignment to labels once.
>> Just use an array of function pointers.
> [snip]
>
> A dumb question: Aren't "computed gotos" already implicit in the language,
> in that they could be easily implemented (at a source-code level) using
> already-existing language constructs? I'm thinking of something like...
>
> {
> lbl: /* do something */
>
> lbl2: /* do something else */
>
> switch (x)
> {
> case 0: goto lbl1;
> case 1: goto lbl2;
> }
> }
> which gives the same results (AFAICT) as the OP's example.
>
>
Except that you are missing the point that I am trying to avoid the
potential overhead of the switch statement (which could/would be VERY
significant in a VM.)
>
|
|
0
|
|
|
|
Reply
|
blake (64)
|
1/6/2009 9:38:05 PM
|
|
On Jan 6, 9:34=A0pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
> This was one of the disappointments of C89: many people had assumed
> that enum types would be sufficiently constrained that a switch-on-enum
> would not need such a check.
You could just add
default: i =3D i++;
as the last case. That would allow the compiler to remove the check
(because if the check fails, behaviour of this code would be
undefined).
|
|
0
|
|
|
|
Reply
|
christian.bau1 (402)
|
1/6/2009 10:34:11 PM
|
|
In article <db76919e-d635-4aeb-9ce7-986ca4254d7a@i20g2000prf.googlegroups.com>,
christian.bau <christian.bau@cbau.wanadoo.co.uk> wrote:
>> This was one of the disappointments of C89: many people had assumed
>> that enum types would be sufficiently constrained that a switch-on-enum
>> would not need such a check.
>You could just add
>
> default: i = i++;
>
>as the last case. That would allow the compiler to remove the check
Unfortunately it would also allow the compiler to do various other
things :-)
In practice, we resorted to editing the assembler output of the
compiler to remove the check. It produced, IIRC, a speedup of about
10%, which is certainly worthwhile when using C to implement another
programming language.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
|
|
0
|
|
|
|
Reply
|
richard91 (3683)
|
1/6/2009 11:02:32 PM
|
|
On Jan 6, 5:34=A0pm, "christian.bau" <christian....@cbau.wanadoo.co.uk>
wrote:
> On Jan 6, 9:34=A0pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
>
> > This was one of the disappointments of C89: many people had assumed
> > that enum types would be sufficiently constrained that a switch-on-enum
> > would not need such a check.
>
> You could just add
>
> =A0 =A0 default: i =3D i++;
>
> as the last case. That would allow the compiler to remove the check
> (because if the check fails, behaviour of this code would be
> undefined).
I do know that the MS compiler provides an __assume() extension that
lets you tell the compiler something that is absolutely known to be
true, in hopes that you can give it a little more info for
optimizations.
You can use it to eliminate the default block of a switch statement
(this is, in fact, their example usage of __assume):
switch (value) {
case ...: ...;
case ...: ...;
default: __assume(0);
}
I don't know if other compilers have similar extensions. I think I've
used __assume() exactly once, though, and not in a serious project.
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/6/2009 11:04:27 PM
|
|
On Jan 6, 3:37=A0pm, Lew Pitcher <lpitc...@teksavvy.com> wrote:
> On January 6, 2009 15:05, in comp.lang.c, user923005 (dcor...@connx.com)
> wrote:
>
>
>
> > On Jan 6, 9:13=A0am, Blake McBride <bl...@mcbride.name> wrote:
> >> Greetings,
>
> >> I am a long-time C programmer (close to 30 years) with very little C++
> >> experience. =A0I don't keep up with the standards process but there ar=
e
> >> two features that I've long thought needed. =A0It might be that C++
> >> already has these features or that the upcoming standards for C or C++
> >> have these features. =A0I suppose I'm just asking and if they are not
> >> there already, I'm suggesting their addition. =A0They are as follows:
>
> >> 1. =A0Computed goto
>
> >> It would be very useful to have a computed goto. =A0This would involve=
two
> >> things. =A0First you should be able to use labels as read-only variabl=
es.
> >> Second, you should be able to branch assign the label to an array and
> >> branch to it via indexing into the array as follows:
>
> >> lbl1:
> >> ...
> >> lbl2:
> >> ...
> >> void *labels[] =3D {lbl1, lbl2};
>
> >> goto labels[x];
>
> >> The labels should not have to appear before the assignment, and there
> >> should be a way of making this runtime assignment to labels once.
>
> > Just use an array of function pointers.
>
> [snip]
>
> A dumb question: Aren't "computed gotos" already implicit in the language=
,
> in that they could be easily implemented (at a source-code level) using
> already-existing language constructs? =A0I'm thinking of something like..=
..
>
> =A0 {
> =A0 =A0 lbl: /* do something */
>
> =A0 =A0 lbl2: /* do something else */
>
> =A0 =A0 switch (x)
> =A0 =A0 {
> =A0 =A0 =A0 case 0: goto lbl1;
> =A0 =A0 =A0 case 1: goto lbl2;
> =A0 =A0 }
> =A0 }
> which gives the same results (AFAICT) as the OP's example.
Good idea, that gives about the same results. The one thing it's
missing is the ability to modify which label a given case jumps to at
run time (something I'm not sure I'm comfortable with in general,
anything that gives *nix kernel developers a means to obfuscate their
code even more doesn't really sit well with me >:-).
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/6/2009 11:11:12 PM
|
|
On Jan 6, 8:33=A0pm, Keith Thompson wrote:
> If you want to propose changes to future versions of the C or C++
> standard, the best place to start is comp.std.c and/or comp.std.c++.
At least group comp.std.c++ is moderated, so you must always prove (to
unknown man) your have rights to write. This is annoying thing. More,
there is "comp.lang.c++.moderated", where you can easy discuss "pure C+
+ questions".
|
|
0
|
|
|
|
Reply
|
grizlyk1 (428)
|
1/7/2009 4:44:13 AM
|
|
On Jan 6, 9:14=A0pm, "jason.cipri...@gmail.com" wrote:
> C++ does not place performance requirements on the code that compilers
> generate. ...
> That is simply outside the scope of the language.
This is not performance question. We are speaking here about usage of
something, that can not be reached by languge in other way. "VLA" in
stack, "moveable data type" are other examples of the "something". As
for me, i no need the futures with goto, but if any want why not?
Other question is "how to set the properties under compier control",
to avoid raw usage of pointers, to make auto-fill of jump array.
|
|
0
|
|
|
|
Reply
|
grizlyk1 (428)
|
1/7/2009 5:06:03 AM
|
|
On Jan 7, 12:06=A0am, Grizlyk <grizl...@yandex.ru> wrote:
> On Jan 6, 9:14=A0pm, "jason.cipri...@gmail.com" wrote:
>
> > C++ does not place performance requirements on the code that compilers
> > generate. ...
> > That is simply outside the scope of the language.
>
> This is not performance question.
It *is* a performance question -- the OP's motivation for these
changes are entirely performance related. Performance is outside the
scope of the language, however, and even if the proposed changes were
adopted they would not be guaranteed to solve the problem they were
intended to solve (which was, performance issues).
> We are speaking here about usage of
> something, that can not be reached by languge in other way.
There were two proposed additions: computed gotos and function gotos.
Both of these are already possible with C and C++. Computed gotos can
be accomplished by using function pointers. Function gotos can be
accomplished by simply calling functions. Both of these achieve the
same end effect as the proposed changes. The difference is that these
approaches do not meet the OP's performance requirements.
> "VLA" in
> stack, "moveable data type" are other examples of the "something".
Neither VLAs nor "movable data types" were mentioned in the proposed
additions.
> As
> for me, i no need the futures with goto, but if any want why not?
Avoiding feature bloat is a compelling reason. If a new feature is
added to the language it should be sufficiently motivated and provide
features and guarantees that are not otherwise available. I agree with
you that the proposed changes would not cause any direct harm, but I
feel they would not provide a significant benefit either (mainly
because the standard can not provide the performance guarantees that
the OP seeks).
> Other question is "how to set the properties under compier control",
> to avoid raw usage of pointers, to make auto-fill of jump array.
Apologies if I'm misunderstanding your question (please rephrase it if
I am). The computed gotos, as suggested, do not require usage of raw
pointers. Instead, you would initialize the jump array with standard
goto labels (something similar is already a GCC extension, as
mentioned by others), e.g.:
void f (void) {
jump_dest jmps[] =3D { label1, label2, label3 };
goto jmps[rand() % 3];
label1:
// some code
return;
label2:
// some code
return
label3:
// some code
return
}
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/7/2009 5:45:39 AM
|
|
On Jan 6, 12:13=A0pm, Blake McBride <bl...@mcbride.name> wrote:
> 1. =A0Computed goto
[snip]
> The labels should not have to appear before the assignment, and there
> should be a way of making this runtime assignment to labels once.
I would assume that this is easier said than done but I am not an
expert on C++ compiling. Would you find forward declarations of labels
acceptable? E.g.:
void somewhere () {
// Forward declarations.
jump_label lbl1;
jump_label lbl2;
computed_goto_t labels[] =3D {lbl1, lbl2};
goto labels[x];
lbl1:
...
lbl2:
...
}
> 2. =A0Function goto instead of call
>
> When you call a function (typically) a call stack is created. =A0When the
> function returns the return goes to the calling function. =A0Some C
> compilers can do tail call elimination in certain circumstances but it
> is never guaranteed to support tail calls in all obvious conditions. =A0C
> is often used as an intermediate language for other languages compilers
> (like Lisp, Scheme, etc.). =A0Languages such as Scheme require tail call
> optimization. =A0Coding in assembler is very un-portable. =A0Using C as a
> portable assembler is great but not being able to eliminate tail calls
> is a big problem. =A0Scheme compilers often use a set of tricks to make C
> eliminate tail calls but these tricks are very slow compared to what is
> really needed.
>=A0If C had the ability to "goto" a function rather than
> "call" a function, other compiler writers can take advantage of this
> feature to give their languages tail call elimination without costly
> tricks or having to resort to assembler.
In C++, say you have the following:
class MyClass {
public:
~MyClass () { }
};
void function1 () {
do_things();
}
void function2 () {
MyClass mc;
do_some_stuff();
function_goto function1;
}
In this behavior, where would you have the destructor of mc be called?
Particularly, would it be before or after the call to do_things()?
If you would have function2's stack unwinding occur at the
function_goto, then means function_goto has significantly different
semantics than a simple function call. Is this OK? The way you
described it made it sound like you intended it to behave as a drop-in
replacement for a simple function call.
If you would have function2's stack unwinding occur when function1
returns, this significantly complicates the implementation of
function1 and/or function_goto, as function1 must now conditionally
unwind function2 stack constructs when it returns depending on whether
or not it was entered from function2.
It may be possible to solve these problems by placing a constraint on
the use of function_goto and only allowing it to jump out of scopes
that do not require objects to be cleaned up during stack unwinding.
Personally I find this constraint too limiting, but would you find it
acceptable?
Here is another example of a troublesome case:
void function1 () {
}
void function2 () {
try {
function_goto function1;
} catch (...) {
}
}
What happens here? Do exceptions thrown by function1 get handled in
function2, or do they escape the try...catch block? If they escape,
how far do they escape? E.g., consider:
void function2 () {
try {
try {
function_goto function1;
} catch (...) {
// caught here?
}
} catch (...) {
// caught here?
}
}
// unhandled?
If they go unhandled, can only the caller of function2() catch
exceptions thrown by function1()?
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/7/2009 6:01:25 AM
|
|
On Jan 7, 1:01=A0am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> In this behavior, where would you have the destructor of mc be called?
This should read "in this example" not "in this behavior".
Jason
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/7/2009 6:03:45 AM
|
|
christian.bau wrote:
> On Jan 6, 9:34=A0pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
> > This was one of the disappointments of C89: many people had assumed
> > that enum types would be sufficiently constrained that a switch-on-enum
> > would not need such a check.
>
> You could just add
>
> default: i = i++;
>
> as the last case. That would allow the compiler to remove the check
> (because if the check fails, behaviour of this code would be
> undefined).
Hahah, maintenance programmers would love that!
switch ( x )
{
...
default:
int i = i++; // 10% performance increase. DO NOT REMOVE!
}
That's about as close as you can get to a magic line.
|
|
0
|
|
|
|
Reply
|
blargg.h4g (301)
|
1/7/2009 6:09:29 AM
|
|
On Jan 7, 1:09=A0am, blargg....@gishpuppy.com (blargg) wrote:
> Hahah, maintenance programmers would love that!
>
> =A0 =A0 switch ( x )
> =A0 =A0 {
> =A0 =A0 ...
> =A0 =A0 default:
> =A0 =A0 =A0 =A0 int i =3D i++; // 10% performance increase. DO NOT REMOVE=
!
> =A0 =A0 }
>
> That's about as close as you can get to a magic line.
I think I finally found a signature, hehe.
--
default:
int i =3D i++; // 10% performance increase. DO NOT REMOVE!
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/7/2009 6:23:33 AM
|
|
Jeff Schwab wrote:
> red floyd wrote:
>> On Jan 6, 10:16 am, "jason.cipri...@gmail.com"
>> <jason.cipri...@gmail.com> wrote:
>>> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
>>>
>>>> Case statements were *invented* to be turned into index-and-branch.
>>> Incidentally, since you mention it, I did observe on at least one
>>> occasion MSVC turning a switch statement into a jump table. I have a
>>> hard time reproducing that behavior at will, though. IIRC it was in a
>>> fairly old version of the compiler, VC 4.0 maybe.
>>
>>
>> Heck, on an old Z8000 ZEUS compiler, switch statements were converted
>> into jump tables. This was back in the mid-80s.
>
> I wonder whether any modern compilers turn if/else trees into jump
> tables (when logically equivalent).
Not only that, but the Z8000 compiler did jump tables for non-contiguous
switch values, by iterating through two tables simultaneously -- a value
table and a jump table. Of course, it helped that the Z8000 had
hardware support for that (CPIR instruction)
|
|
0
|
|
|
|
Reply
|
no.spam.here1 (227)
|
1/7/2009 6:56:36 AM
|
|
On Jan 6, 12:37=A0pm, Lew Pitcher <lpitc...@teksavvy.com> wrote:
> On January 6, 2009 15:05, in comp.lang.c, user923005 (dcor...@connx.com)
> wrote:
>
>
>
>
>
> > On Jan 6, 9:13=A0am, Blake McBride <bl...@mcbride.name> wrote:
> >> Greetings,
>
> >> I am a long-time C programmer (close to 30 years) with very little C++
> >> experience. =A0I don't keep up with the standards process but there ar=
e
> >> two features that I've long thought needed. =A0It might be that C++
> >> already has these features or that the upcoming standards for C or C++
> >> have these features. =A0I suppose I'm just asking and if they are not
> >> there already, I'm suggesting their addition. =A0They are as follows:
>
> >> 1. =A0Computed goto
>
> >> It would be very useful to have a computed goto. =A0This would involve=
two
> >> things. =A0First you should be able to use labels as read-only variabl=
es.
> >> Second, you should be able to branch assign the label to an array and
> >> branch to it via indexing into the array as follows:
>
> >> lbl1:
> >> ...
> >> lbl2:
> >> ...
> >> void *labels[] =3D {lbl1, lbl2};
>
> >> goto labels[x];
>
> >> The labels should not have to appear before the assignment, and there
> >> should be a way of making this runtime assignment to labels once.
>
> > Just use an array of function pointers.
>
> [snip]
>
> A dumb question: Aren't "computed gotos" already implicit in the language=
,
> in that they could be easily implemented (at a source-code level) using
> already-existing language constructs? =A0I'm thinking of something like..=
..
>
> =A0 {
> =A0 =A0 lbl: /* do something */
>
> =A0 =A0 lbl2: /* do something else */
>
> =A0 =A0 switch (x)
> =A0 =A0 {
> =A0 =A0 =A0 case 0: goto lbl1;
> =A0 =A0 =A0 case 1: goto lbl2;
> =A0 =A0 }
> =A0 }
> which gives the same results (AFAICT) as the OP's example.
Quite likely it is what the O.P. meant.
In Fortran, there is also the ability to modify the label in a
variable that you are jumping to. Of course, that's Icky[tm].
If the O.P. needs to write a state machine, there are tools to help
with that.
|
|
0
|
|
|
|
Reply
|
dcorbit (2696)
|
1/7/2009 8:51:04 AM
|
|
On Jan 6, 6:26 pm, Willem <wil...@stack.nl> wrote:
> Blake McBride wrote:
> > The use of this feature is in virtual machines. VM's
> > typically process op-codes. These op-codes can be treated
> > as indexes into the branch array. This would be very, very
> > fast. I know C can use arrays of function pointers that can
> > be indexed into and executed but the problem is that you
> > have the (often huge) function overhead associated with each
> > instruction. The other probable response is a case
> > statement. The problem is that a case statement must do a
> > lot of time-consuming compares in order get to the correct
> > case. In index and branch is much faster. (I know case
> > statement are optimized to a point but I don't think they
> > are guaranteed to be as fast as an index and branch).
> Case statements were *invented* to be turned into
> index-and-branch. Do you agree that computed gotos would be a
> moot point if compilers would *guarantee* that a case
> statement (perhaps with some restrictions, such as only with
> successive integers) would be turned into an index-and-branch?
> Then why not ask for such a guarantee? That would be ten
> times easier.
Neither have the slightest chance. Computed goto's, because
they are universally recognized as a misfeature, only useful for
obfuscation. And requirements on *how* a compiler should
implement a feature are not within the realm of the standard;
one basic principle is that anything the compiler does is fine,
as long as the observable behavior of the program is maintained.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:10:59 AM
|
|
On Jan 6, 7:16 pm, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
> > Case statements were *invented* to be turned into
> > index-and-branch.
> Incidentally, since you mention it, I did observe on at least
> one occasion MSVC turning a switch statement into a jump
> table. I have a hard time reproducing that behavior at will,
> though. IIRC it was in a fairly old version of the compiler,
> VC 4.0 maybe.
I would expect most compilers use a jump table to implement
switch when the cases form a dense set, and this is the fastest
solution for the underlying hardware. (G++, Sun CC and VC++ all
do, at least in the versions I have handy.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:26:09 AM
|
|
On Jan 7, 7:56 am, red floyd <no.spam.h...@example.com> wrote:
> Jeff Schwab wrote:
> > red floyd wrote:
> >> On Jan 6, 10:16 am, "jason.cipri...@gmail.com"
> >> <jason.cipri...@gmail.com> wrote:
> >>> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
> >>>> Case statements were *invented* to be turned into index-and-branch.
> >>> Incidentally, since you mention it, I did observe on at
> >>> least one occasion MSVC turning a switch statement into a
> >>> jump table. I have a hard time reproducing that behavior
> >>> at will, though. IIRC it was in a fairly old version of
> >>> the compiler, VC 4.0 maybe.
> >> Heck, on an old Z8000 ZEUS compiler, switch statements were
> >> converted into jump tables. This was back in the mid-80s.
> > I wonder whether any modern compilers turn if/else trees
> > into jump tables (when logically equivalent).
> Not only that, but the Z8000 compiler did jump tables for
> non-contiguous switch values, by iterating through two tables
> simultaneously -- a value table and a jump table. Of course,
> it helped that the Z8000 had hardware support for that (CPIR
> instruction)
Back when I was working on compilers (and the Z8000 was still
around), the usual rule for handling switch statements was:
if ( "dense" )
generate bounds check and jump table
else if ( "few entries" )
generate linear lookup table, using index into jump
table
else
generate inline binary search.
In this context, "dense" would mean that the difference between
the largest and the smallest entries was smaller than 2 or 3
times the total number of entires (the exact cut-off point
varied), and "few entries" depended on the hardware---for
machines with hardware supported linear search (like the 8086 I
was working on at the time), this value could be quite high.
Some (not a lot) of the compilers would also look for dense
subsets of entries, and use a lookup table for them.
For modern machines, where an indirect jump could cause problems
with branch prediction, I expect that the binary search is used
far more often, perhaps even with dense switchs, provided there
aren't too many entries.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:33:43 AM
|
|
On Jan 6, 10:34 pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
> In article <1231272028.168873@news1nwk>,
> Eric Sosman <Eric.Sos...@sun.com> wrote:
> >You'll typically get at least one comparison to see whether
> >the index is in the range of covered cases.
> This was one of the disappointments of C89: many people had
> assumed that enum types would be sufficiently constrained that
> a switch-on-enum would not need such a check.
> >IMHO the opportunity for optimization is pretty slight unless
> >*very* little work is being done in each `case'
> But there is an important use case in which this is true:
> implementing virtual machines.
I don't think so. If performance isn't an issue, the virtual
machine will just use a table of pointers to functions. If it
is an issue, the virtual machine will compile larger blocks to
machine code, using all of the standard optimization techniques
for this, including (usually) profiling information gathered
when the block was executed earlier.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:37:12 AM
|
|
On Jan 7, 12:02 am, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
> In article
> <db76919e-d635-4aeb-9ce7-986ca4254...@i20g2000prf.googlegroups.com>,
> christian.bau <christian....@cbau.wanadoo.co.uk> wrote:
> >> This was one of the disappointments of C89: many people had
> >> assumed that enum types would be sufficiently constrained
> >> that a switch-on-enum would not need such a check.
> >You could just add
> > default: i =3D i++;
> >as the last case. That would allow the compiler to remove the check
> Unfortunately it would also allow the compiler to do various other
> things :-)
> In practice, we resorted to editing the assembler output of
> the compiler to remove the check. It produced, IIRC, a
> speedup of about 10%, which is certainly worthwhile when using
> C to implement another programming language.
A "computed goto" or a goto through a variable would be useful
when using C as an intermediate language, output from a compiler
front end. Given its wide availability today, however, I expect
most compiler front-ends would prefer GCC's RTL. (But I've not
been active in compilers for a while, so I'm not sure.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:43:56 AM
|
|
On Jan 7, 7:09 am, blargg....@gishpuppy.com (blargg) wrote:
> christian.bau wrote:
> > On Jan 6, 9:34=3DA0pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote:
> > > This was one of the disappointments of C89: many people
> > > had assumed that enum types would be sufficiently
> > > constrained that a switch-on-enum would not need such a
> > > check.
> > You could just add
> > default: i =3D i++;
> > as the last case. That would allow the compiler to remove
> > the check (because if the check fails, behaviour of this
> > code would be undefined).
> Hahah, maintenance programmers would love that!
> switch ( x )
> {
> ...
> default:
> int i =3D i++; // 10% performance increase. DO NOT REMOVE!
> }
> That's about as close as you can get to a magic line.
Yes. It would require some documentation:-). I'd also worry
about any compiler which recognized it as undefined behavior
(and so could provide the performance benefit) also outputting
a warning about it.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/7/2009 10:46:08 AM
|
|
In article <04fdc26f-1ac1-470f-a126-602b97a8cd7c@r10g2000prf.googlegroups.com>,
James Kanze <james.kanze@gmail.com> wrote:
>> But there is an important use case in which this is true:
>> implementing virtual machines.
>I don't think so. If performance isn't an issue, the virtual
>machine will just use a table of pointers to functions. If it
>is an issue, the virtual machine will compile larger blocks to
>machine code
Switching from interpreting virtual machine code in portable C to
generating native code is a big step. Obviously the machine code
itself has to vary from system to system, but so does support code for
loading it, flushing caches, and so on. The maintenance burden is
much higher. This is all very well if you're a large commercial
company, but for many of us getting a 10-20% speedup in a portable
version is quite worthwhile.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
|
|
0
|
|
|
|
Reply
|
richard91 (3683)
|
1/7/2009 11:01:36 AM
|
|
James Kanze wrote:
> On Jan 6, 7:16 pm, "jason.cipri...@gmail.com"
> <jason.cipri...@gmail.com> wrote:
>> On Jan 6, 12:26 pm, Willem <wil...@stack.nl> wrote:
>
>>> Case statements were *invented* to be turned into
>>> index-and-branch.
>
>> Incidentally, since you mention it, I did observe on at least
>> one occasion MSVC turning a switch statement into a jump
>> table. I have a hard time reproducing that behavior at will,
>> though. IIRC it was in a fairly old version of the compiler,
>> VC 4.0 maybe.
>
> I would expect most compilers use a jump table to implement
> switch when the cases form a dense set, and this is the fastest
> solution for the underlying hardware. (G++, Sun CC and VC++ all
> do, at least in the versions I have handy.)
You're forgetting the need to validate the switch index, taking valuable
machine instuctions.
And typically (for dispatching bytecode operators for example), the switch
will be part of a loop.
With gcc on x86, it seemed to need about 5 machine instructions overhead per
bytecode (including stepping the 'instruction pointer'). With the highest
optimisation level, that went up 6 (because it seemed to opimise for space).
When I implement this in ASM, I can get it down to 2 machine instructions
per bytecode.
With a goto and label variable (goto *p or some such syntax), (and with each
case: body ending with such a goto instead of jumping back to the top of the
loop), I'd imagine C could come close to that.
--
Bartc
|
|
0
|
|
|
|
Reply
|
bartc (783)
|
1/7/2009 11:55:43 AM
|
|
In article <3L09l.16467$Sp5.9168@text.news.virginmedia.com>,
Bartc <bartc@freeuk.com> wrote:
>You're forgetting the need to validate the switch index, taking valuable
>machine instuctions.
One way around this is to have cases for all possible values. This is
actually practical for many virtual machines, using an unsigned char
for the opcode.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
|
|
0
|
|
|
|
Reply
|
richard91 (3683)
|
1/7/2009 2:06:17 PM
|
|
On Jan 6, 4:38=A0pm, Blake McBride <bl...@mcbride.name> wrote:
> Lew Pitcher wrote:
> > A dumb question: Aren't "computed gotos" already implicit in the langua=
ge,
> > in that they could be easily implemented (at a source-code level) using
> > already-existing language constructs? =A0I'm thinking of something like=
....
>
> > =A0 {
> > =A0 =A0 lbl: /* do something */
>
> > =A0 =A0 lbl2: /* do something else */
>
> > =A0 =A0 switch (x)
> > =A0 =A0 {
> > =A0 =A0 =A0 case 0: goto lbl1;
> > =A0 =A0 =A0 case 1: goto lbl2;
> > =A0 =A0 }
> > =A0 }
> > which gives the same results (AFAICT) as the OP's example.
>
> Except that you are missing the point that I am trying to avoid the
> potential overhead of the switch statement (which could/would be VERY
> significant in a VM.)
Specifically, the overhead you are trying to avoid, assuming that the
compiler generates a jump table from the switch, is the overhead of a
range check.
1. No language change would guarantee that indexing into a computed
goto array doesn't perform a range check (although it's unlikely a
compiler would implement it as such, there's nothing stopping it from
doing so).
2. Some compilers have extensions that can help you optimize that
away (e.g. __assume() in MSVC). You can take advantage of compiler-
specific extensions (note that *all* optimizations are compiler-
specific) when available to get the performance you need.
I've added comp.lang.c back to the reply list.
|
|
0
|
|
|
|
Reply
|
jason.cipriani (596)
|
1/7/2009 2:10:27 PM
|
|
jason.cipriani@gmail.com wrote:
> On Jan 6, 12:13 pm, Blake McBride <bl...@mcbride.name> wrote:
>> 2. Function goto instead of call
>>
>> When you call a function (typically) a call stack is created. When the
>> function returns the return goes to the calling function. Some C
>> compilers can do tail call elimination in certain circumstances but it
>> is never guaranteed to support tail calls in all obvious conditions. C
>> is often used as an intermediate language for other languages compilers
>> (like Lisp, Scheme, etc.). Languages such as Scheme require tail call
>> optimization. Coding in assembler is very un-portable. Using C as a
>> portable assembler is great but not being able to eliminate tail calls
>> is a big problem. Scheme compilers often use a set of tricks to make C
>> eliminate tail calls but these tricks are very slow compared to what is
>> really needed.
>
>> If C had the ability to "goto" a function rather than
>> "call" a function, other compiler writers can take advantage of this
>> feature to give their languages tail call elimination without costly
>> tricks or having to resort to assembler.
>
> In C++, say you have the following:
>
>
> class MyClass {
> public:
> ~MyClass () { }
> };
>
> void function1 () {
> do_things();
> }
>
> void function2 () {
> MyClass mc;
> do_some_stuff();
> function_goto function1;
> }
>
>
> In this behavior, where would you have the destructor of mc be called?
> Particularly, would it be before or after the call to do_things()?
>
> If you would have function2's stack unwinding occur at the
> function_goto, then means function_goto has significantly different
> semantics than a simple function call. Is this OK? The way you
> described it made it sound like you intended it to behave as a drop-in
> replacement for a simple function call.
>
> If you would have function2's stack unwinding occur when function1
> returns, this significantly complicates the implementation of
> function1 and/or function_goto, as function1 must now conditionally
> unwind function2 stack constructs when it returns depending on whether
> or not it was entered from function2.
>
> It may be possible to solve these problems by placing a constraint on
> the use of function_goto and only allowing it to jump out of scopes
> that do not require objects to be cleaned up during stack unwinding.
> Personally I find this constraint too limiting, but would you find it
> acceptable?
>
> Here is another example of a troublesome case:
>
>
> void function1 () {
> }
>
> void function2 () {
> try {
> function_goto function1;
> } catch (...) {
> }
> }
>
>
> What happens here? Do exceptions thrown by function1 get handled in
> function2, or do they escape the try...catch block? If they escape,
> how far do they escape? E.g., consider:
>
>
> void function2 () {
> try {
> try {
> function_goto function1;
> } catch (...) {
> // caught here?
> }
> } catch (...) {
> // caught here?
> }
> }
> // unhandled?
>
>
> If they go unhandled, can only the caller of function2() catch
> exceptions thrown by function1()?
>
>
> Jason
I suggest the 'function_goto" semantics act as though the function using
"function_goto" essentially ends and cleans up before doing the goto.
Blake McBride
|
|
0
|
|
|
|
Reply
|
blake (64)
|
1/7/2009 2:26:42 PM
|
|
red floyd wrote:
> Jeff Schwab wrote:
>> I wonder whether any modern compilers turn if/else trees into jump
>> tables (when logically equivalent).
>
> Not only that, but the Z8000 compiler did jump tables for non-contiguous
> switch values, by iterating through two tables simultaneously -- a value
> table and a jump table. Of course, it helped that the Z8000 had
> hardware support for that (CPIR instruction)
So, where can I get me one o' them Z8000 beasties?
Some companies do stamp out old cores in new microcontrollers; I wonder
whether Z8000 is still in use. It seems like the high-end cores of
yesteryear are just place-able macros nowadays, like any other block of
random logic.
|
|
0
|
|
|
|
Reply
|
jeff34 (1594)
|
1/7/2009 5:03:44 PM
|
|
jason.cipriani@gmail.com wrote:
> On Jan 7, 12:06 am, Grizlyk <grizl...@yandex.ru> wrote:
>> On Jan 6, 9:14 pm, "jason.cipri...@gmail.com" wrote:
>>
>>> C++ does not place performance requirements on the code that compilers
>>> generate. ...
>>> That is simply outside the scope of the language.
>> This is not performance question.
>
> It *is* a performance question -- the OP's motivation for these
> changes are entirely performance related. Performance is outside the
> scope of the language, however, and even if the proposed changes were
> adopted they would not be guaranteed to solve the problem they were
> intended to solve (which was, performance issues).
You know, I've kept my mouth quiet in this repeated comment and I think
it's time to weigh in. You seem to be implying that language
specifications and performance expectations are unrelated. I strongly
disagree. The fact that C doesn't check array bounds is not just a
language specification, it is also most definitely a performance issue
and performance expectation. In fact, most often there is a strong
relationship between language specification considerations and
performance expectations. I could go on for days with examples. (What
about virtual vs. non-virtual methods in C++? .......)
When a language or language feature is developed or improved,
performance issues are ALWAYS a major consideration. The two are
definitely linked.
Blake McBride
|
|
0
|
|
|
|
Reply
|
blake (64)
|
1/8/2009 12:49:02 AM
|
|
Blake McBride <blake@mcbride.name> writes:
[...]
> You know, I've kept my mouth quiet in this repeated comment and I
> think it's time to weigh in. You seem to be implying that language
> specifications and performance expectations are unrelated. I strongly
> disagree. The fact that C doesn't check array bounds is not just a
> language specification, it is also most definitely a performance issue
> and performance expectation.
[...]
Ah, but C doesn't *not* check array bounds. In other words, going
beyond an array bound invokes undefined behavior. This means that an
implementation is free to do anything it likes, including either
ignoring the error or checking for it.
There are C implementations that do array bound checking.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
|
|
0
|
|
|
|
Reply
|
kst-u (21464)
|
1/8/2009 1:11:24 AM
|
|
On Tue, 06 Jan 2009 11:13:08 -0600, Blake McBride
<blake@mcbride.name> wrote:
>
>Greetings,
>
>I am a long-time C programmer (close to 30 years) with very little C++
>experience. I don't keep up with the standards process but there are
>two features that I've long thought needed. It might be that C++
>already has these features or that the upcoming standards for C or C++
>have these features. I suppose I'm just asking and if they are not
>there already, I'm suggesting their addition. They are as follows:
>
>1. Computed goto
Many languages originally had this; over time they abandoned it.
There may be a reason why. Think on that.
>
>2. Function goto instead of call
>
IMACO (In My Absolutely Correct Opinion) this is a good idea with
the proviso that you stay away from the word "goto" which is the
kiss of death. In a language or two I used the construct
return via blah(args);
(Make up whatever keyword floats your boat to replace "return
via".) The advantage is that it is now clear that the tail
recursion optimization applies.
I will add
3. Generic variable type
I would like a generic generic variable type similar to void *
pointers that be anything that is not a struct. In otherwords it
is large enough to hold a long, any kind of pointer, a long long
if you have them, etc. It is convertible with casting. Thus you
might have
generic T;
long number;
char * s;
T = number;
number = T;
T = s;
s = T;
You can get the same effect with a union and a lot of rubbishy
extra code but this would be a lot cleaner. For example the
linked code looks like this:
struct node {
struct node * link;
generic data;
};
Now it doesn't matter whether the data is numeric or pointers.
Richard Harter, cri@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
|
|
0
|
|
|
|
Reply
|
cri (1432)
|
1/8/2009 1:31:37 AM
|
|
"Richard Harter" <cri@tiac.net> wrote in message
news:49655258.545204953@text.giganews.com...
> On Tue, 06 Jan 2009 11:13:08 -0600, Blake McBride
> <blake@mcbride.name> wrote:
>>1. Computed goto
>
> Many languages originally had this; over time they abandoned it.
> There may be a reason why. Think on that.
> I will add
>
> 3. Generic variable type
>
> I would like a generic generic variable type similar to void *
> pointers that be anything that is not a struct. In otherwords it
> is large enough to hold a long, any kind of pointer, a long long
> if you have them, etc. It is convertible with casting. Thus you
> might have
>
> generic T;
> long number;
> char * s;
>
> T = number;
> number = T;
> T = s;
> s = T;
I think T would need a tag of some sort to remember what type it contains
(otherwise the use is limited).
But would the user have to interrogate the type, or would this be automatic?
If the latter, this could be a very useful feature but also quite high level
(maybe too much so) for C:
generic max(generic A, generic B) {
return A>=B ? A : B;
}
However, my experience of implementing variant types tells me this would be
quite difficult to get as efficient as dedicated types (although in this
case the possibilities are restricted to a small range of scalar types).
--
Bartc
|
|
0
|
|
|
|
Reply
|
bartc (783)
|
1/8/2009 2:48:53 AM
|
|
On Jan 7, 7:11=A0pm, Keith Thompson <ks...@mib.org> wrote:
> Ah, but C doesn't *not* check array bounds. =A0In other words, going
> beyond an array bound invokes undefined behavior. =A0This means that an
> implementation is free to do anything it likes, including either
> ignoring the error or checking for it.
While true, the basically unbounded (and exposed) pointers in C make
effective bounds checking exceptionally painful. Basically you end up
having to carry type information of the original object with each
pointer. So it essentially never happens in real code. For many
other languages, bounds checking caries a much smaller penalty.
|
|
0
|
|
|
|
Reply
|
robertwessel2 (1339)
|
1/8/2009 3:53:22 AM
|
|
On Jan 8, 2:11 am, Keith Thompson <ks...@mib.org> wrote:
> Blake McBride <bl...@mcbride.name> writes:
> [...]> You know, I've kept my mouth quiet in this repeated comment and I
> > think it's time to weigh in. You seem to be implying that language
> > specifications and performance expectations are unrelated. I strongly
> > disagree. The fact that C doesn't check array bounds is not just a
> > language specification, it is also most definitely a performance issue
> > and performance expectation.
> [...]
> Ah, but C doesn't *not* check array bounds. In other words, going
> beyond an array bound invokes undefined behavior. This means that an
> implementation is free to do anything it likes, including either
> ignoring the error or checking for it.
> There are C implementations that do array bound checking.
In fact, the C standard was carefully worded to allow bounds
checking, intentionally. The authors wanted it to be an option.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9590)
|
1/8/2009 9:37:26 AM
|
|
Keith Thompson wrote:
> Blake McBride <blake@mcbride.name> writes:
> [...]
>> You know, I've kept my mouth quiet in this repeated comment and I
>> think it's time to weigh in. You seem to be implying that language
>> specifications and performance expectations are unrelated. I strongly
>> disagree. The fact that C doesn't check array bounds is not just a
>> language specification, it is also most definitely a performance issue
>> and performance expectation.
> [...]
>
> Ah, but C doesn't *not* check array bounds. In other words, going
> beyond an array bound invokes undefined behavior. This means that an
> implementation is free to do anything it likes, including either
> ignoring the error or checking for it.
>
> There are C implementations that do array bound checking.
Got a place with a list?
|
|
0
|
|
|
|
Reply
|
gldncagrls (469)
|
1/9/2009 3:26:28 AM
|
|
Golden California Girls <gldncagrls@aol.com.mil> writes:
> Keith Thompson wrote:
[...]
>> There are C implementations that do array bound checking.
>
> Got a place with a list?
No, but I'm sure somebody else does.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
|
|
0
|
|
|
|
Reply
|
kst-u (21464)
|
1/9/2009 6:28:38 AM
|
|
On Thu, 08 Jan 2009 02:48:53 GMT, "Bartc" <bartc@freeuk.com>
wrote:
>
>"Richard Harter" <cri@tiac.net> wrote in message
>news:49655258.545204953@text.giganews.com...
>> On Tue, 06 Jan 2009 11:13:08 -0600, Blake McBride
>> <blake@mcbride.name> wrote:
>
>>>1. Computed goto
>>
>> Many languages originally had this; over time they abandoned it.
>> There may be a reason why. Think on that.
>
>> I will add
>>
>> 3. Generic variable type
>>
>> I would like a generic generic variable type similar to void *
>> pointers that be anything that is not a struct. In otherwords it
>> is large enough to hold a long, any kind of pointer, a long long
>> if you have them, etc. It is convertible with casting. Thus you
>> might have
>>
>> generic T;
>> long number;
>> char * s;
>>
>> T = number;
>> number = T;
>> T = s;
>> s = T;
>
>I think T would need a tag of some sort to remember what type it contains
>(otherwise the use is limited).
>
>But would the user have to interrogate the type, or would this be automatic?
>If the latter, this could be a very useful feature but also quite high level
>(maybe too much so) for C:
>
>generic max(generic A, generic B) {
> return A>=B ? A : B;
>}
If A and B are pointers to different storage objects you have
just introduced undefined behaviour. We won't even think about A
and B being different types.
>
>However, my experience of implementing variant types tells me this would be
>quite difficult to get as efficient as dedicated types (although in this
>case the possibilities are restricted to a small range of scalar types).
My take on this is that a generic would be like a void * pointer;
you can't dereference it. In C one wouldn't want tags as a
required feature; however you could create a tag structure in the
same way that you would do with unions.
Some people think of unions as a space saving device; however it
can be thought of as a device for implementing polymorphic data.
The typical use I see is in data structures that act as
containers, e.g., linked lists, hash tables, trees, etc. If the
contained data is all of the same type, the container code can be
reused without modification.
If a container holds data of different kinds one could use a tag
system, e.g.,
struct polydata {
enum tagtype type;
generic datum;
};
Richard Harter, cri@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
|
|
0
|
|
|
|
Reply
|
cri (1432)
|
1/9/2009 6:02:44 PM
|
|
"Richard Harter" <cri@tiac.net> wrote in message
news:49677c0b.686951765@text.giganews.com...
> On Thu, 08 Jan 2009 02:48:53 GMT, "Bartc" <bartc@freeuk.com>
> wrote:
>>"Richard Harter" <cri@tiac.net> wrote in message
>>news:49655258.545204953@text.giganews.com...
>>> On Tue, 06 Jan 2009 11:13:08 -0600, Blake McBride
>>> <blake@mcbride.name> wrote:
>>> 3. Generic variable type
>>> I would like a generic generic variable type similar to void *
>>> pointers that be anything that is not a struct. In otherwords it
>>> is large enough to hold a long, any kind of pointer, a long long
>>> if you have them, etc. It is convertible with casting. Thus you
>>> might have
>>>
>>> generic T;
>>> long number;
>>> char * s;
>>>
>>> T = number;
>>> number = T;
>>> T = s;
>>> s = T;
>>
>>I think T would need a tag of some sort to remember what type it contains
>>(otherwise the use is limited).
>>
>>But would the user have to interrogate the type, or would this be
>>automatic?
>>If the latter, this could be a very useful feature but also quite high
>>level
>>(maybe too much so) for C:
>>
>>generic max(generic A, generic B) {
>> return A>=B ? A : B;
>>}
>
> If A and B are pointers to different storage objects you have
> just introduced undefined behaviour. We won't even think about A
> and B being different types.
I don't quite get your last sentence. Probably we are thinking about
somewhat different things. My example assumes generic is a tagged type, and
that A, B refer to the data within the type, not the data structure
representing the type (such as your polydata struct below).
In that case a runtime check would ensure they were compatible for ">=". And
even if A,B happened to be pointers, and ">=" was allowed for pointers to
different types, then the runtime system would know if this was legal or not
for that platform.
>
>>
>>However, my experience of implementing variant types tells me this would
>>be
>>quite difficult to get as efficient as dedicated types (although in this
>>case the possibilities are restricted to a small range of scalar types).
>
> My take on this is that a generic would be like a void * pointer;
> you can't dereference it. In C one wouldn't want tags as a
> required feature;
No? So how would any piece of code know what a generic contained/pointed to?
Without a tag, I can't see this being too useful, and you might as well just
use the longest int available.
> however you could create a tag structure in the
> same way that you would do with unions.
>
> Some people think of unions as a space saving device; however it
> can be thought of as a device for implementing polymorphic data.
> The typical use I see is in data structures that act as
> containers, e.g., linked lists, hash tables, trees, etc. If the
> contained data is all of the same type, the container code can be
> reused without modification.
OK, so you're thinking more along the lines of templates.
> If a container holds data of different kinds one could use a tag
> system, e.g.,
>
> struct polydata {
> enum tagtype type;
> generic datum;
> };
Yes, and my question was whether dealing with this would be done manually
(which is more in line with how C works) or automatically by the runtime
system (which is nicer but more suited to a scripting language).
--
Bartc
|
|
0
|
|
|
|
Reply
|
bartc (783)
|
1/9/2009 11:25:02 PM
|
|
On 9 Jan, 03:26, Golden California Girls <gldncag...@aol.com.mil>
wrote:
> Keith Thompson wrote:
>
> > Ah, but C doesn't *not* check array bounds. In other words, going
> > beyond an array bound invokes undefined behavior. This means that an
> > implementation is free to do anything it likes, including either
> > ignoring the error or checking for it.
>
> > There are C implementations that do array bound checking.
>
> Got a place with a list?
According to its man page Tiny C compiler offers an option for
array bounds checking. If I remember correctly Jacob Navia's
compiler offers the same but I don't remember if it does it in
conforming mode.
|
|
0
|
|
|
|
Reply
|
spibou (1037)
|
1/10/2009 4:48:26 PM
|
|
|
53 Replies
27 Views
(page loaded in 0.491 seconds)
Similiar Articles: truncate file - comp.lang.c++.moderatedIs there not need to truncate files? It can't be done in standard ... about features to be adopted by the C++ standard in the ... for the upcoming revision > of the standard has ... Checking for whether compiler supports C99 or C++0x - comp.lang ...Note that these features are experimental, and may ... Whether it will be included in the upcoming C++ standards ... Third, you first need to check if the BIOS ... Where did Fortran go? - comp.lang.fortran... until they are reminded that standard is nearly 20 years old. We really need ... conformance (where a lot of features need not ... more suitable to the needs, the upcoming ... bold upright Greek and vector - comp.text.texIf you want to go that way, you need a font that ... out all of the fonts that contain the required features ... Using a modern engine (XeTeX, LuaTeX) and the upcoming ... Sampling: What Nyquist Didn't Say, and What to Do About It - comp ...(you also need to consider which PDF version you ... documents are pdf 1.4, a very well-supported standard. ... basic -- the 3rd party packages add a lot more features ... HP LaserJet 3015 - comp.sys.mac.apps... to connect and use the printer features. To use the scanner >> and fax, you need to ... If the printer isn't shown as standard, go ... and=20 select the printer in the upcoming ... Wrap a function - comp.lang.pythonNo need to re-invent the wheel. I don't think Python ... -> Introduction and overview of IPython's features. ... I prefer Python since that has a great standard library ... RESIGNATION OF STEVE JOBS!! - comp.sys.mac.systemYou need this: <http://zapatopi.net/afdb.html ... ways of integrating their functionality into upcoming ... someone will come up with a hack that will let a standard ... Switch + Case - comp.lang.asm.x86In fact, HLA has a macro in the standard library that ... C++ 6.0 because Visual C++ 7.1 has additional features ... The upcoming AMD-64 architecture is a good example. 64 ... Wargame of the Year 2009 - Election - comp.sys.ibm.pc.games.war ...> Unlike you, I don't need to work for the philistines ... know - I try to make sure it's always either an upcoming ... with it ... after I disabled all those clever features ... Haas mill advice - comp.cad.solidworksIf you're mostly engraving, neither is needed. Perhaps ... and am getting back into Mastercam for an upcoming job. ... Indicating the ONE aligning hole aligns all the features ... C++11 - Wikipedia, the free encyclopediaPrefer introduction of new features through the standard library, rather than extending ... To access the latter constructor, the user will need to use the standard ... Upcoming features - Minecraft WikiFor the Pocket Edition, see Pocket Edition upcoming features. ... Added automagical downloading of standard sized ... sea and beside a waterfall). [citation needed] ... 7/26/2012 7:27:09 PM
|