Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #394650 > unrolled thread
| Started by | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| First post | 2025-10-22 09:45 -0300 |
| Last post | 2025-11-24 11:52 -0600 |
| Articles | 20 on this page of 248 — 14 participants |
Back to article view | Back to comp.lang.c
_BitInt(N) Thiago Adams <thiago.adams@gmail.com> - 2025-10-22 09:45 -0300
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-10-22 11:42 -0500
Re: _BitInt(N) Thiago Adams <thiago.adams@gmail.com> - 2025-10-22 14:23 -0300
Re: _BitInt(N) Thiago Adams <thiago.adams@gmail.com> - 2025-10-22 14:25 -0300
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-10-22 14:03 -0500
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-23 12:46 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-23 13:32 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-23 13:59 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-23 17:06 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 10:29 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 11:17 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 05:12 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 14:49 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 17:23 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-25 07:56 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-29 19:36 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 11:56 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-30 15:50 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 05:06 -0800
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-24 15:27 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 14:51 +0100
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-29 22:06 +0100
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-29 17:10 -0600
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-29 17:32 -0800
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-30 11:46 +0200
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 11:12 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 12:07 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-23 17:55 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-23 14:38 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 00:30 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 12:17 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-24 13:44 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 15:02 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 12:31 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 05:33 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 14:41 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 16:46 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 15:41 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 18:35 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 21:26 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 22:27 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 18:10 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-25 21:25 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-25 21:58 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-25 15:20 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 02:08 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-25 19:06 -0800
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 11:52 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 13:15 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 15:08 +0200
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-25 19:21 -0800
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-29 22:40 +0100
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-29 22:04 -0500
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 08:55 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 12:05 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 15:49 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 15:44 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 17:37 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 18:42 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 21:43 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 22:19 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-27 02:32 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 12:46 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-27 14:39 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-27 11:43 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 12:20 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-27 14:02 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-27 16:02 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-27 21:15 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-28 00:15 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-28 09:46 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-28 13:12 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-28 12:45 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-28 15:33 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-28 15:47 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-29 19:23 +0200
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-29 00:20 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-29 19:30 +0200
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-28 13:09 -0600
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 22:43 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 17:13 +0000
Re: _BitInt(N) Ike Naar <ike@sdf.org> - 2025-11-27 17:38 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 17:59 +0000
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-28 03:33 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 11:49 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 14:46 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-28 15:23 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-29 00:08 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-29 03:12 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-28 19:38 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-29 11:24 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-29 14:45 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-29 14:40 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-29 17:15 +0100
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-29 10:27 -0500
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-29 16:29 -0800
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-29 22:08 -0500
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-20 11:24 -0800
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-12-21 00:18 +0000
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-21 23:07 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-22 02:51 -0800
Re: _BitInt(N) Kaz Kylheku <046-301-5902@kylheku.com> - 2025-12-22 19:23 +0000
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 03:01 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-20 18:22 -0800
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-06 21:57 -0800
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-12-20 21:27 -0500
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-06 21:51 -0800
Re: _BitInt(N) Kaz Kylheku <046-301-5902@kylheku.com> - 2025-12-21 02:27 +0000
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-21 22:48 -0800
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-29 03:26 +0100
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-29 03:32 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-29 12:24 +0000
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-28 09:48 -0500
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-28 11:41 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 19:46 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-28 21:58 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-27 15:59 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 00:11 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-27 16:39 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-28 01:49 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-27 19:36 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-04 17:58 -0800
[meta] Newsreader and formatting (was Re: _BitInt(N)) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-28 02:56 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-12-01 14:59 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 14:18 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 12:06 -0800
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-12-01 23:59 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-02 08:31 +0100
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-12-02 12:14 +0100
[OT] Keyboard layout (was Re: _BitInt(N)) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-12-02 14:01 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-02 15:33 -0800
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-12-03 09:23 +0100
Re: _BitInt(N) Richard Heathfield <rjh@cpax.org.uk> - 2025-12-03 08:29 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-03 02:16 -0800
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-15 11:01 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-15 14:19 -0800
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-21 22:24 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-02 12:21 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-02 13:45 +0100
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-12-02 14:15 +0100
Block syntax (was Re: _BitInt(N)) bart <bc@freeuk.com> - 2025-12-02 14:12 +0000
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-12-02 13:53 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-12-02 19:55 +0200
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-12-02 19:37 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-02 21:07 +0100
Re: _BitInt(N) Ike Naar <ike@sdf.org> - 2025-11-27 08:10 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-27 01:30 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 02:18 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-27 04:12 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-29 20:24 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-29 22:58 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-29 16:46 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 02:30 +0000
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-30 05:31 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 12:51 +0000
Re: _BitInt(N) Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-11-30 18:17 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 17:55 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-12-01 00:08 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 01:14 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-12-01 04:10 +0000
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 14:41 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 16:24 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 17:19 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 19:33 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 20:14 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-12-02 01:04 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 18:21 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 12:34 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 22:01 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 15:01 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 11:33 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 11:29 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 14:10 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 08:56 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 19:38 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-01 12:42 -0800
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-12-02 22:17 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-03 09:25 +0100
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-12-03 06:17 -0500
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-12-03 10:07 -0800
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-15 08:19 -0800
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-15 08:21 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-30 18:05 -0800
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-29 20:32 -0800
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-30 12:22 +0200
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 11:41 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 12:28 +0100
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 13:35 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 15:14 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 12:09 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 18:03 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-25 11:38 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-25 14:12 +0200
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-25 14:57 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-25 18:29 +0200
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-25 18:33 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 11:12 +0200
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-26 12:45 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 15:31 +0200
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 11:29 +0200
Re: _BitInt(N) James Kuyper <jameskuyper@alumni.caltech.edu> - 2025-11-26 21:19 -0500
Re: _BitInt(N) Tim Rentsch <tr.17687@z991.linuxsc.com> - 2025-12-15 08:29 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-25 21:54 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-25 13:42 -0800
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-26 12:01 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 15:08 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-26 13:24 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-25 23:11 +0200
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-26 17:04 -0600
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-27 01:05 +0000
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-27 02:54 +0000
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-29 22:17 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-29 22:41 +0000
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 00:17 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-30 01:22 +0000
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 11:00 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-30 11:05 +0200
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 10:51 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 13:10 +0000
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-30 15:26 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-30 15:09 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 17:26 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-30 21:53 +0000
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-30 17:32 -0800
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 08:36 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 11:37 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 14:37 +0100
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-12-01 14:14 +0000
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-12-01 16:28 +0100
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-30 12:39 +0100
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-24 14:10 +0200
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 04:29 -0800
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-23 21:39 -0600
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 11:45 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-24 13:57 +0200
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 12:56 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-24 15:17 +0200
Re: _BitInt(N) David Brown <david.brown@hesbynett.no> - 2025-11-24 15:59 +0100
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 05:35 -0800
Re: _BitInt(N) bart <bc@freeuk.com> - 2025-11-24 14:21 +0000
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-24 13:12 -0600
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 17:00 -0800
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-24 20:10 -0600
Re: _BitInt(N) Philipp Klaus Krause <pkk@spth.de> - 2025-11-29 22:30 +0100
Re: _BitInt(N) antispam@fricas.org (Waldek Hebisch) - 2025-11-30 01:51 +0000
Re: _BitInt(N) Michael S <already5chosen@yahoo.com> - 2025-11-30 11:22 +0200
Re: _BitInt(N) Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-11-24 04:37 -0800
Re: _BitInt(N) BGB <cr88192@gmail.com> - 2025-11-24 11:52 -0600
Page 4 of 13 — ← Prev page 1 2 3 [4] 5 6 … 13 Next page →
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2025-11-26 22:19 +0000 |
| Message-ID | <10g7ue4$r47b$1@dont-email.me> |
| In reply to | #395506 |
On 26/11/2025 20:43, David Brown wrote:
> On 26/11/2025 19:42, bart wrote:
>> On 26/11/2025 16:37, David Brown wrote:
>>> On 26/11/2025 16:44, bart wrote:
>>
>>> The "other people" I referred to are the folks behind the C language,
>>> not me.
>>
>> OK. The people who chose to make 'break' do two jobs, unfortunately in
>> parts of the language that can overlap in use; those people! (I guess
>> you mean the more recent lot.)
>>
>>>> In C, the solution for my example might look like this:
>>>>
>>>> double temp = x+y;
>>>> printf("%llu", ((*(uint64_t*)&temp)>>52) & 2047);
>>>>
>>>
>>> No, that's not how a C solution would work. People who know C would
>>> know that. As a challenge for you, see if you can spot your mistake.
>>
>> This was my point. (Although I can't see the problem, making it even
>> more pertinent.)
>>
>
> So you can claim to have a "better" solution than C, without knowing how
> to write it correctly in C?
>
>>>
>>> (And of course if anyone wanted to do this stuff in real code, they'd
>>> wrap things in a static inline "bit_range_extract" function.)
>>
>> Also my point: everyone will invent their own incompatible solutions
>> for this fundamental stuff.
>
> It is not remotely fundamental. Extracting groups of bits from the
> representation of a type, especially a floating point type, is a niche
> operation.
A bit like that BitInt(12) example then?
This is about a lower-level systems language working with primitive
machine types, and having access to the underlying bits of those types.
How much more fundamental can you get?
C provides only basic bitwise operators, and you have to do some
bit-fiddling, while trying to avoid UB, in order to extract or inject
individual bits or bitfields.
I provide direct indexing ops to get or set any bit or bitfield, which
is actually a great core feature to have, but for some reason you want
to downplay it.
You might just admit for once that it is quite neat.
> (It can be an important operation - such as for software
> floating point routines.
That particular task can be important for lots of reasons.
> But the people who write those are few, and
> they know what they are doing.)
And I don't? I used to write FP emulation routines...
> "Type punning" refers to using a union to access or reinterpret the
> underlying bit representation. Using references and a cast to do so is
> UB,
In C maybe, using your favoured compilers. In my implementations of C,
and in my languages, it is well defined, especially as it is
type-punning a 64-bit quantity to another 64-bit quantity.
(This is a great thing about creating your own implementations: you get
to say what is UB, which will be for genuine, not artificial ones
maintained so that C compilers can be one-up on each other.
As it is, somebody using C as an intermediate language can have a
situation where something is well-defined in their source language,
known to be well-defined on their platforms of interest, but inbetween,
C says otherwise.)
Note that in the original example in my language, no references are used
(the code just copies a FP register to a GPR without conversion).
> except when using pointers to character types. Neither involves
> actually putting data into memory or the stack unless you are using a
> compiler that can't optimise well - and then it is just a matter of less
> efficient generated code.
OK, so how would you do a 'reinterpret' cast in C, of a value like 'x+y'?
>> Anything without braces isn't taken as seriously, eg. scripting
>> languages.
>>
>
> What a /very/ strange way to distinguish or classify languages.
It's an observation. Which languages that call themselves 'systems
languages' these days don't use braces?
> And
> what a bizarre way to generalise what people think, as though all
> programmers share the same opinions.
You're welcome to do your own survey.
[toc] | [prev] | [next] | [standalone]
| From | antispam@fricas.org (Waldek Hebisch) |
|---|---|
| Date | 2025-11-27 02:32 +0000 |
| Message-ID | <10g8d76$i159$1@paganini.bofh.team> |
| In reply to | #395507 |
bart <bc@freeuk.com> wrote:
>
> This is about a lower-level systems language working with primitive
> machine types, and having access to the underlying bits of those types.
>
> How much more fundamental can you get?
>
> C provides only basic bitwise operators, and you have to do some
> bit-fiddling, while trying to avoid UB, in order to extract or inject
> individual bits or bitfields.
>
> I provide direct indexing ops to get or set any bit or bitfield, which
> is actually a great core feature to have, but for some reason you want
> to downplay it.
>
> You might just admit for once that it is quite neat.
Yes, it is neat.
>> (It can be an important operation - such as for software
>> floating point routines.
>
> That particular task can be important for lots of reasons.
>
>> But the people who write those are few, and
>> they know what they are doing.)
>
> And I don't? I used to write FP emulation routines...
>
>
>> "Type punning" refers to using a union to access or reinterpret the
>> underlying bit representation. Using references and a cast to do so is
>> UB,
>
> In C maybe, using your favoured compilers. In my implementations of C,
> and in my languages, it is well defined, especially as it is
> type-punning a 64-bit quantity to another 64-bit quantity.
>
<snip>
>
> OK, so how would you do a 'reinterpret' cast in C, of a value like 'x+y'?
#include <stdint.h>
#include <string.h>
uint64_t
d_to_u(double d) {
uint64_t tmp;
memcpy(&tmp, &d, sizeof(tmp));
return tmp;
}
int
f_exp(double d) {
return (d_to_u(d)>>52)&2047;
}
Using 'gcc -O' I get the following assembly (only code, without
unimportant directives/labels):
d_to_u:
movq %xmm0, %rax
ret
f_exp:
movq %xmm0, %rax
shrq $52, %rax
andl $2047, %eax
ret
As you can see 'd_to_u' is single computational instruction,
you can not do better given that floating point registers
are distinct from integer registers. And 'f_exp' looks
optimal assuming lack of "bit extract" or "extract exponent"
instructions.
Note that you can put both functions above in a header file,
so once you have written few lines above you can use them
in all your C code. Of course, efficientcy depends on
compiler optimization.
--
Waldek Hebisch
[toc] | [prev] | [next] | [standalone]
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2025-11-27 12:46 +0000 |
| Message-ID | <10g9h6a$1crf0$2@dont-email.me> |
| In reply to | #395513 |
On 27/11/2025 02:32, Waldek Hebisch wrote:
> bart <bc@freeuk.com> wrote:
>>
>> This is about a lower-level systems language working with primitive
>> machine types, and having access to the underlying bits of those types.
>>
>> How much more fundamental can you get?
>>
>> C provides only basic bitwise operators, and you have to do some
>> bit-fiddling, while trying to avoid UB, in order to extract or inject
>> individual bits or bitfields.
>>
>> I provide direct indexing ops to get or set any bit or bitfield, which
>> is actually a great core feature to have, but for some reason you want
>> to downplay it.
>>
>> You might just admit for once that it is quite neat.
>
> Yes, it is neat.
Hmm, perhaps you're being sincere, perhaps not ...
>> OK, so how would you do a 'reinterpret' cast in C, of a value like 'x+y'?
>
> #include <stdint.h>
> #include <string.h>
>
> uint64_t
> d_to_u(double d) {
> uint64_t tmp;
> memcpy(&tmp, &d, sizeof(tmp));
> return tmp;
> }
>
> int
> f_exp(double d) {
> return (d_to_u(d)>>52)&2047;
> }
>
> Using 'gcc -O' I get the following assembly (only code, without
> unimportant directives/labels):
>
> d_to_u:
> movq %xmm0, %rax
> ret
>
> f_exp:
> movq %xmm0, %rax
> shrq $52, %rax
> andl $2047, %eax
> ret
>
> As you can see 'd_to_u' is single computational instruction,
> you can not do better given that floating point registers
> are distinct from integer registers. And 'f_exp' looks
> optimal assuming lack of "bit extract" or "extract exponent"
> instructions.
>
> Note that you can put both functions above in a header file,
> so once you have written few lines above you can use them
> in all your C code. Of course, efficientcy depends on
> compiler optimization.
Yes (that's something I can't rely on).
These examples are interesting: with a HLL you normally express yourself
in a clear manner, and it is the compiler's job to generate the
complicated code required to implement what you mean.
Here it seems to be other way around: it is the programmer who writes
the convoluted code, and the compiler turns that into short, clear
instructions! Which unfortunately no one will see.
If I use your functions like this:
a = f_exp(x + y);
then once the x+y result is in a register, gcc-O2 generates this inline
code for the extraction:
movq rax, xmm0
shr rax, 52
and eax, 2047
If I express it in my language:
a := int@(x + y).[52..62]
then my non-optimising compiler generates this (D0 is rax):
movq D0, XMM4
shr D0, 52
and D0, 2047
So such features have definite advantages, in being able to express
intent directly, and to make it easier for a simple compiler to know
that intent and help it generate reasonable code without lots of
analysis or needing function inlining.
BTW, your example explicitly writes to memory; David Brown posted a
version that didn't do so that I could see. Unless a compound literal is
designed to be built in memory? However that version only seemed to work
with one compiler.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-27 14:39 +0100 |
| Message-ID | <10g9kb7$1dpa3$2@dont-email.me> |
| In reply to | #395524 |
On 27/11/2025 13:46, bart wrote:
> On 27/11/2025 02:32, Waldek Hebisch wrote:
>> bart <bc@freeuk.com> wrote:
>>>
>>> This is about a lower-level systems language working with primitive
>>> machine types, and having access to the underlying bits of those types.
>>>
>>> How much more fundamental can you get?
>>>
>>> C provides only basic bitwise operators, and you have to do some
>>> bit-fiddling, while trying to avoid UB, in order to extract or inject
>>> individual bits or bitfields.
>>>
>>> I provide direct indexing ops to get or set any bit or bitfield, which
>>> is actually a great core feature to have, but for some reason you want
>>> to downplay it.
>>>
>>> You might just admit for once that it is quite neat.
>>
>> Yes, it is neat.
>
> Hmm, perhaps you're being sincere, perhaps not ...
>
>>> OK, so how would you do a 'reinterpret' cast in C, of a value like
>>> 'x+y'?
>> #include <stdint.h>
>> #include <string.h>
>>
>> uint64_t
>> d_to_u(double d) {
>> uint64_t tmp;
>> memcpy(&tmp, &d, sizeof(tmp));
>> return tmp;
>> }
>>
>> int
>> f_exp(double d) {
>> return (d_to_u(d)>>52)&2047;
>> }
>>
>> Using 'gcc -O' I get the following assembly (only code, without
>> unimportant directives/labels):
>>
>> d_to_u:
>> movq %xmm0, %rax
>> ret
>>
>> f_exp:
>> movq %xmm0, %rax
>> shrq $52, %rax
>> andl $2047, %eax
>> ret
>>
>> As you can see 'd_to_u' is single computational instruction,
>> you can not do better given that floating point registers
>> are distinct from integer registers. And 'f_exp' looks
>> optimal assuming lack of "bit extract" or "extract exponent"
>> instructions.
>>
>> Note that you can put both functions above in a header file,
>> so once you have written few lines above you can use them
>> in all your C code. Of course, efficientcy depends on
>> compiler optimization.
>
> Yes (that's something I can't rely on).
>
> These examples are interesting: with a HLL you normally express yourself
> in a clear manner, and it is the compiler's job to generate the
> complicated code required to implement what you mean.
>
> Here it seems to be other way around: it is the programmer who writes
> the convoluted code, and the compiler turns that into short, clear
> instructions! Which unfortunately no one will see.
>
I don't think Waldek's code (or mine) is particularly convoluted. But
in either case, you put such things in static inline functions (or
macros if you need to). Then you have clear intent when implementing
those functions - you are clearly doing low-level shifts and masking.
And you have clear intent when /using/ the functions - you are
extracting some bits from the underlying representation of the value.
You split things into identified functions with specific tasks - that's
at the heart of programming.
And then you let the automated computer system - the compiler - do what
it does best, and generate efficient results.
> If I use your functions like this:
>
> a = f_exp(x + y);
>
> then once the x+y result is in a register, gcc-O2 generates this inline
> code for the extraction:
>
> movq rax, xmm0
> shr rax, 52
> and eax, 2047
>
>
> If I express it in my language:
>
> a := int@(x + y).[52..62]
>
> then my non-optimising compiler generates this (D0 is rax):
>
> movq D0, XMM4
> shr D0, 52
> and D0, 2047
>
> So such features have definite advantages, in being able to express
> intent directly, and to make it easier for a simple compiler to know
> that intent and help it generate reasonable code without lots of
> analysis or needing function inlining.
>
You seem to be arguing that it is a good thing to write code that
spoon-feeds the compiler so that the compiler doesn't have to do much
work. You get this because you are writing the application code and
also writing the compiler - so you pick the solution that gives you the
best results for the least effort overall. But that is only appropriate
for people with personal languages like yours.
It should be the other way round - the compiler should be optimising so
that the programmer can work at higher levels of abstraction or write
code in the way that is most convenient to them, and the compiler will
handle the boring low-level details. Programmers using serious
languages /can/ rely on the compiler optimising well.
> BTW, your example explicitly writes to memory; David Brown posted a
> version that didn't do so that I could see. Unless a compound literal is
> designed to be built in memory? However that version only seemed to work
> with one compiler.
The version I wrote is C99 and works fine with any C99 compiler. No,
compound literals are not "designed to be built in memory", whatever
that might mean. A compound literal is a value, and can be used like
any other value.
Waldek's version does use "memcpy" and pointers formed from the
addresses of a parameter and a local variable. That means it must give
results as if the parameter and local variable were in memory somewhere
(the stack, in usual practice - though C does not actually require a
stack) and a memory-to-memory copy was carried out, byte by byte.
Critical here is the term "as if". If the compiler can give the same
results without using memory, it is allowed to do so - thus optimising
compilers will just do a register transfer from a floating point
register to a general purpose register in this case.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-27 11:43 +0100 |
| Message-ID | <10g9a0r$1a895$1@dont-email.me> |
| In reply to | #395507 |
On 26/11/2025 23:19, bart wrote:
> On 26/11/2025 20:43, David Brown wrote:
>> On 26/11/2025 19:42, bart wrote:
>>> On 26/11/2025 16:37, David Brown wrote:
>>>> On 26/11/2025 16:44, bart wrote:
>>>
>>>> The "other people" I referred to are the folks behind the C
>>>> language, not me.
>>>
>>> OK. The people who chose to make 'break' do two jobs, unfortunately
>>> in parts of the language that can overlap in use; those people! (I
>>> guess you mean the more recent lot.)
>>>
>>>>> In C, the solution for my example might look like this:
>>>>>
>>>>> double temp = x+y;
>>>>> printf("%llu", ((*(uint64_t*)&temp)>>52) & 2047);
>>>>>
>>>>
>>>> No, that's not how a C solution would work. People who know C would
>>>> know that. As a challenge for you, see if you can spot your mistake.
>>>
>>> This was my point. (Although I can't see the problem, making it even
>>> more pertinent.)
>>>
>>
>> So you can claim to have a "better" solution than C, without knowing
>> how to write it correctly in C?
>
>>
>>>>
>>>> (And of course if anyone wanted to do this stuff in real code,
>>>> they'd wrap things in a static inline "bit_range_extract" function.)
>>>
>>> Also my point: everyone will invent their own incompatible solutions
>>> for this fundamental stuff.
>>
>> It is not remotely fundamental. Extracting groups of bits from the
>> representation of a type, especially a floating point type, is a niche
>> operation.
>
> A bit like that BitInt(12) example then?
Yes, using BitInt(12) is quite niche.
But when the people behind _BitInt() started thinking about what sizes
people might want, it quickly became clear that it would be vastly more
effort to try to define which sizes were useful. It was much simpler
and clearer just to support any size (up to an implementation-defined
limit). Most particular sizes, other than 8, 16, 32, 64, and perhaps
128, are going to be niche. But if one clear feature enables a large
number of niche uses, that's a good thing.
No one has suggested that _BitInt(12) is in any way a /necessary/
feature. And I certainly don't think a stand-alone proposal to add
12-bit types to C would have been accepted. But since it exists, it
will let me write slightly neater code in some cases - thus I will use
it when appropriate.
What I don't like about your bit extraction operations is that you have
an operator syntax for a fairly obscure and rarely used operation. A
"bit_range_extract" standard library function would make more sense to
me, though I think shifting and masking works well enough for the few
situations where you need it. A syntax that looks very much like array
access is not going to be helpful to people looking at the code - for
general-purpose languages, most programmers will never see or use bit
ranges.
>
> This is about a lower-level systems language working with primitive
> machine types, and having access to the underlying bits of those types.
>
> How much more fundamental can you get?
It is not fundamental for a low-level systems language. And this is a C
group - C is a language covering general application programming as well
as systems programming. I can agree that it can be a /useful/ operation
at times - useful enough to make it worth having a standard library
function (or macro - or, in your case, a keyword or built-in function).
But not "fundamental" or useful enough to make it operator based like that.
>
> C provides only basic bitwise operators, and you have to do some
> bit-fiddling, while trying to avoid UB, in order to extract or inject
> individual bits or bitfields.
You make it sound difficult. It's not.
>
> I provide direct indexing ops to get or set any bit or bitfield, which
> is actually a great core feature to have, but for some reason you want
> to downplay it.
>
> You might just admit for once that it is quite neat.
>
I am sure it is very nice on the few occasions when it is useful.
>
>> (It can be an important operation - such as for software floating
>> point routines.
>
> That particular task can be important for lots of reasons.
>
>> But the people who write those are few, and they know what they are
>> doing.)
>
> And I don't? I used to write FP emulation routines...
>
The thing you always seem to forget, is that your languages are written
for /you/ - no one else. It doesn't make a difference whether something
is added /to/ the language or written in code /for/ the language. You
think other languages are missing critical features simply because there
is a thing that /you/ want to do that you added to your own language.
And you think other languages are overly complex or bloated because they
have features that you don't want to use.
That attitude is fine for your own personal specific language. If
that's how you like to do things, that's fine. But that's your own
little isolated world that does not compare to the wider world of other
people, other programmers, other languages, other tools.
Imagine asking the regulars in this group what features or changes they
would like C to have in order to make C "perfect" for their uses,
regardless of everyone else, all existing code, all existing tools. We
could all fill pages with ideas. And if those were all added to C, the
result would be a language that made C++ look as easy as Logo, while
being riddled with inconsistencies and contradictions.
>
>> "Type punning" refers to using a union to access or reinterpret the
>> underlying bit representation. Using references and a cast to do so
>> is UB,
>
> In C maybe, using your favoured compilers.
In C, yes. This is comp.lang.c.
> In my implementations of C,
> and in my languages, it is well defined, especially as it is
> type-punning a 64-bit quantity to another 64-bit quantity.
>
OK. But not in C.
> (This is a great thing about creating your own implementations: you get
> to say what is UB, which will be for genuine, not artificial ones
> maintained so that C compilers can be one-up on each other.
Ah, so the many C compilers I have used over the decades were not
"genuine", and the many different processors I have used were all
"artificial". Okay, that clears things up.
>
> As it is, somebody using C as an intermediate language can have a
> situation where something is well-defined in their source language,
> known to be well-defined on their platforms of interest, but inbetween,
> C says otherwise.)
You've never really understood how languages are defined, have you?
With your own languages and tools, you don't have to - there is no need
for standards, specifications, or anything like that. You can just make
up what suits you at the time. The language is "defined" by what the
implementation does. That's been very convenient for you, but it has
left you with serious misconceptions about how non-personal languages work.
>
> Note that in the original example in my language, no references are used
> (the code just copies a FP register to a GPR without conversion).
>
>> except when using pointers to character types. Neither involves
>> actually putting data into memory or the stack unless you are using a
>> compiler that can't optimise well - and then it is just a matter of
>> less efficient generated code.
>
> OK, so how would you do a 'reinterpret' cast in C, of a value like 'x+y'?
As you know, you use a union. So just to please you, here is your bit
extraction - written as a one-line function (split over two lines for
Usenet) because you seem to think that kind of thing is important :
uint64_t get_exponent(double x) {
return ((union { double d; uint64_t u;}) { x }.u >> 52)
& ((1ull << (62 - 52 + 1)) - 1);
}
That compiles (with gcc on x86-64) to :
movq rax, xmm0
shr rax, 52
and eax, 2047
ret
There's nothing in C that suggests this must be put in memory or do
anything more than this.
>
>>> Anything without braces isn't taken as seriously, eg. scripting
>>> languages.
>>>
>>
>> What a /very/ strange way to distinguish or classify languages.
>
> It's an observation. Which languages that call themselves 'systems
> languages' these days don't use braces?
>
Ada? Forth?
It is certainly common for languages to use braces, simply because they
are a simple and unambiguous way to delimit blocks. They are widely
used in languages that might be called "systems languages", and widely
used in languages that might /not/ be called "systems languages" -
though I don't think there is any remotely clear definition or
distinction between "systems languages" and other languages.
>> And what a bizarre way to generalise what people think, as though
>> all programmers share the same opinions.
>
> You're welcome to do your own survey.
>
In what way are languages like Ada, Fortran, Python, Haskell, Erlang,
etc., "not taken seriously" ? /Who/ does not take them seriously? Who
takes "B" seriously but not Ruby, just because "B" uses braces and Ruby
does not?
<https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(syntax)#Block_delimitation>
[toc] | [prev] | [next] | [standalone]
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2025-11-27 12:20 +0000 |
| Message-ID | <10g9fmh$1crf0$1@dont-email.me> |
| In reply to | #395522 |
On 27/11/2025 10:43, David Brown wrote:
> On 26/11/2025 23:19, bart wrote:
> What I don't like about your bit extraction operations is that you have
> an operator syntax for a fairly obscure and rarely used operation.
So shift and masking operations in C are obscure?!
A
> "bit_range_extract" standard library function would make more sense to
> me, though I think shifting and masking works well enough for the few
> situations where you need it. A syntax that looks very much like array
> access is not going to be helpful to people looking at the code - for
> general-purpose languages, most programmers will never see or use bit
> ranges.
The syntax actually comes from DEC Algol60 IIRC. It was used to access
individual characters of a string, normally an indivisible type in that
language, and I applied the same concept to bits of an integer.
>> How much more fundamental can you get?
>
> It is not fundamental for a low-level systems language.
So bits are not fundamental either! But then, it has taken until C23 to
standardise binary literals, and there is still no format code for
binary output.
>>> But the people who write those are few, and they know what they are
>>> doing.)
>>
>> And I don't? I used to write FP emulation routines...
>>
>
> The thing you always seem to forget, is that your languages are written
> for /you/ - no one else. It doesn't make a difference whether something
> is added /to/ the language or written in code /for/ the language. You
> think other languages are missing critical features simply because there
> is a thing that /you/ want to do that you added to your own language.
> And you think other languages are overly complex or bloated because they
> have features that you don't want to use.
They frequently have advanced features while ignoring the basics.
> Imagine asking the regulars in this group what features or changes they
> would like C to have in order to make C "perfect" for their uses,
> regardless of everyone else, all existing code, all existing tools. We
> could all fill pages with ideas. And if those were all added to C, the
> result would be a language that made C++ look as easy as Logo, while
> being riddled with inconsistencies and contradictions.
Yes, that's the trick. That's why a lot of features I've played with
have disappeared, while some have proved indispensable.
>> As it is, somebody using C as an intermediate language can have a
>> situation where something is well-defined in their source language,
>> known to be well-defined on their platforms of interest, but
>> inbetween, C says otherwise.)
>
> You've never really understood how languages are defined, have you? With
> your own languages and tools, you don't have to - there is no need for
> standards, specifications, or anything like that. You can just make up
> what suits you at the time. The language is "defined" by what the
> implementation does. That's been very convenient for you, but it has
> left you with serious misconceptions about how non-personal languages work.
Here's a program in a very simple language, where all variables have
i64 type:
c = a + b
Here, the author has decreed that any overflow in this addition will
wrap (any overflow bits above 64 are lost). If directly compiled to x64
code it might use this (here 'a b c' are aliases for the registers where
they reside):
mov c, a
add c, b
Or on ARM64:
add c, a, b
Now, the author decides to use intermediate C (for portability, for
optimisations etc), and will generate perhaps:
int64_t a, b, c;
...
c = a + b;
But here, if a + b happens to overflow, it is UB, and for no good
reason. You have to fix it. This is where it can be harder to generate
HLL code than assembly!
*Now* do you understand? This is nothing to do with me or my personal
languages, it is a problem for every language that transpiles to C,
where there is a mismatch between the sets of behaviour considered UB in
each.
>> OK, so how would you do a 'reinterpret' cast in C, of a value like 'x+y'?
>
> As you know, you use a union. So just to please you, here is your bit
> extraction - written as a one-line function (split over two lines for
> Usenet) because you seem to think that kind of thing is important :
>
> uint64_t get_exponent(double x) {
> return ((union { double d; uint64_t u;}) { x }.u >> 52)
> & ((1ull << (62 - 52 + 1)) - 1);
> }
>
> That compiles (with gcc on x86-64) to :
>
> movq rax, xmm0
> shr rax, 52
> and eax, 2047
> ret
>
> There's nothing in C that suggests this must be put in memory or do
> anything more than this.
(This only seems to work with gcc. Clang and MSVS don't like it.)
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-27 14:02 +0100 |
| Message-ID | <10g9i5e$1dpa3$1@dont-email.me> |
| In reply to | #395523 |
On 27/11/2025 13:20, bart wrote:
> On 27/11/2025 10:43, David Brown wrote:
>> On 26/11/2025 23:19, bart wrote:
>
>
>> What I don't like about your bit extraction operations is that you
>> have an operator syntax for a fairly obscure and rarely used operation.
>
> So shift and masking operations in C are obscure?!
Both shift operators and bitwise operators have lots of other uses.
When you are designing a programming language, you first provide general
features that can be used for multiple purposes. You only implement
specialised features if the need arises - it is too cumbersome, or
error-prone, or inefficient, or laborious to use the general features.
In some areas of C usage, shifts and masks - and bitfield extraction -
turn up quite a bit. But it seems the C operators work fine for the
task. It would not exactly be difficult to add a standard
"bit_range_extract" function to the C standard library, yet no one has
felt it to be worth the effort over the last 50 years. Perhaps it is
not as essential or fundamental as you think? Or perhaps C's current
features do the job well enough that there's no need for anything else?
>
> A
>> "bit_range_extract" standard library function would make more sense to
>> me, though I think shifting and masking works well enough for the few
>> situations where you need it. A syntax that looks very much like
>> array access is not going to be helpful to people looking at the code
>> - for general-purpose languages, most programmers will never see or
>> use bit ranges.
>
> The syntax actually comes from DEC Algol60 IIRC. It was used to access
> individual characters of a string, normally an indivisible type in that
> language, and I applied the same concept to bits of an integer.
I don't care if you found the syntax on the back of a cornflakes packet.
The origin is not relevant.
>
>>> How much more fundamental can you get?
>>
>> It is not fundamental for a low-level systems language.
>
> So bits are not fundamental either! But then, it has taken until C23 to
> standardise binary literals, and there is still no format code for
> binary output.
>
Very few programmers are at all interested in bits. A "double" holds a
floating point value, not a pattern of bits. You are thinking on a
level of abstraction that is not realistic for most programming tasks.
>>>> But the people who write those are few, and they know what they
>>>> are doing.)
>>>
>>> And I don't? I used to write FP emulation routines...
>>>
>>
>> The thing you always seem to forget, is that your languages are
>> written for /you/ - no one else. It doesn't make a difference whether
>> something is added /to/ the language or written in code /for/ the
>> language. You think other languages are missing critical features
>> simply because there is a thing that /you/ want to do that you added
>> to your own language. And you think other languages are overly complex
>> or bloated because they have features that you don't want to use.
>
> They frequently have advanced features while ignoring the basics.
No - they frequently have features that /you/ call "advanced" because
you don't need or want them, and they ignore things that /you/ call
"basics" because you /do/ need or want them. It's all about /you/.
>
>> Imagine asking the regulars in this group what features or changes
>> they would like C to have in order to make C "perfect" for their uses,
>> regardless of everyone else, all existing code, all existing tools.
>> We could all fill pages with ideas. And if those were all added to C,
>> the result would be a language that made C++ look as easy as Logo,
>> while being riddled with inconsistencies and contradictions.
>
> Yes, that's the trick. That's why a lot of features I've played with
> have disappeared, while some have proved indispensable.
>
>>> As it is, somebody using C as an intermediate language can have a
>>> situation where something is well-defined in their source language,
>>> known to be well-defined on their platforms of interest, but
>>> inbetween, C says otherwise.)
>>
>> You've never really understood how languages are defined, have you?
>> With your own languages and tools, you don't have to - there is no
>> need for standards, specifications, or anything like that. You can
>> just make up what suits you at the time. The language is "defined" by
>> what the implementation does. That's been very convenient for you,
>> but it has left you with serious misconceptions about how non-personal
>> languages work.
>
> Here's a program in a very simple language, where all variables have
> i64 type:
>
> c = a + b
>
> Here, the author has decreed that any overflow in this addition will
> wrap (any overflow bits above 64 are lost). If directly compiled to x64
> code it might use this (here 'a b c' are aliases for the registers where
> they reside):
>
> mov c, a
> add c, b
>
> Or on ARM64:
>
> add c, a, b
>
> Now, the author decides to use intermediate C (for portability, for
> optimisations etc), and will generate perhaps:
>
> int64_t a, b, c;
> ...
> c = a + b;
>
> But here, if a + b happens to overflow, it is UB, and for no good
> reason. You have to fix it. This is where it can be harder to generate
> HLL code than assembly!
>
You are talking nonsense.
Either a + b results in the correct answer, or it does not. Any sane
person reads that as "a plus b" - mathematically adding two integers to
get their sum. That's what the programmer wants, and that's what they
ask for. And any sane programmer expects the language to give the
correct result within its limitations, but doe not expect it to do
magic. Expecting to form a sum that is greater than 2 ^ 63 and somehow
produce the "correct" result is a total misunderstanding of mathematics
and programming - any primary school kid will tell you that using the
fingers of one hand, you can't add 3 and 4. They will /not/ tell you
that it's fine to add them on one hand because 3 + 4 is actually equal to 2.
> *Now* do you understand? This is nothing to do with me or my personal
> languages, it is a problem for every language that transpiles to C,
> where there is a mismatch between the sets of behaviour considered UB in
> each.
I understand that simple maths and common sense is beyond you. I
understand that you think mathematics should be defined in terms of
accidental byproducts of the way hardware logic designs happen to be
implemented.
>
>>> OK, so how would you do a 'reinterpret' cast in C, of a value like
>>> 'x+y'?
>>
>> As you know, you use a union. So just to please you, here is your bit
>> extraction - written as a one-line function (split over two lines for
>> Usenet) because you seem to think that kind of thing is important :
>>
>> uint64_t get_exponent(double x) {
>> return ((union { double d; uint64_t u;}) { x }.u >> 52)
>> & ((1ull << (62 - 52 + 1)) - 1);
>> }
>>
>> That compiles (with gcc on x86-64) to :
>>
>> movq rax, xmm0
>> shr rax, 52
>> and eax, 2047
>> ret
>>
>> There's nothing in C that suggests this must be put in memory or do
>> anything more than this.
>
> (This only seems to work with gcc. Clang and MSVS don't like it.)
>
I think you are mistaken. clang is fine with it. It is standard C99,
so any decent C compiler from the last 25 years will handle it fine. MS
gave up on bothering to make C compilers before the turn of the century
(they make a reasonable enough C++ compiler). Even your hero tcc is
fine with it (though on my attempts, it produces rubbish code - maybe it
needs different flags for optimisation). The C code is not made invalid
by the existence of C90-only compilers.
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-27 16:02 +0200 |
| Message-ID | <20251127160223.0000141e@yahoo.com> |
| In reply to | #395525 |
On Thu, 27 Nov 2025 14:02:38 +0100
David Brown <david.brown@hesbynett.no> wrote:
> On 27/11/2025 13:20, bart wrote:
> > On 27/11/2025 10:43, David Brown wrote:
> >> On 26/11/2025 23:19, bart wrote:
> >
> >
> >> What I don't like about your bit extraction operations is that you
> >> have an operator syntax for a fairly obscure and rarely used
> >> operation.
> >
> > So shift and masking operations in C are obscure?!
>
> Both shift operators and bitwise operators have lots of other uses.
>
> When you are designing a programming language, you first provide
> general features that can be used for multiple purposes. You only
> implement specialised features if the need arises - it is too
> cumbersome, or error-prone, or inefficient, or laborious to use the
> general features.
>
> In some areas of C usage, shifts and masks - and bitfield extraction
> - turn up quite a bit. But it seems the C operators work fine for
> the task. It would not exactly be difficult to add a standard
> "bit_range_extract" function to the C standard library, yet no one
> has felt it to be worth the effort over the last 50 years. Perhaps
> it is not as essential or fundamental as you think? Or perhaps C's
> current features do the job well enough that there's no need for
> anything else?
>
> >
> > A
> >> "bit_range_extract" standard library function would make more
> >> sense to me, though I think shifting and masking works well enough
> >> for the few situations where you need it. A syntax that looks
> >> very much like array access is not going to be helpful to people
> >> looking at the code
> >> - for general-purpose languages, most programmers will never see
> >> or use bit ranges.
> >
> > The syntax actually comes from DEC Algol60 IIRC. It was used to
> > access individual characters of a string, normally an indivisible
> > type in that language, and I applied the same concept to bits of an
> > integer.
>
> I don't care if you found the syntax on the back of a cornflakes
> packet. The origin is not relevant.
>
> >
> >>> How much more fundamental can you get?
> >>
> >> It is not fundamental for a low-level systems language.
> >
> > So bits are not fundamental either! But then, it has taken until
> > C23 to standardise binary literals, and there is still no format
> > code for binary output.
> >
>
> Very few programmers are at all interested in bits. A "double" holds
> a floating point value, not a pattern of bits. You are thinking on a
> level of abstraction that is not realistic for most programming tasks.
>
> >>>> But the people who write those are few, and they know what
> >>>> they are doing.)
> >>>
> >>> And I don't? I used to write FP emulation routines...
> >>>
> >>
> >> The thing you always seem to forget, is that your languages are
> >> written for /you/ - no one else. It doesn't make a difference
> >> whether something is added /to/ the language or written in code
> >> /for/ the language. You think other languages are missing
> >> critical features simply because there is a thing that /you/ want
> >> to do that you added to your own language. And you think other
> >> languages are overly complex or bloated because they have features
> >> that you don't want to use.
> >
> > They frequently have advanced features while ignoring the basics.
>
> No - they frequently have features that /you/ call "advanced" because
> you don't need or want them, and they ignore things that /you/ call
> "basics" because you /do/ need or want them. It's all about /you/.
>
> >
> >> Imagine asking the regulars in this group what features or changes
> >> they would like C to have in order to make C "perfect" for their
> >> uses, regardless of everyone else, all existing code, all existing
> >> tools. We could all fill pages with ideas. And if those were all
> >> added to C, the result would be a language that made C++ look as
> >> easy as Logo, while being riddled with inconsistencies and
> >> contradictions.
> >
> > Yes, that's the trick. That's why a lot of features I've played
> > with have disappeared, while some have proved indispensable.
> >
> >>> As it is, somebody using C as an intermediate language can have a
> >>> situation where something is well-defined in their source
> >>> language, known to be well-defined on their platforms of
> >>> interest, but inbetween, C says otherwise.)
> >>
> >> You've never really understood how languages are defined, have
> >> you? With your own languages and tools, you don't have to - there
> >> is no need for standards, specifications, or anything like that.
> >> You can just make up what suits you at the time. The language is
> >> "defined" by what the implementation does. That's been very
> >> convenient for you, but it has left you with serious
> >> misconceptions about how non-personal languages work.
> >
> > Here's a program in a very simple language, where all variables
> > have i64 type:
> >
> > c = a + b
> >
> > Here, the author has decreed that any overflow in this addition
> > will wrap (any overflow bits above 64 are lost). If directly
> > compiled to x64 code it might use this (here 'a b c' are aliases
> > for the registers where they reside):
> >
> > mov c, a
> > add c, b
> >
> > Or on ARM64:
> >
> > add c, a, b
> >
> > Now, the author decides to use intermediate C (for portability, for
> > optimisations etc), and will generate perhaps:
> >
> > int64_t a, b, c;
> > ...
> > c = a + b;
> >
> > But here, if a + b happens to overflow, it is UB, and for no good
> > reason. You have to fix it. This is where it can be harder to
> > generate HLL code than assembly!
> >
>
> You are talking nonsense.
>
> Either a + b results in the correct answer, or it does not. Any sane
> person reads that as "a plus b" - mathematically adding two integers
> to get their sum. That's what the programmer wants, and that's what
> they ask for. And any sane programmer expects the language to give
> the correct result within its limitations, but doe not expect it to
> do magic. Expecting to form a sum that is greater than 2 ^ 63 and
> somehow produce the "correct" result is a total misunderstanding of
> mathematics and programming - any primary school kid will tell you
> that using the fingers of one hand, you can't add 3 and 4. They will
> /not/ tell you that it's fine to add them on one hand because 3 + 4
> is actually equal to 2.
>
> > *Now* do you understand? This is nothing to do with me or my
> > personal languages, it is a problem for every language that
> > transpiles to C, where there is a mismatch between the sets of
> > behaviour considered UB in each.
>
> I understand that simple maths and common sense is beyond you. I
> understand that you think mathematics should be defined in terms of
> accidental byproducts of the way hardware logic designs happen to be
> implemented.
>
> >
> >>> OK, so how would you do a 'reinterpret' cast in C, of a value
> >>> like 'x+y'?
> >>
> >> As you know, you use a union. So just to please you, here is your
> >> bit extraction - written as a one-line function (split over two
> >> lines for Usenet) because you seem to think that kind of thing is
> >> important :
> >>
> >> uint64_t get_exponent(double x) {
> >> return ((union { double d; uint64_t u;}) { x }.u >> 52)
> >> & ((1ull << (62 - 52 + 1)) - 1);
> >> }
> >>
> >> That compiles (with gcc on x86-64) to :
> >>
> >> movq rax, xmm0
> >> shr rax, 52
> >> and eax, 2047
> >> ret
> >>
> >> There's nothing in C that suggests this must be put in memory or
> >> do anything more than this.
> >
> > (This only seems to work with gcc. Clang and MSVS don't like it.)
> >
>
> I think you are mistaken. clang is fine with it. It is standard
> C99, so any decent C compiler from the last 25 years will handle it
> fine. MS gave up on bothering to make C compilers before the turn of
> the century (they make a reasonable enough C++ compiler). Even your
> hero tcc is fine with it (though on my attempts, it produces rubbish
> code - maybe it needs different flags for optimisation). The C code
> is not made invalid by the existence of C90-only compilers.
>
MSVC compilers compile your code and produce correct result, but the
code
looks less nice:
0000000000000000 <get_exponent>:
0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp)
6: 48 8b 44 24 08 mov 0x8(%rsp),%rax
b: 48 c1 e8 34 shr $0x34,%rax
f: 25 ff 07 00 00 and $0x7ff,%eax
14: c3 ret
Although on old AMD processors it is likely faster than nicer code
generated by gcc and clang. On newer processor gcc code is likely a bit
better, but the difference is unlikely to be detected by simple
measurements.
Also MSVC compiler does not like your style and produces following
warning:
dave_b.c(5): warning C4116: unnamed type definition in parentheses
BTW, I don't like your style either. My preferred code will look
very similar to the code of Waldek Hebisch except that I'd declare
d_to_u() static.
I don't like union trick. Not just in this particular context, but
generally. memcpy() much cleaner in expressing programmer's intentions.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-27 21:15 +0100 |
| Message-ID | <10gabhp$1o6rk$1@dont-email.me> |
| In reply to | #395527 |
On 27/11/2025 15:02, Michael S wrote: > On Thu, 27 Nov 2025 14:02:38 +0100 > David Brown <david.brown@hesbynett.no> wrote: > > > MSVC compilers compile your code and produce correct result, but the > code > looks less nice: > 0000000000000000 <get_exponent>: > 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp) > 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax > b: 48 c1 e8 34 shr $0x34,%rax > f: 25 ff 07 00 00 and $0x7ff,%eax > 14: c3 ret > > Although on old AMD processors it is likely faster than nicer code > generated by gcc and clang. On newer processor gcc code is likely a bit > better, but the difference is unlikely to be detected by simple > measurements. I think it is unlikely that this version - moving from xmm0 to rax via memory instead of directly - is faster on any processor. But I fully agree that it is unlikely to be a measurable difference in practice. > > Also MSVC compiler does not like your style and produces following > warning: > dave_b.c(5): warning C4116: unnamed type definition in parentheses Warnings are a matter of taste. There's nothing wrong with my code, but it may be against some code styles. > > BTW, I don't like your style either. My preferred code will look > very similar to the code of Waldek Hebisch except that I'd declare > d_to_u() static. > I don't like union trick. Not just in this particular context, but > generally. memcpy() much cleaner in expressing programmer's intentions. > I particularly don't like using unions in compound literals like this either - it was just to make a compact demonstration. I'd write real code in more re-usable bits with static inline functions. I disagree, however, that memcpy() shows intent better. The intention is not to copy it to memory - the intention is to access the underlying bit representation as a different type. A type-punning union is at least, if not more, clear for that purpose (IMHO - and judgements of style and clarity are very much a matter of opinion).
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-28 00:15 +0200 |
| Message-ID | <20251128001507.000064e1@yahoo.com> |
| In reply to | #395534 |
On Thu, 27 Nov 2025 21:15:53 +0100 David Brown <david.brown@hesbynett.no> wrote: > On 27/11/2025 15:02, Michael S wrote: > > On Thu, 27 Nov 2025 14:02:38 +0100 > > David Brown <david.brown@hesbynett.no> wrote: > > > > > > > MSVC compilers compile your code and produce correct result, but the > > code > > looks less nice: > > 0000000000000000 <get_exponent>: > > 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp) > > 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax > > b: 48 c1 e8 34 shr $0x34,%rax > > f: 25 ff 07 00 00 and $0x7ff,%eax > > 14: c3 ret > > > > Although on old AMD processors it is likely faster than nicer code > > generated by gcc and clang. On newer processor gcc code is likely a > > bit better, but the difference is unlikely to be detected by simple > > measurements. > > I think it is unlikely that this version - moving from xmm0 to rax > via memory instead of directly - is faster on any processor. But I > fully agree that it is unlikely to be a measurable difference in > practice. I wonder, how do you have a nerve "to think" about things that you have absolutely no idea about? Instead of "thinking" you could just as well open Optimization Reference manuals of AMD Bulldozer family or of Bobcat. Or to read Agner Fog's instruction tables. Move from XMM to GPR on these processors is very slow: 8 clocks on BD, 7 on BbC. BTW, AMD K8 has the opposite problem. Move from XMM to GPR is reasonably fast, but move from GPR to XMM is painfully slow. On the other hand, moves "via memory" are reasonably fast on these CPUs (except, may be, Bobcat? I am not sure about it), because data does not really travels through memory or through cache. Load-store forwarding picks the data directly from the store queue.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-28 09:46 +0100 |
| Message-ID | <10gbni0$27ugi$1@dont-email.me> |
| In reply to | #395535 |
On 27/11/2025 23:15, Michael S wrote: > On Thu, 27 Nov 2025 21:15:53 +0100 > David Brown <david.brown@hesbynett.no> wrote: > >> On 27/11/2025 15:02, Michael S wrote: >>> On Thu, 27 Nov 2025 14:02:38 +0100 >>> David Brown <david.brown@hesbynett.no> wrote: >>> >> >>> >>> MSVC compilers compile your code and produce correct result, but the >>> code >>> looks less nice: >>> 0000000000000000 <get_exponent>: >>> 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp) >>> 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax >>> b: 48 c1 e8 34 shr $0x34,%rax >>> f: 25 ff 07 00 00 and $0x7ff,%eax >>> 14: c3 ret >>> >>> Although on old AMD processors it is likely faster than nicer code >>> generated by gcc and clang. On newer processor gcc code is likely a >>> bit better, but the difference is unlikely to be detected by simple >>> measurements. >> >> I think it is unlikely that this version - moving from xmm0 to rax >> via memory instead of directly - is faster on any processor. But I >> fully agree that it is unlikely to be a measurable difference in >> practice. > > I wonder, how do you have a nerve "to think" about things that you have > absolutely no idea about? I think about many things - and these are things I /do/ know about. But I don't know all the details, and am happy to be corrected and learn more. > > Instead of "thinking" you could just as well open Optimization > Reference manuals of AMD Bulldozer family or of Bobcat. Or to read > Agner Fog's instruction tables. Move from XMM to GPR on these > processors is very slow: 8 clocks on BD, 7 on BbC. > Okay. But storing data to memory from xmm0 is also going to be slow, and loading it to rax from memory is going to be slow. I am not an expert at the x86 world or reading Fog's tables, but it looks to me that on a Bulldozer, storing from xmm0 to memory has a latency of 6 cycles and reading the memory into rax has a latency of 4 cycles. That adds up to more than the 8 cycles for the direct register transfer, and I expect (but do not claim to know for sure!) that the dependency limits the scope for pipeline overlap - decode and address calculations can be done, but the data can't be fetched until the previous store is complete. So all in all, my estimate was, I think, quite reasonable. There may be unusual circumstances on particular cores if the instruction scheduling and pipelining, combined with the stack engine, make that sequence faster than the single register move. I've now had a short look at the relevant table from Fog's site. My conclusion from that is that the register move - though surprisingly slow - is probably marginally faster than passing it through memory. Perhaps if I spend enough time studying the details, I might find out more and discover that I was wrong. But that would be an extraordinary effort to learn about a meaningless little detail of a long-gone processor. I am also fairly confident that the function as a whole will be faster with the register move since you will get better overlap and superscaling with the call and return sequence when the instructions in the middle don't access the stack. Of curiosity, I compiled the code with gcc and "-march=bdver1", which I believe is the correct flag for that processor. It generated the register move version, but with a "vmovq" instruction instead of "movq". I don't know if there is any difference there - x86 instruction naming seems to have a certain degree of variance. (gcc's models of scheduling, pipelining and timing for processors is far from perfect, but the gcc folks do study Agner Fog's publications as well as having contributors from AMD and Intel.) More interesting, however, was that with "-march=bdver2" (up to bdver4) gcc changed the "shr / and" sequence to a single "bextr" instruction. I didn't see that on other -march choices. It seems the two instruction shift-and-mask is faster than a single bit extract instruction on most x86 processors. All in all, it is a lesson on how small details of architectures can make a difference. > BTW, AMD K8 has the opposite problem. Move from XMM to GPR is reasonably > fast, but move from GPR to XMM is painfully slow. > > On the other hand, moves "via memory" are reasonably fast on these > CPUs (except, may be, Bobcat? I am not sure about it), because data > does not really travels through memory or through cache. Load-store > forwarding picks the data directly from the store queue. > Yes, and there can be even more specialised short-cuts for stack data.
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-28 13:12 +0200 |
| Message-ID | <20251128131217.00002a69@yahoo.com> |
| In reply to | #395544 |
On Fri, 28 Nov 2025 09:46:56 +0100 David Brown <david.brown@hesbynett.no> wrote: > On 27/11/2025 23:15, Michael S wrote: > > On Thu, 27 Nov 2025 21:15:53 +0100 > > David Brown <david.brown@hesbynett.no> wrote: > > > >> On 27/11/2025 15:02, Michael S wrote: > >>> On Thu, 27 Nov 2025 14:02:38 +0100 > >>> David Brown <david.brown@hesbynett.no> wrote: > >>> > >> > >>> > >>> MSVC compilers compile your code and produce correct result, but > >>> the code > >>> looks less nice: > >>> 0000000000000000 <get_exponent>: > >>> 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp) > >>> 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax > >>> b: 48 c1 e8 34 shr $0x34,%rax > >>> f: 25 ff 07 00 00 and $0x7ff,%eax > >>> 14: c3 ret > >>> > >>> Although on old AMD processors it is likely faster than nicer code > >>> generated by gcc and clang. On newer processor gcc code is likely > >>> a bit better, but the difference is unlikely to be detected by > >>> simple measurements. > >> > >> I think it is unlikely that this version - moving from xmm0 to rax > >> via memory instead of directly - is faster on any processor. But I > >> fully agree that it is unlikely to be a measurable difference in > >> practice. > > > > I wonder, how do you have a nerve "to think" about things that you > > have absolutely no idea about? > > I think about many things - and these are things I /do/ know about. > But I don't know all the details, and am happy to be corrected and > learn more. > > > > > Instead of "thinking" you could just as well open Optimization > > Reference manuals of AMD Bulldozer family or of Bobcat. Or to read > > Agner Fog's instruction tables. Move from XMM to GPR on these > > processors is very slow: 8 clocks on BD, 7 on BbC. > > > > Okay. But storing data to memory from xmm0 is also going to be slow, > and loading it to rax from memory is going to be slow. I am not an > expert at the x86 world or reading Fog's tables, but it looks to me > that on a Bulldozer, storing from xmm0 to memory has a latency of 6 > cycles and reading the memory into rax has a latency of 4 cycles. > That adds up to more than the 8 cycles for the direct register > transfer, and I expect (but do not claim to know for sure!) that the > dependency limits the scope for pipeline overlap - decode and address > calculations can be done, but the data can't be fetched until the > previous store is complete. > > So all in all, my estimate was, I think, quite reasonable. There may > be unusual circumstances on particular cores if the instruction > scheduling and pipelining, combined with the stack engine, make that > sequence faster than the single register move. > It seems, you are correct in this particular case. Latency tables, esp. those that are measured by software rather than supplied by designer, are problematic in case of moves between registers of different types, memory stores of all types and even memory loads, with exception of memory load into GPR. Agner explains why they are problematic in te preface to his tables. In short, there is no direct way to measure this things in isolation, so one has to measure latency of the sequence of instructions and then to apply either guesswork or manufacturer's docs to somehow divide the combined latency into individual parts. So, the best way is to go by recommendations of the vendor in Opt. Reference Manual. There are no relevant recommendations for K8, unfortunately. I suspect that all methods are slow here. For Bobcat, there should be recommendations, but I don't have them and too lazy to look for. For Family 10h (Barcelona and derivatives): "When moving data from a GPR to an MMX or XMM register, use separate store and load instructions to move the data first from the source register to a temporary location in memory and then from memory into the destination register, taking the memory latency into account when scheduling both stages of the load-store sequence. When moving data from an MMX or XMM register to a general-purpose register, use the MOVD instruction. Whenever possible, use loads and stores of the same data length. (See 5.3, ‘Store-to-Load Forwarding Restrictions” on page 74 for more information.)" For Family 15h (Bullozer and derivatives): "When moving data from a GPR to an XMM register, use separate store and load instructions to move the data first from the source register to a temporary location in memory and then from memory into the destination register, taking the memory latency into account when scheduling both stages of the load-store sequence. When moving data from an XMM register to a general-purpose register, use the VMOVD instruction. Whenever possible, use loads and stores of the same data length. (See 6.3, ‘Store-to-Load Forwarding Restrictions” on page 98 for more information.)" So, for both families, vendor recommends register move in direction from SIMD to GPR and Store/Load sequence in direction from GPR to SIMD. The suspect point here is specific mentioning of EVEX-encoded form (VMOVD) in case of BD. It can mean that "legacy" (SSE-encoded) form is slower or it can mean nothing. I suspect the latter. > I've now had a short look at the relevant table from Fog's site. My > conclusion from that is that the register move - though surprisingly > slow - is probably marginally faster than passing it through memory. > Perhaps if I spend enough time studying the details, I might find out > more and discover that I was wrong. But that would be an > extraordinary effort to learn about a meaningless little detail of a > long-gone processor. > > I am also fairly confident that the function as a whole will be > faster with the register move since you will get better overlap and > superscaling with the call and return sequence when the instructions > in the middle don't access the stack. > > Of curiosity, I compiled the code with gcc and "-march=bdver1", which > I believe is the correct flag for that processor. It generated the > register move version, but with a "vmovq" instruction instead of > "movq". I don't know if there is any difference there - x86 > instruction naming seems to have a certain degree of variance. > (gcc's models of scheduling, pipelining and timing for processors is > far from perfect, but the gcc folks do study Agner Fog's publications > as well as having contributors from AMD and Intel.) > > More interesting, however, was that with "-march=bdver2" (up to > bdver4) gcc changed the "shr / and" sequence to a single "bextr" > instruction. I didn't see that on other -march choices. It seems > the two instruction shift-and-mask is faster than a single bit > extract instruction on most x86 processors. > > All in all, it is a lesson on how small details of architectures can > make a difference. > Zen3 has its own can of worms in the area of moving data between GPR and SIMD. The issues here are more subtle than those mentioned above. And unfortunately almost completely non-documented in the manuals. And despite that issues are subtle, performance impact can be very significant. I encountered these things when implementing alternative (to those currently in use by gcc) IEEE binary128 arithmetic routines. My conclusion was that designers of binary128 ABI in general and of ABI of support routines in particular made a serious mistake by treating binary128 (a.k.a. __float128, a.k.a _Float128, a.k.a. 'long double' on ARM64) as "floating-point" type that is passed around in XMM registers (or Neon registers on ARM64). Both passing it in pair of GPRs and via memory would be significantly faster on AMD processors and detectably faster on Intel processors. > > BTW, AMD K8 has the opposite problem. Move from XMM to GPR is > > reasonably fast, but move from GPR to XMM is painfully slow. > > > > On the other hand, moves "via memory" are reasonably fast on these > > CPUs (except, may be, Bobcat? I am not sure about it), because data > > does not really travels through memory or through cache. Load-store > > forwarding picks the data directly from the store queue. > > > > Yes, and there can be even more specialised short-cuts for stack data. > > >
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-28 12:45 +0100 |
| Message-ID | <10gc21m$2bsou$1@dont-email.me> |
| In reply to | #395546 |
On 28/11/2025 12:12, Michael S wrote: > On Fri, 28 Nov 2025 09:46:56 +0100 > David Brown <david.brown@hesbynett.no> wrote: > >> On 27/11/2025 23:15, Michael S wrote: >>> On Thu, 27 Nov 2025 21:15:53 +0100 >>> David Brown <david.brown@hesbynett.no> wrote: >>> >>>> On 27/11/2025 15:02, Michael S wrote: >>>>> On Thu, 27 Nov 2025 14:02:38 +0100 >>>>> David Brown <david.brown@hesbynett.no> wrote: >>>>> >>>> >>>>> >>>>> MSVC compilers compile your code and produce correct result, but >>>>> the code >>>>> looks less nice: >>>>> 0000000000000000 <get_exponent>: >>>>> 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp) >>>>> 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax >>>>> b: 48 c1 e8 34 shr $0x34,%rax >>>>> f: 25 ff 07 00 00 and $0x7ff,%eax >>>>> 14: c3 ret >>>>> >>>>> Although on old AMD processors it is likely faster than nicer code >>>>> generated by gcc and clang. On newer processor gcc code is likely >>>>> a bit better, but the difference is unlikely to be detected by >>>>> simple measurements. >>>> >>>> I think it is unlikely that this version - moving from xmm0 to rax >>>> via memory instead of directly - is faster on any processor. But I >>>> fully agree that it is unlikely to be a measurable difference in >>>> practice. >>> >>> I wonder, how do you have a nerve "to think" about things that you >>> have absolutely no idea about? >> >> I think about many things - and these are things I /do/ know about. >> But I don't know all the details, and am happy to be corrected and >> learn more. >> >>> >>> Instead of "thinking" you could just as well open Optimization >>> Reference manuals of AMD Bulldozer family or of Bobcat. Or to read >>> Agner Fog's instruction tables. Move from XMM to GPR on these >>> processors is very slow: 8 clocks on BD, 7 on BbC. >>> >> >> Okay. But storing data to memory from xmm0 is also going to be slow, >> and loading it to rax from memory is going to be slow. I am not an >> expert at the x86 world or reading Fog's tables, but it looks to me >> that on a Bulldozer, storing from xmm0 to memory has a latency of 6 >> cycles and reading the memory into rax has a latency of 4 cycles. >> That adds up to more than the 8 cycles for the direct register >> transfer, and I expect (but do not claim to know for sure!) that the >> dependency limits the scope for pipeline overlap - decode and address >> calculations can be done, but the data can't be fetched until the >> previous store is complete. >> >> So all in all, my estimate was, I think, quite reasonable. There may >> be unusual circumstances on particular cores if the instruction >> scheduling and pipelining, combined with the stack engine, make that >> sequence faster than the single register move. >> > > It seems, you are correct in this particular case. > Latency tables, esp. those that are measured by software rather > than supplied by designer, are problematic in case of moves between > registers of different types, memory stores of all types and even > memory loads, with exception of memory load into GPR. Agner explains why > they are problematic in te preface to his tables. In short, there is no > direct way to measure this things in isolation, so one has to measure > latency of the sequence of instructions and then to apply either > guesswork or manufacturer's docs to somehow divide the combined > latency into individual parts. > Well, if even Agner thinks it is difficult, then I don't feel bad for having trouble! > So, the best way is to go by recommendations of the vendor in Opt. > Reference Manual. > There are no relevant recommendations for K8, unfortunately. I suspect > that all methods are slow here. > For Bobcat, there should be recommendations, but I don't have them and > too lazy to look for. > Fair enough. It is not information that is likely to be useful to anyone here, so it's all for fun and interest. I certainly wouldn't want you to spend effort finding out the details just for me. > For Family 10h (Barcelona and derivatives): > "When moving data from a GPR to an MMX or XMM register, use separate > store and load instructions to move the data first from the source > register to a temporary location in memory and then from memory into > the destination register, taking the memory latency into account when > scheduling both stages of the load-store sequence. > > When moving data from an MMX or XMM register to a general-purpose > register, use the MOVD instruction. > > Whenever possible, use loads and stores of the same data length. (See > 5.3, ‘Store-to-Load Forwarding Restrictions” on page 74 for more > information.)" How much does advice like this take into account surrounding code? That's what makes generating optimal code /really/ hard. And it means micro-optimising a short instruction sequence can be ineffective for real-world code. After all, no one is actually interested in minimising the number of nanoseconds it takes to extract the exponent of a floating point number - the speed only matters if you are doing lots of these, probably in a big loop with data moving into and out of memory all the time. This stuff was all /so/ much easier when we used PIC's and AVR's... > > For Family 15h (Bullozer and derivatives): > "When moving data from a GPR to an XMM register, use separate store and > load instructions to move the data first from the source register to a > temporary location in memory and then from memory into the destination > register, taking the memory latency into account when scheduling both > stages of the load-store sequence. > > When moving data from an XMM register to a general-purpose register, > use the VMOVD instruction. > > Whenever possible, use loads and stores of the same data length. (See > 6.3, ‘Store-to-Load Forwarding Restrictions” on page 98 for more > information.)" > > So, for both families, vendor recommends register move in direction from > SIMD to GPR and Store/Load sequence in direction from GPR to SIMD. > The suspect point here is specific mentioning of EVEX-encoded form > (VMOVD) in case of BD. It can mean that "legacy" (SSE-encoded) form is > slower or it can mean nothing. I suspect the latter. > >> I've now had a short look at the relevant table from Fog's site. My >> conclusion from that is that the register move - though surprisingly >> slow - is probably marginally faster than passing it through memory. >> Perhaps if I spend enough time studying the details, I might find out >> more and discover that I was wrong. But that would be an >> extraordinary effort to learn about a meaningless little detail of a >> long-gone processor. >> >> I am also fairly confident that the function as a whole will be >> faster with the register move since you will get better overlap and >> superscaling with the call and return sequence when the instructions >> in the middle don't access the stack. >> >> Of curiosity, I compiled the code with gcc and "-march=bdver1", which >> I believe is the correct flag for that processor. It generated the >> register move version, but with a "vmovq" instruction instead of >> "movq". I don't know if there is any difference there - x86 >> instruction naming seems to have a certain degree of variance. >> (gcc's models of scheduling, pipelining and timing for processors is >> far from perfect, but the gcc folks do study Agner Fog's publications >> as well as having contributors from AMD and Intel.) >> >> More interesting, however, was that with "-march=bdver2" (up to >> bdver4) gcc changed the "shr / and" sequence to a single "bextr" >> instruction. I didn't see that on other -march choices. It seems >> the two instruction shift-and-mask is faster than a single bit >> extract instruction on most x86 processors. >> >> All in all, it is a lesson on how small details of architectures can >> make a difference. >> > > Zen3 has its own can of worms in the area of moving data between > GPR and SIMD. The issues here are more subtle than those mentioned > above. And unfortunately almost completely non-documented in the > manuals. And despite that issues are subtle, performance impact can be > very significant. > > I encountered these things when implementing alternative > (to those currently in use by gcc) IEEE binary128 arithmetic routines. > My conclusion was that designers of binary128 ABI in general and of ABI > of support routines in particular made a serious mistake by treating > binary128 (a.k.a. __float128, a.k.a _Float128, a.k.a. 'long double' on > ARM64) as "floating-point" type that is passed around in XMM registers > (or Neon registers on ARM64). Both passing it in pair of GPRs and via > memory would be significantly faster on AMD processors and detectably > faster on Intel processors. I can believe that. If you have to implement floating point routines in general integer hardware (and I expect that is the case for most of your implementation here) then I would think it is better to start and end with the data in GPR's. On some targets, moving data into and out of floating point or vector registers is efficient enough that those registers can effectively be used as caches, but it sounds like that is not the case here. > > >>> BTW, AMD K8 has the opposite problem. Move from XMM to GPR is >>> reasonably fast, but move from GPR to XMM is painfully slow. >>> >>> On the other hand, moves "via memory" are reasonably fast on these >>> CPUs (except, may be, Bobcat? I am not sure about it), because data >>> does not really travels through memory or through cache. Load-store >>> forwarding picks the data directly from the store queue. >>> >> >> Yes, and there can be even more specialised short-cuts for stack data. >> >> >> > >
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-28 15:33 +0200 |
| Message-ID | <20251128153355.00002711@yahoo.com> |
| In reply to | #395547 |
On Fri, 28 Nov 2025 12:45:58 +0100 David Brown <david.brown@hesbynett.no> wrote: > > I can believe that. If you have to implement floating point routines > in general integer hardware (and I expect that is the case for most > of your implementation here) then I would think it is better to start > and end with the data in GPR's. On some targets, moving data into > and out of floating point or vector registers is efficient enough > that those registers can effectively be used as caches, but it sounds > like that is not the case here. > On Windows the problem is only of moving data between various types of registers. On SysV things are worse: there is also a problem of absence of caller-saved FP/SIMD registers. In theory, the problem could have been solved by defining specialized ABI for support routines (__addtf3, __subtf3, __multf3, etc...), but that was not done either. I think, that it all comes from the old mental model of soft floating point routines being very slow; so slow that ABI impedance mismatches lost in noise. But in specific case of binary128 on modern CPUs, it's simply not true - arithmetic itself is quite fast so ABI mismatches are significant.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-11-28 15:47 +0100 |
| Message-ID | <10gccmd$2frk7$1@dont-email.me> |
| In reply to | #395549 |
On 28/11/2025 14:33, Michael S wrote: > On Fri, 28 Nov 2025 12:45:58 +0100 > David Brown <david.brown@hesbynett.no> wrote: > >> >> I can believe that. If you have to implement floating point routines >> in general integer hardware (and I expect that is the case for most >> of your implementation here) then I would think it is better to start >> and end with the data in GPR's. On some targets, moving data into >> and out of floating point or vector registers is efficient enough >> that those registers can effectively be used as caches, but it sounds >> like that is not the case here. >> > > On Windows the problem is only of moving data between various types of > registers. > On SysV things are worse: there is also a problem of absence of > caller-saved FP/SIMD registers. In theory, the problem could have been > solved by defining specialized ABI for support routines (__addtf3, > __subtf3, __multf3, etc...), but that was not done either. > > I think, that it all comes from the old mental model of soft floating > point routines being very slow; so slow that ABI impedance mismatches > lost in noise. But in specific case of binary128 on modern CPUs, it's > simply not true - arithmetic itself is quite fast so ABI mismatches are > significant. > My only real experience with software floating point (using it, not writing it) is on systems where they are either slow (like 32-bit Cortex-M ARMs), or /very/ slow (like an 8-bit AVR). A little inefficiency in the main ABI's is, as you say, just noise in these cases. But in those systems, the floating point arithmetic routines were part of the compiler support library. Functions there don't have to abide by the platform ABI - they can use different registers according to what suits best. Were you working on a library that integrates into the compiler, or was it more "user level" (like a C++ "binary128" class with operator overrides) ? ABI's are obviously useful for standardisation and intermixing of code from different tools. But they can also be a pain, especially when they are old and outdated or designed to be efficient on different processors or with different kinds of code. I am finding the EABI for 32-bit ARM to be a serious performance drain for some kinds of work. It doesn't support passing anything bigger than 32-bit in registers, except for "long long int" and "unsigned long long int". It has the same restriction on return values. That means if you have something like a C++ optional<uint32_t> type, or equivalent struct in C, it's all passed back and forth on the stack. And unlike the AMD processors you mention, on a Cortex-M core that is a lot slower!
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-29 19:23 +0200 |
| Message-ID | <20251129192359.00002cfe@yahoo.com> |
| In reply to | #395551 |
On Fri, 28 Nov 2025 15:47:41 +0100 David Brown <david.brown@hesbynett.no> wrote: > On 28/11/2025 14:33, Michael S wrote: > > On Fri, 28 Nov 2025 12:45:58 +0100 > > David Brown <david.brown@hesbynett.no> wrote: > > > >> > >> I can believe that. If you have to implement floating point > >> routines in general integer hardware (and I expect that is the > >> case for most of your implementation here) then I would think it > >> is better to start and end with the data in GPR's. On some > >> targets, moving data into and out of floating point or vector > >> registers is efficient enough that those registers can effectively > >> be used as caches, but it sounds like that is not the case here. > >> > > > > On Windows the problem is only of moving data between various types > > of registers. > > On SysV things are worse: there is also a problem of absence of > > caller-saved FP/SIMD registers. In theory, the problem could have > > been solved by defining specialized ABI for support routines > > (__addtf3, __subtf3, __multf3, etc...), but that was not done > > either. > > > > I think, that it all comes from the old mental model of soft > > floating point routines being very slow; so slow that ABI impedance > > mismatches lost in noise. But in specific case of binary128 on > > modern CPUs, it's simply not true - arithmetic itself is quite fast > > so ABI mismatches are significant. > > > > My only real experience with software floating point (using it, not > writing it) is on systems where they are either slow (like 32-bit > Cortex-M ARMs), or /very/ slow (like an 8-bit AVR). A little > inefficiency in the main ABI's is, as you say, just noise in these > cases. > > But in those systems, the floating point arithmetic routines were > part of the compiler support library. Functions there don't have to > abide by the platform ABI - they can use different registers > according to what suits best. Were you working on a library that > integrates into the compiler, or was it more "user level" (like a C++ > "binary128" class with operator overrides) ? > The former. Plug-in replacement for libgcc routines. It's absolutely true that gcc people were not obliged to follow SysV ABI, which is rather bad in general, but especially harmful in this particular case. But they decided to follow it. > ABI's are obviously useful for standardisation and intermixing of > code from different tools. But they can also be a pain, especially > when they are old and outdated or designed to be efficient on > different processors or with different kinds of code. I am finding > the EABI for 32-bit ARM to be a serious performance drain for some > kinds of work. It doesn't support passing anything bigger than > 32-bit in registers, except for "long long int" and "unsigned long > long int". It has the same restriction on return values. That means > if you have something like a C++ optional<uint32_t> type, or > equivalent struct in C, it's all passed back and forth on the stack. > And unlike the AMD processors you mention, on a Cortex-M core that is > a lot slower! > You know my opinion about use of C++ on MCUs. I don't have to repeat myself.
[toc] | [prev] | [next] | [standalone]
| From | antispam@fricas.org (Waldek Hebisch) |
|---|---|
| Date | 2025-11-29 00:20 +0000 |
| Message-ID | <10gde8b$10fda$1@paganini.bofh.team> |
| In reply to | #395546 |
Michael S <already5chosen@yahoo.com> wrote:
>
> Zen3 has its own can of worms in the area of moving data between
> GPR and SIMD. The issues here are more subtle than those mentioned
> above. And unfortunately almost completely non-documented in the
> manuals. And despite that issues are subtle, performance impact can be
> very significant.
>
> I encountered these things when implementing alternative
> (to those currently in use by gcc) IEEE binary128 arithmetic routines.
> My conclusion was that designers of binary128 ABI in general and of ABI
> of support routines in particular made a serious mistake by treating
> binary128 (a.k.a. __float128, a.k.a _Float128, a.k.a. 'long double' on
> ARM64) as "floating-point" type that is passed around in XMM registers
> (or Neon registers on ARM64). Both passing it in pair of GPRs and via
> memory would be significantly faster on AMD processors and detectably
> faster on Intel processors.
If they want to handle that type in hardware on some future model,
then ABI must use floating point (that is XMM) register.
--
Waldek Hebisch
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2025-11-29 19:30 +0200 |
| Message-ID | <20251129193007.00005efa@yahoo.com> |
| In reply to | #395560 |
On Sat, 29 Nov 2025 00:20:29 -0000 (UTC) antispam@fricas.org (Waldek Hebisch) wrote: > Michael S <already5chosen@yahoo.com> wrote: > > > > Zen3 has its own can of worms in the area of moving data between > > GPR and SIMD. The issues here are more subtle than those mentioned > > above. And unfortunately almost completely non-documented in the > > manuals. And despite that issues are subtle, performance impact can > > be very significant. > > > > I encountered these things when implementing alternative > > (to those currently in use by gcc) IEEE binary128 arithmetic > > routines. My conclusion was that designers of binary128 ABI in > > general and of ABI of support routines in particular made a serious > > mistake by treating binary128 (a.k.a. __float128, a.k.a _Float128, > > a.k.a. 'long double' on ARM64) as "floating-point" type that is > > passed around in XMM registers (or Neon registers on ARM64). Both > > passing it in pair of GPRs and via memory would be significantly > > faster on AMD processors and detectably faster on Intel processors. > > > > If they want to handle that type in hardware on some future model, > then ABI must use floating point (that is XMM) register. > Neither Intel nor AMD nor Arm ever said that they have plans of that sort. Thinking too much about future is bad engineering. In specific case of computer engineering, I am pretty sure that it caused significantly more harm than not thinking enough about future.
[toc] | [prev] | [next] | [standalone]
| From | BGB <cr88192@gmail.com> |
|---|---|
| Date | 2025-11-28 13:09 -0600 |
| Message-ID | <10gcs5g$2mrrt$1@dont-email.me> |
| In reply to | #395534 |
On 11/27/2025 2:15 PM, David Brown wrote:
> On 27/11/2025 15:02, Michael S wrote:
>> On Thu, 27 Nov 2025 14:02:38 +0100
>> David Brown <david.brown@hesbynett.no> wrote:
>>
>
>>
>> MSVC compilers compile your code and produce correct result, but the
>> code
>> looks less nice:
>> 0000000000000000 <get_exponent>:
>> 0: f2 0f 11 44 24 08 movsd %xmm0,0x8(%rsp)
>> 6: 48 8b 44 24 08 mov 0x8(%rsp),%rax
>> b: 48 c1 e8 34 shr $0x34,%rax
>> f: 25 ff 07 00 00 and $0x7ff,%eax
>> 14: c3 ret
>>
>> Although on old AMD processors it is likely faster than nicer code
>> generated by gcc and clang. On newer processor gcc code is likely a bit
>> better, but the difference is unlikely to be detected by simple
>> measurements.
>
> I think it is unlikely that this version - moving from xmm0 to rax via
> memory instead of directly - is faster on any processor. But I fully
> agree that it is unlikely to be a measurable difference in practice.
>
>>
>> Also MSVC compiler does not like your style and produces following
>> warning:
>> dave_b.c(5): warning C4116: unnamed type definition in parentheses
>
> Warnings are a matter of taste. There's nothing wrong with my code, but
> it may be against some code styles.
>
>>
>> BTW, I don't like your style either. My preferred code will look
>> very similar to the code of Waldek Hebisch except that I'd declare
>> d_to_u() static.
>> I don't like union trick. Not just in this particular context, but
>> generally. memcpy() much cleaner in expressing programmer's intentions.
>>
>
> I particularly don't like using unions in compound literals like this
> either - it was just to make a compact demonstration. I'd write real
> code in more re-usable bits with static inline functions.
>
> I disagree, however, that memcpy() shows intent better. The intention
> is not to copy it to memory - the intention is to access the underlying
> bit representation as a different type. A type-punning union is at
> least, if not more, clear for that purpose (IMHO - and judgements of
> style and clarity are very much a matter of opinion).
>
FWIW, BGBCC allows:
double f;
u64 uli;
uli=(u64)((__m64)f);
And, you can extract an exponent as:
uli[62:52]
But, this is pretty nonstandard...
Here, "val[hi:lo]" works on pretty much any integer type, with the behavior:
If it is a normal integer type, will return a zero-extended value of the
same type as the input (so, similar to what shift and mask would do).
If the input type is a _BitInt or _UBitInt, the result will also be
_BitInt or _UBitInt with the same width as the bitfield selector.
It is possible to select a single bit:
uli[63]
But, this is only valid for _BitInt and _UBitInt, where if a normal
integer type it used here, it makes more sense to assume the user had
mistyped something, so "uli[63:63]" would be needed for a single bit
extract in this case.
It is also possible to compose values of _UBitInt and similar, say:
_UBitInt(24) rgb24;
_UBitInt(16) rgb5;
rgb5=(_UBitInt(16)) { 0b0u1, rgb24[23:19], rgb24[15:11], rgb24[7:3] };
Etc...
Some of this was partly inspired by Verilog in my case.
Partial merit in this case is that, beyond just being slightly more
concise and readable than a more traditional shifts-and-masks approach,
also makes it easier for the compiler to generate more efficient code...
Though, for this particular scenario, my ISA has a specialized CPU
instruction for RGB24 to RGB555 that is faster than manually repacking
the bits, so alas...
But, also there are special optional instructions for bitfield moves
that would allow the above to be expressed in 3 CPU instructions (vs the
11 or so instructions that would be needed with a more traditional
approach, or 8 if one gets clever with how they use shifts).
However, with the syntax, without the special CPU instruction, it can
infer the 8-instruction construct, and other similar constructs, it
cases where it might have otherwise been too much mental effort for a
human programmer (and where inferring this from shifts and masks is also
asking too much from the compiler...).
...
[toc] | [prev] | [next] | [standalone]
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2025-11-28 22:43 +0000 |
| Message-ID | <10gd8in$2qefr$1@dont-email.me> |
| In reply to | #395554 |
On 28/11/2025 19:09, BGB wrote:
> It is also possible to compose values of _UBitInt and similar, say:
> _UBitInt(24) rgb24;
> _UBitInt(16) rgb5;
> rgb5=(_UBitInt(16)) { 0b0u1, rgb24[23:19], rgb24[15:11], rgb24[7:3] };
This has given me an idea for an extended feature. Here, I would use
rgb.[x] syntax, where x is maybe 23, or 23..19, and rgb.[x, y] just
means rgb.[x].[y].
The latter is not that useful however; suppose that rgb.[x, y] actually
combines rgb.[x] and rgb.[y]. That could then be used to express your
example like this:
rgb24.[23..19, 15..11, 7..3]
So the 3 distinct 5-bit bitfields are concatenated into one 15-bit field.
However the exact meaning and ordering would still need pinning down,
and there are various questions to be answered. I also think that such
extaction can be a separate feature from packing multiple sub-word
values into one result.
I think this might be worth looking at. But I'm still not keen on
relying on the type system to give you the lengths of those fields. (In
my language, rgb.[23..19] is extracted into an i64 value so its bitfield
info is lost.)
[toc] | [prev] | [next] | [standalone]
Page 4 of 13 — ← Prev page 1 2 3 [4] 5 6 … 13 Next page →
Back to top | Article view | comp.lang.c
csiph-web