{"thread":{"id":"31022","subject":"[PATCH maint-1.6.5] block-sha1: avoid unaligned accesses on some big-endian systems","startedAt":"2012-07-14T07:59:06Z","lastAt":"2012-07-16T09:53:53Z","messageCount":10,"participants":["Jonathan Nieder","Linus Torvalds","Michael Cree"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"195038","messageId":"20120714075906.GD3693@burratino","threadId":"31022","inReplyTo":"50010B84.5030606@orcon.net.nz","subject":"[PATCH maint-1.6.5] block-sha1: avoid unaligned accesses on some big-endian systems","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-07-14T07:59:06Z","receivedAt":"2012-07-14T07:59:06Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"With 660231aa (block-sha1: support for architectures with memory\nalignment restrictions, 2009-08-12), blk_SHA1_Update was modified to\nwork reasonably on RISC-y architectures by accessing 32-bit values one\nbyte at a time on machines that prefer that:\n\n\t#define get_unaligned_be32(p)    ( \\\n\t\t(*((unsigned char *)(p) + 0) << 24) | \\\n\t\t(*((unsigned char *)(p) + 1) << 16) | \\\n\t\t(*((unsigned char *)(p) + 2) <<  8) | \\\n\t\t(*((unsigned char *)(p) + 3) <<  0) )\n\nUnfortunately, on big-endian architectures, if p is a pointer to\nunsigned int then current gcc assumes it is properly aligned and\nconverts this construct to a 32-bit load.  The result is the same\nalignment fault we want to avoid.  Fix it by passing around 'data' as\nan unsigned char * instead of unsigned int * to more clearly document\nthe intended alignment for compilers and humans.\n\nThe patch renames 'data' to 'block' to make sure all references are\nupdated to reflect its new type.\n\nNoticed on an alpha.  Typical ARM systems and other little-endian\narches don't hit this because with the endianness conversion gcc\n(rightly) prefers reading one byte at a time even if the pointer is\naligned.\n\nReported-and-tested-by: Michael Cree <mcree@orcon.net.nz>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nHi,\n\nMichael Cree wrote[1]:\n> On 14/07/12 14:18, Jonathan Nieder wrote:\n\n>> Does this patch help?\n>\n> Yes, it does!  Unaligned accesses are no longer reported and git is\n> running noticeably faster.\n\nThanks!  Nico, Linus, what do you think?\n\nAs Michael mentioned, in the long term it might make sense to tweak\ngit to always pass aligned pointers and lengths in the 'data' and\n'len' arguments to SHA1_Update, but that's an experiment for another\nday.\n\n[1] http://bugs.debian.org/681532\n\n block-sha1/sha1.c |    8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/block-sha1/sha1.c b/block-sha1/sha1.c\nindex d8934757..4d72e4bc 100644\n--- a/block-sha1/sha1.c\n+++ b/block-sha1/sha1.c\n@@ -100,7 +100,7 @@\n  * Where do we get the source from? The first 16 iterations get it from\n  * the input data, the next mix it from the 512-bit array.\n  */\n-#define SHA_SRC(t) get_be32(data + t)\n+#define SHA_SRC(t) get_be32(block + t*4)\n #define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)\n \n #define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \\\n@@ -114,7 +114,7 @@\n #define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )\n #define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) ,  0xca62c1d6, A, B, C, D, E )\n \n-static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)\n+static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned char *block)\n {\n \tunsigned int A,B,C,D,E;\n \tunsigned int array[16];\n@@ -125,7 +125,7 @@ static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)\n \tD = ctx->H[3];\n \tE = ctx->H[4];\n \n-\t/* Round 1 - iterations 0-16 take their input from 'data' */\n+\t/* Round 1 - iterations 0-16 take their input from 'block' */\n \tT_0_15( 0, A, B, C, D, E);\n \tT_0_15( 1, E, A, B, C, D);\n \tT_0_15( 2, D, E, A, B, C);\n@@ -251,7 +251,7 @@ void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)\n \t\tdata = ((const char *)data + left);\n \t\tif (lenW)\n \t\t\treturn;\n-\t\tblk_SHA1_Block(ctx, ctx->W);\n+\t\tblk_SHA1_Block(ctx, (const unsigned char *) ctx->W);\n \t}\n \twhile (len >= 64) {\n \t\tblk_SHA1_Block(ctx, data);\n-- \n1.7.10.4\n"},{"id":"195052","messageId":"CA+55aFy+y=TCoJUQarinaduibt4i-46TAuvpp7fsAmjDZj_+3w@mail.gmail.com","threadId":"31022","inReplyTo":"20120714075906.GD3693@burratino","subject":"Re: [PATCH maint-1.6.5] block-sha1: avoid unaligned accesses on some big-endian systems","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2012-07-14T19:11:59Z","receivedAt":"2012-07-14T19:11:59Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"On Sat, Jul 14, 2012 at 12:59 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n>\n> Unfortunately, on big-endian architectures, if p is a pointer to\n> unsigned int then current gcc assumes it is properly aligned and\n> converts this construct to a 32-bit load.\n\nThis patch seems to entirely depend on the location of the cast. And\nas far as I can tell, that workaround will in turn depend on just what\ngets inlined.\n\nMy gut feel is that this makes the code uglier (the manual \"multiply\nby four\" being a prime example) while not really even addressing the\nproblem.\n\nI think a much better approach would be to just mark the unsigned int\ndata pointer as being unaligned, or add a \"get_unaligned()\" helper\nfunction (you have to do a structure member and mark the structure\npacked, I think - I don't think you can just mark an int pointer\npacked). Sure, that's compiler-dependent, but if a compiler does\nsomething like gcc apparently does, it had better support the notion\nof unaligned pointers.\n\nAnd then gcc might actually do the unaligned word read *optimally* on\nbig-endian architectures, instead of that idiotic byte-at-a-time crap\nwith shifting.\n\nAnyway, the whole \"noticed on alpha\" makes no sense, since alpha isn't\neven big-endian. So the commit log is insane and misleading too. Alpha\nis very much little-endian, but maybe gcc turns the thing into an\nunaligned load followed by a bswap.\n\n                      Linus\n"},{"id":"195053","messageId":"20120714195022.GB23242@burratino","threadId":"31022","inReplyTo":"CA+55aFy+y=TCoJUQarinaduibt4i-46TAuvpp7fsAmjDZj_+3w@mail.gmail.com","subject":"Re: [PATCH maint-1.6.5] block-sha1: avoid unaligned accesses on some big-endian systems","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-07-14T19:50:22Z","receivedAt":"2012-07-14T19:50:22Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Linus Torvalds wrote:\n> On Sat, Jul 14, 2012 at 12:59 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n>> Unfortunately, on big-endian architectures, if p is a pointer to\n>> unsigned int then current gcc assumes it is properly aligned and\n>> converts this construct to a 32-bit load.\n>\n> This patch seems to entirely depend on the location of the cast. And\n> as far as I can tell, that workaround will in turn depend on just what\n> gets inlined.\n\nAfter the patch, what reason does gcc have to expect that 'block' is\n32-bit aligned except when it is?  The code (including the code I\ndidn't touch) never casts from char * to int * except in get/put_be32\non arches that don't mind unaligned accesses.\n\n[...]\n> Anyway, the whole \"noticed on alpha\" makes no sense, since alpha isn't\n> even big-endian. So the commit log is insane and misleading too.\n\nYes, true.  Thanks for catching it.\n\nJonathan\n"},{"id":"195054","messageId":"CA+55aFwKYhUtXfaRcbOmMsvQW8p+h8N9PKpxW_y1kj6L=FQQNw@mail.gmail.com","threadId":"31022","inReplyTo":"20120714195022.GB23242@burratino","subject":"Re: [PATCH maint-1.6.5] block-sha1: avoid unaligned accesses on some big-endian systems","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2012-07-14T19:55:30Z","receivedAt":"2012-07-14T19:55:30Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"On Sat, Jul 14, 2012 at 12:50 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> After the patch, what reason does gcc have to expect that 'block' is\n> 32-bit aligned except when it is?  The code (including the code I\n> didn't touch) never casts from char * to int * except in get/put_be32\n> on arches that don't mind unaligned accesses.\n\nAhh. I was looking at the cast you added:\n\n    blk_SHA1_Block(ctx, (const unsigned char *) ctx->W);\n\nbut I guess that if gcc inlines that and sees the original int type,\nit doesn't matter, because that *is* aligned.\n\nSo it's ok, but please just make blk_SHA1_Block() take a \"const void\n*\" instead and that cast can go away.\n\n               Linus\n"},{"id":"195060","messageId":"20120714205049.GA28502@burratino","threadId":"31022","inReplyTo":"CA+55aFy+y=TCoJUQarinaduibt4i-46TAuvpp7fsAmjDZj_+3w@mail.gmail.com","subject":"[PATCH maint-1.6.5 v2] block-sha1: avoid pointer conversion that violates alignment constraints","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-07-14T20:50:49Z","receivedAt":"2012-07-14T20:50:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"With 660231aa (block-sha1: support for architectures with memory\nalignment restrictions, 2009-08-12), blk_SHA1_Update was modified to\naccess 32-bit chunks of memory one byte at a time on arches that\nprefer that:\n\n\t#define get_be32(p)    ( \\\n\t\t(*((unsigned char *)(p) + 0) << 24) | \\\n\t\t(*((unsigned char *)(p) + 1) << 16) | \\\n\t\t(*((unsigned char *)(p) + 2) <<  8) | \\\n\t\t(*((unsigned char *)(p) + 3) <<  0) )\n\nThe code previously accessed these values by just using htonl(*p).\n\nUnfortunately, Michael noticed on an Alpha machine that git was using\nplain 32-bit reads anyway.  As soon as we convert a pointer to int *,\nthe compiler can assume that the object pointed to is correctly\naligned as an int (C99 section 6.3.2.3 \"pointer conversions\"\nparagraph 7), and gcc takes full advantage by converting the get_be32\ncalls back to a load and bswap and producing a whole bunch of\nunaligned access traps.\n\nSo we need to obey the alignment constraints even when only dealing\nwith pointers instead of actual values.  Do so by changing the type\nof 'data' to void *.  This patch renames 'data' to 'block' at the same\ntime to make sure all references are updated to reflect the new type.\n\nReported-and-tested-by: Michael Cree <mcree@orcon.net.nz>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nLinus Torvalds wrote:\n\n> Anyway, the whole \"noticed on alpha\" makes no sense, since alpha isn't\n> even big-endian.\n\nThanks again for catching that.  Here's a reroll.\n\n block-sha1/sha1.c |    6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/block-sha1/sha1.c b/block-sha1/sha1.c\nindex d8934757..10fd94d1 100644\n--- a/block-sha1/sha1.c\n+++ b/block-sha1/sha1.c\n@@ -100,7 +100,7 @@\n  * Where do we get the source from? The first 16 iterations get it from\n  * the input data, the next mix it from the 512-bit array.\n  */\n-#define SHA_SRC(t) get_be32(data + t)\n+#define SHA_SRC(t) get_be32((unsigned char *) block + t*4)\n #define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)\n \n #define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \\\n@@ -114,7 +114,7 @@\n #define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )\n #define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) ,  0xca62c1d6, A, B, C, D, E )\n \n-static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)\n+static void blk_SHA1_Block(blk_SHA_CTX *ctx, const void *block)\n {\n \tunsigned int A,B,C,D,E;\n \tunsigned int array[16];\n@@ -125,7 +125,7 @@ static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)\n \tD = ctx->H[3];\n \tE = ctx->H[4];\n \n-\t/* Round 1 - iterations 0-16 take their input from 'data' */\n+\t/* Round 1 - iterations 0-16 take their input from 'block' */\n \tT_0_15( 0, A, B, C, D, E);\n \tT_0_15( 1, E, A, B, C, D);\n \tT_0_15( 2, D, E, A, B, C);\n-- \n1.7.10.4\n"},{"id":"195061","messageId":"CA+55aFxHAPJi9cKVy6Mi7gunHT3PPLEQUwJBFQ4ftO2szc_dow@mail.gmail.com","threadId":"31022","inReplyTo":"20120714205049.GA28502@burratino","subject":"Re: [PATCH maint-1.6.5 v2] block-sha1: avoid pointer conversion that violates alignment constraints","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2012-07-14T20:56:17Z","receivedAt":"2012-07-14T20:56:17Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"Looks good to me. I'd suggest doing the macro argument expansion in\n\n   #define SHA_SRC(t) get_be32((unsigned char *) block + t*4)\n\nwith parenthesis around 't', but that's a fairly independent thing.\nThe old code didn't do that either.\n\n          Linus\n"},{"id":"195063","messageId":"20120714215749.GE28502@burratino","threadId":"31022","inReplyTo":"CA+55aFxHAPJi9cKVy6Mi7gunHT3PPLEQUwJBFQ4ftO2szc_dow@mail.gmail.com","subject":"[PATCH] block-sha1: put macro arguments in parentheses","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-07-14T21:57:49Z","receivedAt":"2012-07-14T21:57:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"'t' is currently always a numeric constant, but it can't hurt to\nprepare for the day that it becomes useful for a caller to pass in a\nmore complex expression.\n\nSuggested-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n block-sha1/sha1.c |    4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/block-sha1/sha1.c b/block-sha1/sha1.c\nindex 10fd94d1..6f885c43 100644\n--- a/block-sha1/sha1.c\n+++ b/block-sha1/sha1.c\n@@ -100,8 +100,8 @@\n  * Where do we get the source from? The first 16 iterations get it from\n  * the input data, the next mix it from the 512-bit array.\n  */\n-#define SHA_SRC(t) get_be32((unsigned char *) block + t*4)\n-#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)\n+#define SHA_SRC(t) get_be32((unsigned char *) block + (t)*4)\n+#define SHA_MIX(t) SHA_ROL(W((t)+13) ^ W((t)+8) ^ W((t)+2) ^ W(t), 1);\n \n #define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \\\n \tunsigned int TEMP = input(t); setW(t, TEMP); \\\n-- \n1.7.10.4\n"},{"id":"195087","messageId":"FDFB73BB-64E8-48F8-95DB-94C0EC7FFB2A@orcon.net.nz","threadId":"31022","inReplyTo":"20120714205049.GA28502@burratino","subject":"Re: [PATCH maint-1.6.5 v2] block-sha1: avoid pointer conversion that violates alignment constraints","fromName":"Michael Cree","fromEmail":"mcree@orcon.net.nz","sentAt":"2012-07-15T20:58:34Z","receivedAt":"2012-07-15T20:58:34Z","isPatch":true,"sender":{"key":"mcree@orcon.net.nz","avatar":null},"body":"Jonathan,\n\nThanks for acting so promptly on this.  Just a minor point on the  \ncommit message below.\n\nOn 15/07/2012, at 8:50 AM, Jonathan Nieder wrote:\n> Unfortunately, Michael noticed on an Alpha machine that git was using\n> plain 32-bit reads anyway.  As soon as we convert a pointer to int *,\n> the compiler can assume that the object pointed to is correctly\n> aligned as an int (C99 section 6.3.2.3 \"pointer conversions\"\n> paragraph 7), and gcc takes full advantage by converting the get_be32\n> calls back to a load and bswap and producing a whole bunch of\n> unaligned access traps.\n\nAlpha does not have a bswap (or similar) instruction.  I do recall  \nreading somewhere that one can get halfway to swapping endianness by  \ntreating a number as a VAX float and converting to IEEE float, with  \nonly a couple or so more instructions to achieve the full swap.  But I  \ndon't think that is available to us anyway because on Debian we  \ncompile for generic Alpha. I suspect that the crux of the matter is  \nthat compiling for generic Alpha also means that byte access  \ninstructions are not permitted.  In other words, all memory accesses  \nmust be long words (32bits) or quad words (64bits).  In the get_be32  \nroutine the compiler _has_ to issue 32bit memory accesses whether the  \nbase pointer is char * or int *.  If the pointer is unaligned then two  \nneighbouring aligned 32bit loads are required to ensure that all four  \nbytes are loaded.  If the pointer is aligned then a single 32bit load  \ngets all the four bytes.  Having never looked at the generated  \nassembler code, I nevertheless suspect that is the guts of the  \noptimisation --- the compiler can eliminate an access to memory if it  \nknows the pointer is aligned.\n\nCheers\nMichael.\n"},{"id":"195088","messageId":"20120715212731.GG1986@burratino","threadId":"31022","inReplyTo":"FDFB73BB-64E8-48F8-95DB-94C0EC7FFB2A@orcon.net.nz","subject":"Re: [PATCH maint-1.6.5 v2] block-sha1: avoid pointer conversion that violates alignment constraints","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-07-15T21:27:31Z","receivedAt":"2012-07-15T21:27:31Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nMichael Cree wrote:\n\n> On 15/07/2012, at 8:50 AM, Jonathan Nieder wrote:\n\n>>                   gcc takes full advantage by converting the get_be32\n>> calls back to a load and bswap and producing a whole bunch of\n>> unaligned access traps.\n>\n> Alpha does not have a bswap (or similar) instruction.\n[...]\n>                                    .  If the pointer is unaligned\n> then two neighbouring aligned 32bit loads are required to ensure\n> that all four bytes are loaded.  If the pointer is aligned then a\n> single 32bit load gets all the four bytes.  Having never looked at\n> the generated assembler code, I nevertheless suspect that is the\n> guts of the optimisation --- the compiler can eliminate an access to\n> memory if it knows the pointer is aligned.\n\nHow about:\n\n\tgcc takes full advantage by using a single 32-bit load,\n\tresulting in a whole bunch of unaligned access traps.\n\nYou can see the generated assembler with \"make block-sha1/sha1.s\" and\nreading the resulting sha1.s file in the current working directory\n(oops).  I don't have an alpha cross-compiler installed or access to\nan alpha to check for myself.\n\n-- >8 --\nSubject: Makefile: fix location of listing produced by \"make subdir/foo.s\"\n\nWhen I invoke \"make block-sha1/sha1.s\", 'make' runs $(CC) -S without\nspecifying where it should put its output and the output ends up in\n./sha1.s.  Confusing.\n\nAdd an -o option to the .s rule to fix this.  We were already doing\nthat for most compiler invocations but had forgotten it for the\nassembler listings.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nThanks,\nJonathan\n\n Makefile |    2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/Makefile b/Makefile\nindex dc709029..e8d2798f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2230,7 +2230,7 @@ $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)\n endif\n \n %.s: %.c GIT-CFLAGS FORCE\n-\t$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<\n+\t$(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<\n \n ifdef USE_COMPUTED_HEADER_DEPENDENCIES\n # Take advantage of gcc's on-the-fly dependency generation\n-- \n1.7.10.4\n"},{"id":"195100","messageId":"5003E4B1.605@orcon.net.nz","threadId":"31022","inReplyTo":"20120715212731.GG1986@burratino","subject":"Re: [PATCH maint-1.6.5 v2] block-sha1: avoid pointer conversion that violates alignment constraints","fromName":"Michael Cree","fromEmail":"mcree@orcon.net.nz","sentAt":"2012-07-16T09:53:53Z","receivedAt":"2012-07-16T09:53:53Z","isPatch":true,"sender":{"key":"mcree@orcon.net.nz","avatar":null},"body":"On 16/07/12 09:27, Jonathan Nieder wrote:\n> Michael Cree wrote:\n> \n>> On 15/07/2012, at 8:50 AM, Jonathan Nieder wrote:\n> \n>>>                   gcc takes full advantage by converting the get_be32\n>>> calls back to a load and bswap and producing a whole bunch of\n>>> unaligned access traps.\n>>\n>> Alpha does not have a bswap (or similar) instruction.\n> [...]\n>>                                    .  If the pointer is unaligned\n>> then two neighbouring aligned 32bit loads are required to ensure\n>> that all four bytes are loaded.  If the pointer is aligned then a\n>> single 32bit load gets all the four bytes.  Having never looked at\n>> the generated assembler code, I nevertheless suspect that is the\n>> guts of the optimisation --- the compiler can eliminate an access to\n>> memory if it knows the pointer is aligned.\n> \n> How about:\n> \n> \tgcc takes full advantage by using a single 32-bit load,\n> \tresulting in a whole bunch of unaligned access traps.\n\nYes, that's good.\n\nI just checked the generated assembler and I am correct except that I\nunderestimated the number of memory accesses for the a priori known\nunaligned data case.  It is actually doing four long-word memory access,\ni.e. a memory access for each individual byte despite that it only needs\nto do a maximum of two, so the optimisation for the a priori known\naligned data saves three memory accesses, not just one.  (And probably\nalso saves on a load-load replay trap on the EV6 and later CPUs, i.e., a\ncomplete and very costly replay of the whole pipeline when the CPU\nrealises just in the nick of time that it has cocked up the\ninterrelationships between reordered load instructions.)\n\nCheers\nMichael.\n"}]}