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


Groups > comp.lang.c > #145807 > unrolled thread

in place swap of float types

Started by3queens@shabbyroad.com
First post2019-08-27 17:03 +0000
Last post2019-09-06 14:23 +0200
Articles 20 on this page of 63 — 20 participants

Back to article view | Back to comp.lang.c


Contents

  in place swap of float types 3queens@shabbyroad.com - 2019-08-27 17:03 +0000
    Re: in place swap of float types Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-08-27 19:22 +0000
      Re: in place swap of float types Andrew Smallshaw <andrews@sdf.org> - 2019-09-02 15:25 +0000
        Re: in place swap of float types Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-02 19:37 +0000
          Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-03 06:37 -0700
            Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-03 16:13 +0200
              Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-03 16:54 +0100
                Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-04 11:19 +0200
                  Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-04 02:35 -0700
                    Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-04 12:31 +0200
                  Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-04 12:12 +0100
                    Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-04 15:53 +0200
                      Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-04 07:17 -0700
                        Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-05 15:12 +0200
                          Re: in place swap of float types Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-09-05 21:11 +0100
                      Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-04 16:30 +0100
                        Re: in place swap of float types jadill33@gmail.com - 2019-09-04 10:26 -0700
                        Re: in place swap of float types Ike Naar <ike@iceland.freeshell.org> - 2019-09-05 06:00 +0000
                          Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-05 11:14 +0100
                        Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-05 14:54 +0200
                          Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-05 15:48 +0100
                            Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-06 10:35 +0200
                              Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-06 02:52 -0700
                                Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-06 13:18 +0200
                              Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-06 12:14 +0100
                                Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-06 15:08 +0200
                                  Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-06 06:23 -0700
                      Re: in place swap of float types Keith Thompson <kst-u@mib.org> - 2019-09-04 14:16 -0700
                        Re: in place swap of float types Bart <bc@freeuk.com> - 2019-09-04 22:42 +0100
                        Re: in place swap of float types Keith Thompson <kst-u@mib.org> - 2019-09-04 15:21 -0700
                        Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-05 15:15 +0200
                Re: in place swap of float types Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-09-04 08:05 -0600
                  Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-05 15:17 +0200
                    Re: in place swap of float types Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-09-05 20:28 -0600
                      Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-06 10:39 +0200
                        Re: in place swap of float types Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2019-09-06 08:11 -0600
                          Re: in place swap of float types scott@slp53.sl.home (Scott Lurndal) - 2019-09-06 18:31 +0000
            Re: in place swap of float types Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-09-04 19:02 +0000
        Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-02 22:16 +0200
    Re: in place swap of float types Robert Wessel <robertwessel2@yahoo.com> - 2019-08-27 17:59 -0500
      Re: in place swap of float types Richard Damon <Richard@Damon-Family.org> - 2019-08-27 17:45 -0700
      Re: in place swap of float types James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-27 20:48 -0400
        Re: in place swap of float types Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-09-03 06:17 -0700
      Re: in place swap of float types Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-08-28 02:09 +0100
      Re: in place swap of float types Siri Cruise <chine.bleu@yahoo.com> - 2019-08-27 21:26 -0700
      Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-08-28 09:22 +0200
      Re: in place swap of float types Andrey Tarasevich <andreytarasevich@hotmail.com> - 2019-08-28 16:36 -0700
    Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-08-28 09:36 +0200
      Re: in place swap of float types Bart <bc@freeuk.com> - 2019-08-28 12:02 +0100
        Re: in place swap of float types James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-28 05:08 -0700
          Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-08-28 05:26 -0700
          Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-08-28 14:40 +0200
          Re: in place swap of float types Keith Thompson <kst-u@mib.org> - 2019-08-28 13:01 -0700
      Re: in place swap of float types Philipp Klaus Krause <pkk@spth.de> - 2019-09-04 11:18 +0200
        Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-04 12:57 +0200
          Re: in place swap of float types Philipp Klaus Krause <pkk@spth.de> - 2019-09-04 13:24 +0200
    Re: in place swap of float types Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-05 08:18 +0200
      Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-05 15:19 +0200
        Re: in place swap of float types Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-05 16:18 +0200
          Re: in place swap of float types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-09-05 07:32 -0700
            Re: in place swap of float types Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-05 17:32 +0200
            Re: in place swap of float types David Brown <david.brown@hesbynett.no> - 2019-09-06 10:54 +0200
              Re: in place swap of float types Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-06 14:23 +0200

Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →


#146031

FromBart <bc@freeuk.com>
Date2019-09-05 15:48 +0100
Message-ID<tf9cF.443041$TW.79701@fx03.am4>
In reply to#146016
On 05/09/2019 13:54, David Brown wrote:
> On 04/09/2019 17:30, Bart wrote:

> Again, I am not saying "do it like C", or "don't make "swap" a built in
> function in your language".  I am merely encouraging that you think
> about it, and make considered decisions on a solid basis.  The focus
> should be on what is best for the programmer, the user of the language.
>   I feel that sometimes your focus is on showing off the simplicity of
> your compiler (adding features just because it is easy to do so), or on
> picking features precisely because C does not have that feature.  As
> justifications for features, these are not much better than saying you
> are adding the <^v> "min-max-swap" operator because you had a dream
> about it.  And I know you don't want to go there!

It is /because/ I have simple compilers, that will not have the 
optimisations found in some C and C++ compilers, that I place importance 
on having certain operations built-in. Rather than having to emulate 
them in unwieldy user-code then relying on optimisation to reduce it down.
> Depending on the expected usage domains of your language, I think it
> would be reasonable to relegate "xor" to a standard library function
> too, leaving the ^ symbol for a power operator, or re-direction operator
> (like in Pascal).

Bitwise XOR will always be in the core language. (I also have logical 
XOR -would be ^^ in C - but have never used it.)

When you see the same macros being defined in every other C program: 
STREQ, SWAP, MIN/MAX, ARRAYLEN, then those are good candidates to be 
part of either a core-language or core-runtime.

> To me, multiple assignment removes the need for a special "swap" feature
> for handling common cases.  I would want a "swap" function if it were
> designed to handle more complex types (such as handling "deep swaps" of
> trees or lists), and there the critical point is that it must be
> extendable and overloaded by user code - /not/ a compiler built-in fixed
> function.

In my languages, swap is not an operator (it doesn't return a value). In 
the static one, it will work with any compatible flat types, including 
arrays and structs. In the dynamic one, it will exchange objects of any 
complexity and depth (in all cases, it means swapping two 16-byte 
descriptors), and which do not need to be compatible.

I can't see the need for a user-overload. If somebody does, then they 
can create their own swap function. You can't deny everyone else a 
'swap' feature because 0.1% of people might want to override it sometime.

(In a version I was using in the 80s and 90s, I had a cruder feature in 
place of swap, but it was more general:

     stack a, b              # push a then b to the hardware stack
     unstack a, b            # pop a then b

This would also swap a and b, but all sorts of things were possible, 
including having other code between the two:

     stack a, b, c           # save a, b, c
     ....
     unstack c, b, a         # restore

But I eventually considered this too low-level a feature.)

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


#146052

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-06 10:35 +0200
Message-ID<qkt5p7$jdr$1@dont-email.me>
In reply to#146031
On 05/09/2019 16:48, Bart wrote:
> On 05/09/2019 13:54, David Brown wrote:
>> On 04/09/2019 17:30, Bart wrote:
> 
>> Again, I am not saying "do it like C", or "don't make "swap" a built in
>> function in your language".  I am merely encouraging that you think
>> about it, and make considered decisions on a solid basis.  The focus
>> should be on what is best for the programmer, the user of the language.
>>   I feel that sometimes your focus is on showing off the simplicity of
>> your compiler (adding features just because it is easy to do so), or on
>> picking features precisely because C does not have that feature.  As
>> justifications for features, these are not much better than saying you
>> are adding the <^v> "min-max-swap" operator because you had a dream
>> about it.  And I know you don't want to go there!
> 
> It is /because/ I have simple compilers, that will not have the
> optimisations found in some C and C++ compilers, that I place importance
> on having certain operations built-in. Rather than having to emulate
> them in unwieldy user-code then relying on optimisation to reduce it down.

If you give the compiler a built-in, it will generate better object code
for source using that one feature.  If you give the compiler an
optimisation, it will generate better object code for /all/ source code.

Look at how C++ handles this.  (Look at the high level ideas - I am not
suggesting you copy the syntax :-) ).  Features are added to the core
language to give wide abilities - details and individual features are
put in the library.  This gives maximal flexibility, making it
(relatively) easy to make changes, and the language features allow a
wide range of library functions to be made.  It avoids duplication of
the work.  And nothing stops you having the library implementation
delegating particular functions to built-ins for efficiency.


I realise you have your priorities, and your finite time, and you are
writing a one-man compiler for a one-man language.  So you will pick a
different balance than might be chosen for a more general language.  But
if you dream of moving it beyond a personal project, please don't hobble
the language at this stage.  We have more than enough oddities in
programming languages because the design made sense when the project was
small.

>> Depending on the expected usage domains of your language, I think it
>> would be reasonable to relegate "xor" to a standard library function
>> too, leaving the ^ symbol for a power operator, or re-direction operator
>> (like in Pascal).
> 
> Bitwise XOR will always be in the core language. (I also have logical
> XOR -would be ^^ in C - but have never used it.)
> 
> When you see the same macros being defined in every other C program:
> STREQ, SWAP, MIN/MAX, ARRAYLEN, then those are good candidates to be
> part of either a core-language or core-runtime.

These are not macros in every other C program - you exaggerate.  But
certainly many programs have things like that.  I'd fully support
putting them in a standard library ("core-runtime", if you prefer) - I
am more sceptical about putting them in the core language.

> 
>> To me, multiple assignment removes the need for a special "swap" feature
>> for handling common cases.  I would want a "swap" function if it were
>> designed to handle more complex types (such as handling "deep swaps" of
>> trees or lists), and there the critical point is that it must be
>> extendable and overloaded by user code - /not/ a compiler built-in fixed
>> function.
> 
> In my languages, swap is not an operator (it doesn't return a value). In
> the static one, it will work with any compatible flat types, including
> arrays and structs. In the dynamic one, it will exchange objects of any
> complexity and depth (in all cases, it means swapping two 16-byte
> descriptors), and which do not need to be compatible.
> 
> I can't see the need for a user-overload. If somebody does, then they
> can create their own swap function. You can't deny everyone else a
> 'swap' feature because 0.1% of people might want to override it sometime.

Imagine you have a simple linked list:

struct list_node;
struct list_node {
	int data;
	struct list_node * next;
};
typedef struct list_node *list;
list a, b;

What should "swap(a, b)" do?  With a simple direct swap function
(builtin or otherwise), this will swap the heads of the lists - but not
the tails.  With a user overrideable swap, the user can write (in a sort
of "C with references") :

void swap(list &a, list &b) {
	if (!a) {
		a = b;
		b = NULL;
		return;
	}
	if (!b) {
		b = a;
		a = NULL;
		return;
	}

	swap(a->data, b->data);
	swap(a->next, b->next);
}

Then they have a "deep swap".

This is not denying people a swap feature because some people might want
to override the standard function - it is giving people the standard
function /and/ allowing them to override it.  /Everybody/ wins.
	

> 
> (In a version I was using in the 80s and 90s, I had a cruder feature in
> place of swap, but it was more general:
> 
>     stack a, b              # push a then b to the hardware stack
>     unstack a, b            # pop a then b
> 
> This would also swap a and b, but all sorts of things were possible,
> including having other code between the two:
> 
>     stack a, b, c           # save a, b, c
>     ....
>     unstack c, b, a         # restore
> 
> But I eventually considered this too low-level a feature.)
> 

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


#146058

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2019-09-06 02:52 -0700
Message-ID<0e043b75-93bc-4eca-a364-586287d04c4b@googlegroups.com>
In reply to#146052
On Friday, 6 September 2019 09:35:59 UTC+1, David Brown  wrote:
>
> Imagine you have a simple linked list:
> 
> struct list_node;
> struct list_node {
> 	int data;
> 	struct list_node * next;
> };
> typedef struct list_node *list;
> list a, b;
> 
> What should "swap(a, b)" do?  With a simple direct swap function
> (builtin or otherwise), this will swap the heads of the lists - but not
> the tails.  With a user overrideable swap, the user can write (in a sort
> of "C with references") :
> 
Don't really follow you here. The next"pointer" will be swapped along with
the data member. So the tails come with the heads.

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


#146060

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-06 13:18 +0200
Message-ID<qktfab$bf1$1@dont-email.me>
In reply to#146058
On 06/09/2019 11:52, Malcolm McLean wrote:
> On Friday, 6 September 2019 09:35:59 UTC+1, David Brown  wrote:
>>
>> Imagine you have a simple linked list:
>>
>> struct list_node;
>> struct list_node {
>> 	int data;
>> 	struct list_node * next;
>> };
>> typedef struct list_node *list;
>> list a, b;
>>
>> What should "swap(a, b)" do?  With a simple direct swap function
>> (builtin or otherwise), this will swap the heads of the lists - but not
>> the tails.  With a user overrideable swap, the user can write (in a sort
>> of "C with references") :
>>
> Don't really follow you here. The next"pointer" will be swapped along with
> the data member. So the tails come with the heads.
> 

Sorry, you are completely correct.  My "swap" shuffles the lists like a
pack of cards.  My apologies for writing nonsense without thinking it
through properly.

Sometimes you will want a specialised "swap" function.  But not for this
particular structure!

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


#146059

FromBart <bc@freeuk.com>
Date2019-09-06 12:14 +0100
Message-ID<FcrcF.240288$TY7.124824@fx29.am4>
In reply to#146052
On 06/09/2019 09:35, David Brown wrote:
> On 05/09/2019 16:48, Bart wrote:
>> On 05/09/2019 13:54, David Brown wrote:
>>> On 04/09/2019 17:30, Bart wrote:
>>
>>> Again, I am not saying "do it like C", or "don't make "swap" a built in
>>> function in your language".  I am merely encouraging that you think
>>> about it, and make considered decisions on a solid basis.  The focus
>>> should be on what is best for the programmer, the user of the language.
>>>    I feel that sometimes your focus is on showing off the simplicity of
>>> your compiler (adding features just because it is easy to do so), or on
>>> picking features precisely because C does not have that feature.  As
>>> justifications for features, these are not much better than saying you
>>> are adding the <^v> "min-max-swap" operator because you had a dream
>>> about it.  And I know you don't want to go there!
>>
>> It is /because/ I have simple compilers, that will not have the
>> optimisations found in some C and C++ compilers, that I place importance
>> on having certain operations built-in. Rather than having to emulate
>> them in unwieldy user-code then relying on optimisation to reduce it down.
> 
> If you give the compiler a built-in, it will generate better object code
> for source using that one feature.  If you give the compiler an
> optimisation, it will generate better object code for /all/ source code.
> 
> Look at how C++ handles this.  (Look at the high level ideas - I am not
> suggesting you copy the syntax :-) ).  Features are added to the core
> language to give wide abilities - details and individual features are
> put in the library.  This gives maximal flexibility, making it
> (relatively) easy to make changes, and the language features allow a
> wide range of library functions to be made.  It avoids duplication of
> the work.  And nothing stops you having the library implementation
> delegating particular functions to built-ins for efficiency.
> 
> 
> I realise you have your priorities, and your finite time, and you are
> writing a one-man compiler for a one-man language.  So you will pick a
> different balance than might be chosen for a more general language.  But
> if you dream of moving it beyond a personal project, please don't hobble
> the language at this stage.  We have more than enough oddities in
> programming languages because the design made sense when the project was
> small.
> 
>>> Depending on the expected usage domains of your language, I think it
>>> would be reasonable to relegate "xor" to a standard library function
>>> too, leaving the ^ symbol for a power operator, or re-direction operator
>>> (like in Pascal).
>>
>> Bitwise XOR will always be in the core language. (I also have logical
>> XOR -would be ^^ in C - but have never used it.)
>>
>> When you see the same macros being defined in every other C program:
>> STREQ, SWAP, MIN/MAX, ARRAYLEN, then those are good candidates to be
>> part of either a core-language or core-runtime.
> 
> These are not macros in every other C program - you exaggerate.  But
> certainly many programs have things like that.  I'd fully support
> putting them in a standard library ("core-runtime", if you prefer) - I
> am more sceptical about putting them in the core language.
> 
>>
>>> To me, multiple assignment removes the need for a special "swap" feature
>>> for handling common cases.  I would want a "swap" function if it were
>>> designed to handle more complex types (such as handling "deep swaps" of
>>> trees or lists), and there the critical point is that it must be
>>> extendable and overloaded by user code - /not/ a compiler built-in fixed
>>> function.
>>
>> In my languages, swap is not an operator (it doesn't return a value). In
>> the static one, it will work with any compatible flat types, including
>> arrays and structs. In the dynamic one, it will exchange objects of any
>> complexity and depth (in all cases, it means swapping two 16-byte
>> descriptors), and which do not need to be compatible.
>>
>> I can't see the need for a user-overload. If somebody does, then they
>> can create their own swap function. You can't deny everyone else a
>> 'swap' feature because 0.1% of people might want to override it sometime.
> 
> Imagine you have a simple linked list:
> 
> struct list_node;
> struct list_node {
> 	int data;
> 	struct list_node * next;
> };
> typedef struct list_node *list;
> list a, b;
> 
> What should "swap(a, b)" do?

What does a=b do?

You could argue that "=" should be overridable, and in some languages it 
can be. But if those same languages have 'swap' built-in, then you can 
override that too (if you want to obscure what happens when someone 
encounters swap(a,b) in your code).

At the level of C, you can't override "=", its meaning is clear (it does 
a shallow assignment involving the values of a and b) and the same can 
be done for 'swap'.

In C, if you want a=b for those lists to do anything other than copy 
pointers, then you write that other code, or put it in a function. Same 
for 'swap'.

   With a simple direct swap function
> (builtin or otherwise), this will swap the heads of the lists - but not
> the tails.  With a user overrideable swap, the user can write (in a sort
> of "C with references") :
> 
> void swap(list &a, list &b) {
> 	if (!a) {
> 		a = b;
> 		b = NULL;
> 		return;
> 	}
> 	if (!b) {
> 		b = a;
> 		a = NULL;
> 		return;
> 	}
> 
> 	swap(a->data, b->data);
> 	swap(a->next, b->next);
> }
> 
> Then they have a "deep swap".

It's not clear what such a deep swap actually achieves.

If A is the list (10,20,30) and and B is (40,50,60), then you can 
exchange their contents simply by swapping the pointers to the heads of 
each list. Your algorithm will exchange the actual values of each node 
in each list.

Which version is suitable depends on requirements (eg. a pointer to the 
2nd node of A must still point to the 2nd node of A), but usually you 
want to minimise the amount of copying going on.

(C code to demonstrate what happens using your override is given below.)

> This is not denying people a swap feature because some people might want
> to override the standard function - it is giving people the standard
> function /and/ allowing them to override it.  /Everybody/ wins.

You can trivially 'override' by providing a dedicated function. Then a 
reader will also know it will be doing something different.

(In the code below, swapint() and swapptr() represent basic built-in 
swaps that would just be a generic swap() if that was present. 
swaplist() is a dedicated swap for a particular type.)

-------------------------------------------
#include <stdio.h>
#include <stdlib.h>

struct list_node;
struct list_node {
     int data;
     struct list_node * next;
};
typedef struct list_node *list;
list a, b;

void swapint(int* a, int* b){
     int temp;
     temp=*a; *a=*b; *b=temp;
}

void swaplist(list* a, list* b) {
     if (!*a) {
         *a = *b;
         *b = NULL;
         return;
     }
     if (!*b) {
         *b = *a;
         *a = NULL;
         return;
     }

     swapint(&((*a)->data), &((*b)->data));
     swaplist(&(*a)->next, &(*b)->next);
}

void swapptr(void** p, void** q) {
     void* temp;
     temp=*p; *p=*q; *q=temp;
}

list newnode(int a,list next){
     list p;
     p=malloc(sizeof(*p));
     p->data=a;
     p->next=next;
}

void printlist(char* caption,list a){
     printf("%s(",caption);
     while (a) {
         printf("%06X:(%d %06X) ",a,a->data, a->next);
//      printf("(%d %08X) ",a->data, a->next);
         a=a->next;
     }
     printf(")\n");
}

int main(void){
     list a,a1,a2,a3;
     list b,b1,b2,b3;

     a3=newnode(30,0);
     a2=newnode(20,a3);
     a1=newnode(10,a2);
     a=a1;
     b3=newnode(60,0);
     b2=newnode(50,b3);
     b1=newnode(40,b2);
     b=b1;

     printlist("A=",a);
     printlist("B=",b);

     puts("\nAfter 'deep' swap:");

     swaplist(&a,&b);

     printlist("A=",a);
     printlist("B=",b);

     swaplist(&a, &b);

     puts("\nAfter reset:");
     printlist("A=",a);
     printlist("B=",b);

     swapptr(&a, &b);

     puts("\nAfter shallow swap:");
     printlist("A=",a);
     printlist("B=",b);
}
-------------------------------------------

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


#146066

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-06 15:08 +0200
Message-ID<qktlo5$j1h$1@dont-email.me>
In reply to#146059
On 06/09/2019 13:14, Bart wrote:
> On 06/09/2019 09:35, David Brown wrote:
>> On 05/09/2019 16:48, Bart wrote:
>>> On 05/09/2019 13:54, David Brown wrote:
>>>> On 04/09/2019 17:30, Bart wrote:
>>>
>>>> Again, I am not saying "do it like C", or "don't make "swap" a built in
>>>> function in your language".  I am merely encouraging that you think
>>>> about it, and make considered decisions on a solid basis.  The focus
>>>> should be on what is best for the programmer, the user of the language.
>>>>    I feel that sometimes your focus is on showing off the simplicity of
>>>> your compiler (adding features just because it is easy to do so), or on
>>>> picking features precisely because C does not have that feature.  As
>>>> justifications for features, these are not much better than saying you
>>>> are adding the <^v> "min-max-swap" operator because you had a dream
>>>> about it.  And I know you don't want to go there!
>>>
>>> It is /because/ I have simple compilers, that will not have the
>>> optimisations found in some C and C++ compilers, that I place importance
>>> on having certain operations built-in. Rather than having to emulate
>>> them in unwieldy user-code then relying on optimisation to reduce it
>>> down.
>>
>> If you give the compiler a built-in, it will generate better object code
>> for source using that one feature.  If you give the compiler an
>> optimisation, it will generate better object code for /all/ source code.
>>
>> Look at how C++ handles this.  (Look at the high level ideas - I am not
>> suggesting you copy the syntax :-) ).  Features are added to the core
>> language to give wide abilities - details and individual features are
>> put in the library.  This gives maximal flexibility, making it
>> (relatively) easy to make changes, and the language features allow a
>> wide range of library functions to be made.  It avoids duplication of
>> the work.  And nothing stops you having the library implementation
>> delegating particular functions to built-ins for efficiency.
>>
>>
>> I realise you have your priorities, and your finite time, and you are
>> writing a one-man compiler for a one-man language.  So you will pick a
>> different balance than might be chosen for a more general language.  But
>> if you dream of moving it beyond a personal project, please don't hobble
>> the language at this stage.  We have more than enough oddities in
>> programming languages because the design made sense when the project was
>> small.
>>
>>>> Depending on the expected usage domains of your language, I think it
>>>> would be reasonable to relegate "xor" to a standard library function
>>>> too, leaving the ^ symbol for a power operator, or re-direction
>>>> operator
>>>> (like in Pascal).
>>>
>>> Bitwise XOR will always be in the core language. (I also have logical
>>> XOR -would be ^^ in C - but have never used it.)
>>>
>>> When you see the same macros being defined in every other C program:
>>> STREQ, SWAP, MIN/MAX, ARRAYLEN, then those are good candidates to be
>>> part of either a core-language or core-runtime.
>>
>> These are not macros in every other C program - you exaggerate.  But
>> certainly many programs have things like that.  I'd fully support
>> putting them in a standard library ("core-runtime", if you prefer) - I
>> am more sceptical about putting them in the core language.
>>
>>>
>>>> To me, multiple assignment removes the need for a special "swap"
>>>> feature
>>>> for handling common cases.  I would want a "swap" function if it were
>>>> designed to handle more complex types (such as handling "deep swaps" of
>>>> trees or lists), and there the critical point is that it must be
>>>> extendable and overloaded by user code - /not/ a compiler built-in
>>>> fixed
>>>> function.
>>>
>>> In my languages, swap is not an operator (it doesn't return a value). In
>>> the static one, it will work with any compatible flat types, including
>>> arrays and structs. In the dynamic one, it will exchange objects of any
>>> complexity and depth (in all cases, it means swapping two 16-byte
>>> descriptors), and which do not need to be compatible.
>>>
>>> I can't see the need for a user-overload. If somebody does, then they
>>> can create their own swap function. You can't deny everyone else a
>>> 'swap' feature because 0.1% of people might want to override it
>>> sometime.
>>
>> Imagine you have a simple linked list:
>>
>> struct list_node;
>> struct list_node {
>>     int data;
>>     struct list_node * next;
>> };
>> typedef struct list_node *list;
>> list a, b;
>>
>> What should "swap(a, b)" do?
> 
> What does a=b do?
> 
> You could argue that "=" should be overridable, and in some languages it
> can be. But if those same languages have 'swap' built-in, then you can
> override that too (if you want to obscure what happens when someone
> encounters swap(a,b) in your code).

I would argue that "=" should be overrideable.

But this all depends on the level and complexity of the language you are
making.  In C, you don't get to override that kind of thing.  In C++,
you do.  In your language, you pick the level you want.  I'm just trying
to show how this flexibility can be achieved without hindering
efficiency or user convenience when they don't need to override anything.

> 
> At the level of C, you can't override "=", its meaning is clear (it does
> a shallow assignment involving the values of a and b) and the same can
> be done for 'swap'.
> 
> In C, if you want a=b for those lists to do anything other than copy
> pointers, then you write that other code, or put it in a function. Same
> for 'swap'.
> 
>   With a simple direct swap function
>> (builtin or otherwise), this will swap the heads of the lists - but not
>> the tails.  With a user overrideable swap, the user can write (in a sort
>> of "C with references") :
>>
>> void swap(list &a, list &b) {
>>     if (!a) {
>>         a = b;
>>         b = NULL;
>>         return;
>>     }
>>     if (!b) {
>>         b = a;
>>         a = NULL;
>>         return;
>>     }
>>
>>     swap(a->data, b->data);
>>     swap(a->next, b->next);
>> }
>>
>> Then they have a "deep swap".
> 
> It's not clear what such a deep swap actually achieves.

It is clear that it doesn't achieve what I thought it would.  As Malcolm
pointed out, I got this example totally wrong.  Sorry for that.

Let me just say that sometimes you might want a "swap" that is more
sophisticated than a plain binary copy.  Perhaps you can take shortcuts
in some way, perhaps you want some locking to make the swap atomic, or
whatever.  I'm not going to try and give an example here because I might
make another silly mistake with it.

> 
> If A is the list (10,20,30) and and B is (40,50,60), then you can
> exchange their contents simply by swapping the pointers to the heads of
> each list. Your algorithm will exchange the actual values of each node
> in each list.
> 
> Which version is suitable depends on requirements (eg. a pointer to the
> 2nd node of A must still point to the 2nd node of A), but usually you
> want to minimise the amount of copying going on.
> 
> (C code to demonstrate what happens using your override is given below.)

It's okay - I know the mistake.

> 
>> This is not denying people a swap feature because some people might want
>> to override the standard function - it is giving people the standard
>> function /and/ allowing them to override it.  /Everybody/ wins.
> 
> You can trivially 'override' by providing a dedicated function. Then a
> reader will also know it will be doing something different.

Having the same function name for the same purpose has its advantages.
You lose the one-to-one match between source level function names and
assembly-level labels, but it can make source code programming nicer.
(As always, it's your choice if that is something you want in the language.)

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


#146067

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2019-09-06 06:23 -0700
Message-ID<571ae626-86bb-4623-b295-f505de7d9f46@googlegroups.com>
In reply to#146066
On Friday, 6 September 2019 14:08:29 UTC+1, David Brown  wrote:
> On 06/09/2019 13:14, Bart wrote:
>  
> Let me just say that sometimes you might want a "swap" that is more
> sophisticated than a plain binary copy.  Perhaps you can take shortcuts
> in some way, perhaps you want some locking to make the swap atomic, or
> whatever.  I'm not going to try and give an example here because I might
> make another silly mistake with it.
> 
An example would be  a circular linked list. Now the next pointer of the last
item points back to the head. You can't swap two head structures.

But in reality you'd probably have  

LIST *lista; LIST *listb; /* all nodes dynamic */

rather than
 
LIST lista; LIST listb; /* first node on stack, other nodes dynamic */ 

Then to swap you just swap two pointers.

The number of swaps for which memswap() is not adequate is surely very
small.

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


#145999

FromKeith Thompson <kst-u@mib.org>
Date2019-09-04 14:16 -0700
Message-ID<ln7e6nwylx.fsf@kst-u.example.com>
In reply to#145987
David Brown <david.brown@hesbynett.no> writes:
[...]
> In C++, "swap" could not be part of the language because it needs to be
> modifiable by code.  You have to be able to write your own
> specialisations of swap for your own types, if you want to.

You could make the same argument for sizeof.

There's no fundamental reason C++ couldn't have, say, a swap operator,
where `a swap b` takes to lvalues of the same (or compatible?) types and
swaps the contents of the objects they refer to -- or whatever syntax
you like.

But C's language features (templates, references) are powerful
enough that a convenient swap() can be defined in the library --
and in fact it is:

    #include <algorithm>
    ...
    std::swap(a, b);

There's probably no point in writing your own swap()
function/macro/whatever in C++ (unless you're using a freestanding,
nonconforming, or ancient implementation that doesn't provide the
standard library).

If there were a good enough reason to add swap() to C (IMHO there
isn't), a memswap() function would be one way to do it.  Multiple
assignment would be tricky to add to the language, since
    a, b = b, a;
is already valid with a different meaning.

A minor tangent: The common way of writing code to swap two objects is:
    {
        int temp = a;
        a = b;
        b = temp;
    }
I find this a bit clearer:
    {
        const int old_a = a;
        a = b;
        b = old_a;
    }
I like defining objects as "const" if they're not going to be
modified (YMMV), and the name "old_a" is clearer than "temp".
With the name "temp", it takes me a moment to be sure that the
assignments are in the right order.  Swapping is symmetric, but
swapping using a temporary introduces a mildly annoying assymetry.
(Those who don't obsess about this kind of thing are of course free
to call the temporary "temp" or "t".)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

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


#146000

FromBart <bc@freeuk.com>
Date2019-09-04 22:42 +0100
Message-ID<bdWbF.201989$Nw3.199362@fx40.am4>
In reply to#145999
On 04/09/2019 22:16, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>> In C++, "swap" could not be part of the language because it needs to be
>> modifiable by code.  You have to be able to write your own
>> specialisations of swap for your own types, if you want to.
> 
> You could make the same argument for sizeof.
> 
> There's no fundamental reason C++ couldn't have, say, a swap operator,
> where `a swap b` takes to lvalues of the same (or compatible?) types and
> swaps the contents of the objects they refer to -- or whatever syntax
> you like.
> 
> But C's language features (templates, references) are powerful
> enough that a convenient swap() can be defined in the library --
> and in fact it is:
> 
>      #include <algorithm>
>      ...
>      std::swap(a, b);

C++ you mean? I think even I can just about manage that; this is the 
first template I've ever written (test code elided):

     template <class T>
     void swap(T &a, T &b) {
         T temp;
         temp = a;
         a = b;
         b = temp;
     }

(My own static language can't do this, but then 'swap' is built-in. My 
dynamic language however could; here I'm defining 'myswap' as 'swap' is 
also built-in:

     proc myswap(&a,&b)=
         swap(a,b)                # choice of 3 swap methods
     #   t:=a; a:=b; b:=t
     #   (a,b):=(b,a)
     end

With the additional ability for a and b to be of completely different 
types, and of any complexity, which C++ would have some trouble with.)

> A minor tangent: The common way of writing code to swap two objects is:
>      {
>          int temp = a;
>          a = b;
>          b = temp;
>      }
> I find this a bit clearer:
>      {
>          const int old_a = a;
>          a = b;
>          b = old_a;
>      }
> I like defining objects as "const" if they're not going to be
> modified (YMMV), and the name "old_a" is clearer than "temp".
> With the name "temp", it takes me a moment to be sure that the
> assignments are in the right order.  Swapping is symmetric, but
> swapping using a temporary introduces a mildly annoying assymetry.

A true swap can be considered symmetric (whether it's done with a left 
or right rotation, or uses some other method, is not exposed, so can be 
assumed to be either). The way it is commonly written with a temp, uses 
left-rotation, so is not symmetric.

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


#146002

FromKeith Thompson <kst-u@mib.org>
Date2019-09-04 15:21 -0700
Message-ID<lny2z3vh1q.fsf@kst-u.example.com>
In reply to#145999
Keith Thompson <kst-u@mib.org> writes:
[...]
> But C's language features (templates, references) are powerful
> enough that a convenient swap() can be defined in the library --
> and in fact it is:
>
>     #include <algorithm>
>     ...
>     std::swap(a, b);
[...]

Correction, I meant C++, not C.  Thanks to Bart for catching this.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

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


#146019

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-05 15:15 +0200
Message-ID<qkr1pj$ag1$1@dont-email.me>
In reply to#145999
On 04/09/2019 23:16, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>> In C++, "swap" could not be part of the language because it needs to be
>> modifiable by code.  You have to be able to write your own
>> specialisations of swap for your own types, if you want to.
> 
> You could make the same argument for sizeof.

I am not sure that is the case - "sizeof" is quite a fundamental,
low-level feature and you would not want to write your own version.  I
don't think you would want to be able to override sizeof for your string
types and use it to return a string length, for example.

> 
> There's no fundamental reason C++ couldn't have, say, a swap operator,
> where `a swap b` takes to lvalues of the same (or compatible?) types and
> swaps the contents of the objects they refer to -- or whatever syntax
> you like.

That could have been done, yes.  But would it have been an improvement
at all?  I don't think so.  The syntax doesn't look good - "swap(a, b)"
seems clearer to me, as it would be used in a statement rather than
within an expression.  (Yes, that is subjective.)  And by making it an
operator, you are (as C++ is today) making it a keyword, which limits
your use of "swap" as an identifier.

(As an aside, I think it would be nice to figure out a syntax for C++ to
allow functions to be called infix, as though they were operators.  But
I suspect there would be all sorts of complications involved in such a
syntax.)

> 
> But C's language features (templates, references) are powerful

(You mean "C++'s language features".)

> enough that a convenient swap() can be defined in the library --
> and in fact it is:
> 
>     #include <algorithm>
>     ...
>     std::swap(a, b);
> 
> There's probably no point in writing your own swap()
> function/macro/whatever in C++ (unless you're using a freestanding,
> nonconforming, or ancient implementation that doesn't provide the
> standard library).

Agreed.

> 
> If there were a good enough reason to add swap() to C (IMHO there
> isn't), a memswap() function would be one way to do it.  

Yes, Malcolm also suggested that name.

> Multiple
> assignment would be tricky to add to the language, since
>     a, b = b, a;
> is already valid with a different meaning.

Yes.  But Bart doesn't have that issue for his own language.
(Personally, I would not miss C/C++'s comma operator if it disappeared
overnight, but I am not the only person who codes in C or C++.)

> 
> A minor tangent: The common way of writing code to swap two objects is:
>     {
>         int temp = a;
>         a = b;
>         b = temp;
>     }
> I find this a bit clearer:
>     {
>         const int old_a = a;
>         a = b;
>         b = old_a;
>     }

I am a fan of "const" too, and also of longer identifiers - I was just
keeping things simple here.

> I like defining objects as "const" if they're not going to be
> modified (YMMV), and the name "old_a" is clearer than "temp".
> With the name "temp", it takes me a moment to be sure that the
> assignments are in the right order.  Swapping is symmetric, but
> swapping using a temporary introduces a mildly annoying assymetry.
> (Those who don't obsess about this kind of thing are of course free
> to call the temporary "temp" or "t".)
> 

I try to be less obsessive in the code I write in Usenet posts than the
code I write in my programs.

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


#145988

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2019-09-04 08:05 -0600
Message-ID<1btv9s17jl.fsf@pfeifferfamily.net>
In reply to#145937
Bart <bc@freeuk.com> writes:
>
> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
> in inlines the call, but the swap takes 6 instructions for x64
> target. Slightly different code between int64 and float64, but still 6
> instructions.
>
> I had to use extern variables, and to sandwich the swap between extern
> calls, to stop it optimising the code out of existence. Using volatile
> in place of extern generates 4 instructions rather than 6, but
> volatile is not often used in real code.
<snip>

Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
higher, your swap code compiled to the four instructions

	movsd	x(%rip), %xmm0
	movsd	y(%rip), %xmm1
	movsd	%xmm0, y(%rip)
	movsd	%xmm1, x(%rip)

What I find particularly interesting is that it compiled to using two
temporaries, not just the one in the source code.

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


#146021

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-05 15:17 +0200
Message-ID<qkr1tm$ag1$2@dont-email.me>
In reply to#145988
On 04/09/2019 16:05, Joe Pfeiffer wrote:
> Bart <bc@freeuk.com> writes:
>>
>> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
>> in inlines the call, but the swap takes 6 instructions for x64
>> target. Slightly different code between int64 and float64, but still 6
>> instructions.
>>
>> I had to use extern variables, and to sandwich the swap between extern
>> calls, to stop it optimising the code out of existence. Using volatile
>> in place of extern generates 4 instructions rather than 6, but
>> volatile is not often used in real code.
> <snip>
> 
> Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
> higher, your swap code compiled to the four instructions
> 
> 	movsd	x(%rip), %xmm0
> 	movsd	y(%rip), %xmm1
> 	movsd	%xmm0, y(%rip)
> 	movsd	%xmm1, x(%rip)
> 
> What I find particularly interesting is that it compiled to using two
> temporaries, not just the one in the source code.
> 

The number of registers used in the object code does not need to have
any bearing on the number of variables defined in the code.

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


#146050

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2019-09-05 20:28 -0600
Message-ID<1bmufi17lg.fsf@pfeifferfamily.net>
In reply to#146021
David Brown <david.brown@hesbynett.no> writes:

>> On 04/09/2019 16:05, Joe Pfeiffer wrote:
>> Bart <bc@freeuk.com> writes:
>>>
>>> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
>>> in inlines the call, but the swap takes 6 instructions for x64
>>> target. Slightly different code between int64 and float64, but still 6
>>> instructions.
>>>
>>> I had to use extern variables, and to sandwich the swap between extern
>>> calls, to stop it optimising the code out of existence. Using volatile
>>> in place of extern generates 4 instructions rather than 6, but
>>> volatile is not often used in real code.
>> <snip>
>> 
>> Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
>> higher, your swap code compiled to the four instructions
>> 
>> 	movsd	x(%rip), %xmm0
>> 	movsd	y(%rip), %xmm1
>> 	movsd	%xmm0, y(%rip)
>> 	movsd	%xmm1, x(%rip)
>> 
>> What I find particularly interesting is that it compiled to using two
>> temporaries, not just the one in the source code.
>> 
>
> The number of registers used in the object code does not need to have
> any bearing on the number of variables defined in the code.

Of course not -- I'm just a little surprised that the compiler came up
with something that looks so much like the original code, but with an
extra temp.  I find myself wondering just what dependency analysis came
up with it, or if the swap idiom is so common that there's a heuristic
looking for it.

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


#146053

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-06 10:39 +0200
Message-ID<qkt60i$kir$1@dont-email.me>
In reply to#146050
On 06/09/2019 04:28, Joe Pfeiffer wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>>> On 04/09/2019 16:05, Joe Pfeiffer wrote:
>>> Bart <bc@freeuk.com> writes:
>>>>
>>>> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
>>>> in inlines the call, but the swap takes 6 instructions for x64
>>>> target. Slightly different code between int64 and float64, but still 6
>>>> instructions.
>>>>
>>>> I had to use extern variables, and to sandwich the swap between extern
>>>> calls, to stop it optimising the code out of existence. Using volatile
>>>> in place of extern generates 4 instructions rather than 6, but
>>>> volatile is not often used in real code.
>>> <snip>
>>>
>>> Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
>>> higher, your swap code compiled to the four instructions
>>>
>>> 	movsd	x(%rip), %xmm0
>>> 	movsd	y(%rip), %xmm1
>>> 	movsd	%xmm0, y(%rip)
>>> 	movsd	%xmm1, x(%rip)
>>>
>>> What I find particularly interesting is that it compiled to using two
>>> temporaries, not just the one in the source code.
>>>
>>
>> The number of registers used in the object code does not need to have
>> any bearing on the number of variables defined in the code.
> 
> Of course not -- I'm just a little surprised that the compiler came up
> with something that looks so much like the original code, but with an
> extra temp.  I find myself wondering just what dependency analysis came
> up with it, or if the swap idiom is so common that there's a heuristic
> looking for it.
> 

I can't guess the answer there, sorry.  But compilers do treat a set of
registers (depending on the compiler, ABI, and the target) as zero cost
to use, and they tend to treat modern processors as RISC-like load-store
architectures even when the instruction set allows more complex
instructions - as a "load-store attitude" is easier for scheduling and
works better with pipelines and super-scaler execution.

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


#146069

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2019-09-06 08:11 -0600
Message-ID<1bimq51pmt.fsf@pfeifferfamily.net>
In reply to#146053
David Brown <david.brown@hesbynett.no> writes:

> On 06/09/2019 04:28, Joe Pfeiffer wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>> 
>>>> On 04/09/2019 16:05, Joe Pfeiffer wrote:
>>>> Bart <bc@freeuk.com> writes:
>>>>>
>>>>> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
>>>>> in inlines the call, but the swap takes 6 instructions for x64
>>>>> target. Slightly different code between int64 and float64, but still 6
>>>>> instructions.
>>>>>
>>>>> I had to use extern variables, and to sandwich the swap between extern
>>>>> calls, to stop it optimising the code out of existence. Using volatile
>>>>> in place of extern generates 4 instructions rather than 6, but
>>>>> volatile is not often used in real code.
>>>> <snip>
>>>>
>>>> Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
>>>> higher, your swap code compiled to the four instructions
>>>>
>>>> 	movsd	x(%rip), %xmm0
>>>> 	movsd	y(%rip), %xmm1
>>>> 	movsd	%xmm0, y(%rip)
>>>> 	movsd	%xmm1, x(%rip)
>>>>
>>>> What I find particularly interesting is that it compiled to using two
>>>> temporaries, not just the one in the source code.
>>>>
>>>
>>> The number of registers used in the object code does not need to have
>>> any bearing on the number of variables defined in the code.
>> 
>> Of course not -- I'm just a little surprised that the compiler came up
>> with something that looks so much like the original code, but with an
>> extra temp.  I find myself wondering just what dependency analysis came
>> up with it, or if the swap idiom is so common that there's a heuristic
>> looking for it.
>> 
>
> I can't guess the answer there, sorry.  But compilers do treat a set of
> registers (depending on the compiler, ABI, and the target) as zero cost
> to use, and they tend to treat modern processors as RISC-like load-store
> architectures even when the instruction set allows more complex
> instructions - as a "load-store attitude" is easier for scheduling and
> works better with pipelines and super-scaler execution.

Playing with it a little, it turns out that sequence is exactly what a
naive code generator would come up with if it put the temporary variable
"t" in a register, since x86-64 doesn't do memory-memory moves.  So no
mystery after all.

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


#146072

Fromscott@slp53.sl.home (Scott Lurndal)
Date2019-09-06 18:31 +0000
Message-ID<rCxcF.79338$O63.50790@fx26.iad>
In reply to#146069
Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:
>David Brown <david.brown@hesbynett.no> writes:
>
>> On 06/09/2019 04:28, Joe Pfeiffer wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>> 
>>>>> On 04/09/2019 16:05, Joe Pfeiffer wrote:
>>>>> Bart <bc@freeuk.com> writes:
>>>>>>
>>>>>> gcc -O0 generates the actual call as expected. With gcc-O1 to -O3, it
>>>>>> in inlines the call, but the swap takes 6 instructions for x64
>>>>>> target. Slightly different code between int64 and float64, but still 6
>>>>>> instructions.
>>>>>>
>>>>>> I had to use extern variables, and to sandwich the swap between extern
>>>>>> calls, to stop it optimising the code out of existence. Using volatile
>>>>>> in place of extern generates 4 instructions rather than 6, but
>>>>>> volatile is not often used in real code.
>>>>> <snip>
>>>>>
>>>>> Interestingly, on my 64 bit Linux system with gcc 8.3.0 at -O3 and
>>>>> higher, your swap code compiled to the four instructions
>>>>>
>>>>> 	movsd	x(%rip), %xmm0
>>>>> 	movsd	y(%rip), %xmm1
>>>>> 	movsd	%xmm0, y(%rip)
>>>>> 	movsd	%xmm1, x(%rip)
>>>>>
>>>>> What I find particularly interesting is that it compiled to using two
>>>>> temporaries, not just the one in the source code.
>>>>>
>>>>
>>>> The number of registers used in the object code does not need to have
>>>> any bearing on the number of variables defined in the code.
>>> 
>>> Of course not -- I'm just a little surprised that the compiler came up
>>> with something that looks so much like the original code, but with an
>>> extra temp.  I find myself wondering just what dependency analysis came
>>> up with it, or if the swap idiom is so common that there's a heuristic
>>> looking for it.
>>> 
>>
>> I can't guess the answer there, sorry.  But compilers do treat a set of
>> registers (depending on the compiler, ABI, and the target) as zero cost
>> to use, and they tend to treat modern processors as RISC-like load-store
>> architectures even when the instruction set allows more complex
>> instructions - as a "load-store attitude" is easier for scheduling and
>> works better with pipelines and super-scaler execution.
>
>Playing with it a little, it turns out that sequence is exactly what a
>naive code generator would come up with if it put the temporary variable
>"t" in a register, since x86-64 doesn't do memory-memory moves.  So no
>mystery after all.

One machine (no registers, all instruction operands were memory operands)
that I used had an swap instruction called 'move links' (MVL).  A three
operand instruction that would move A->C, B->A and C->B.   For a two-way
swap, two of the three operands pointed to the same field in memory
(and the microcode was optimized for this case).

The memory fields described by the operands could be from one digit
(nibble) to one hundred bytes in size.

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


#145995

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2019-09-04 19:02 +0000
Message-ID<slrnqn02ij.cdo.grahn+nntp@frailea.sa.invalid>
In reply to#145926
On Tue, 2019-09-03, Malcolm McLean wrote:
> On Monday, 2 September 2019 20:37:58 UTC+1, Jorgen Grahn  wrote:
>> On Mon, 2019-09-02, Andrew Smallshaw wrote:
>> > On 2019-08-27, Jorgen Grahn <grahn+nntp@snipabacken.se> wrote:
>> >> On Tue, 2019-08-27, 3queens@shabbyroad.com wrote:
>> >>> Some time ago, there was a thread concerning using "a^=b; b^=a; a^=b" 
>> >>> to do an in place swap of two variables of the same size.  It was
>> >>> pointed out that this can only be done with integer types.  I found a
>> >>> way to do it with floating point types as well.
>> >> ...
>> >>> Maybe not that useful, but if space is really tight, perhaps useful in
>> >>> some situations.
>> >>
>> >> An optimizing compiler would, I strongly suspect, do a better job with
>> >> no weird code involved.  I think it's all an intellectual exercise and
>> >> nothing more (or less).
>> >
>> > I have long suspected so to, one proviso is that I'd use a dedicated
>> > variable rather than reusing a generic "temporary" variable which
>> > IMHO is bad practice anyway since there is no way to indicate to
>> > the compiler the value doesn't need to be preserved between distinct
>> > uses. To make it as clear as possible declare it with the tightest
>> > scope possible, e.g.
>> >
>> > double a, b;
>> >
>> > ...
>> >
>> > {
>> >     double c = a;
>> > 	a = b;
>> > 	b = c;
>> > }
>> 
>> I'd use a function: swap(&a, &b);
>> 
>> I think/assume that would get inlined adequately.
>> 
> It would be 
>
> swap(&a, &b, sizeof(a));
>
> Then the only way of implementing it portably is via a byte copying loop.
> So you're demanding quite a lot of the compiler to see that that is
> equivalent to a store to a temporary. It would be interesting to see
> if different compilers manage to optimise it.

You're redefining the problem.  The context was doubles, so it would
simply be

  swap(double*, double*);

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

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


#145911

FromDavid Brown <david.brown@hesbynett.no>
Date2019-09-02 22:16 +0200
Message-ID<qkjtb2$med$1@dont-email.me>
In reply to#145905
On 02/09/2019 17:25, Andrew Smallshaw wrote:
> On 2019-08-27, Jorgen Grahn <grahn+nntp@snipabacken.se> wrote:
>> On Tue, 2019-08-27, 3queens@shabbyroad.com wrote:
>>> Some time ago, there was a thread concerning using "a^=b; b^=a; a^=b"
>>> to do an in place swap of two variables of the same size.  It was
>>> pointed out that this can only be done with integer types.  I found a
>>> way to do it with floating point types as well.
>> ...
>>> Maybe not that useful, but if space is really tight, perhaps useful in
>>> some situations.
>>
>> An optimizing compiler would, I strongly suspect, do a better job with
>> no weird code involved.  I think it's all an intellectual exercise and
>> nothing more (or less).
> 
> I have long suspected so to, one proviso is that I'd use a dedicated
> variable rather than reusing a generic "temporary" variable which
> IMHO is bad practice anyway since there is no way to indicate to
> the compiler the value doesn't need to be preserved between distinct
> uses. To make it as clear as possible declare it with the tightest
> scope possible, e.g.
> 
> double a, b;
> 
> ...
> 
> {
>      double c = a;
> 	a = b;
> 	b = c;
> }
> 
> 

It is usually best to have a small scope for your variables.  But the 
compiler won't care - it will generate the same code whether the 
temporary is within a small scope like this, or a wider scope (but local 
to the function).

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


#145814

FromRobert Wessel <robertwessel2@yahoo.com>
Date2019-08-27 17:59 -0500
Message-ID<9ddbme52b398c5lrr1c653lvdo2oe7qbv5@4ax.com>
In reply to#145807
On Tue, 27 Aug 2019 17:03:38 -0000 (UTC), 3queens@shabbyroad.com
wrote:

>Some time ago, there was a thread concerning using "a^=b; b^=a; a^=b" 
>to do an in place swap of two variables of the same size.  It was
>pointed out that this can only be done with integer types.  I found a
>way to do it with floating point types as well.
>
>Declare a union with the floating point variable and an equally long
>integer variable.  Then use the integer member to do the exclusive-or
>process.
>
>Naturally, this would not be efficient if the data had to be copied into
>and out of the union, but if the variables were defined as unions to
>begin with, this would work.
>
>Maybe not that useful, but if space is really tight, perhaps useful in
>some situations.


AFAIK, this invokes undefined behavior.  You cannot reliably read from
a different member of a union than was written to.

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


Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web