-
Notifications
You must be signed in to change notification settings - Fork 49
Add big endian support #771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,14 +62,22 @@ uint8_t memread_ubyte(memreader *reader) { | |
|
|
||
| uint16_t memread_uword(memreader *reader) { | ||
| uint16_t r; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| r = __builtin_bswap16(*((uint16_t *)(reader->buf + reader->pos))); | ||
| #else | ||
| memcpy(&r, reader->buf + reader->pos, sizeof(r)); | ||
| #endif | ||
| reader->pos += sizeof(r); | ||
| return r; | ||
| } | ||
|
|
||
| uint32_t memread_udword(memreader *reader) { | ||
| uint32_t r; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| r = __builtin_bswap32(*((uint32_t *)(reader->buf + reader->pos))); | ||
| #else | ||
| memcpy(&r, reader->buf + reader->pos, sizeof(r)); | ||
| #endif | ||
| reader->pos += sizeof(r); | ||
| return r; | ||
| } | ||
|
|
@@ -83,22 +91,37 @@ int8_t memread_byte(memreader *reader) { | |
|
|
||
| int16_t memread_word(memreader *reader) { | ||
| int16_t r; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| r = __builtin_bswap16(*((uint16_t *)(reader->buf + reader->pos))); | ||
| #else | ||
| memcpy(&r, reader->buf + reader->pos, sizeof(r)); | ||
| #endif | ||
| reader->pos += sizeof(r); | ||
| return r; | ||
| } | ||
|
|
||
| int32_t memread_dword(memreader *reader) { | ||
| int32_t r; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| r = __builtin_bswap32(*((int32_t *)(reader->buf + reader->pos))); | ||
| #else | ||
| memcpy(&r, reader->buf + reader->pos, sizeof(r)); | ||
| #endif | ||
| reader->pos += sizeof(r); | ||
| return r; | ||
| } | ||
|
|
||
| float memread_float(memreader *reader) { | ||
| float r; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| uint32_t fl; | ||
| memcpy(&fl, reader->buf + reader->pos, sizeof(fl)); | ||
| fl = __builtin_bswap32(fl); | ||
| reader->pos += sizeof(fl); | ||
| #else | ||
| memcpy(&r, reader->buf + reader->pos, sizeof(r)); | ||
| reader->pos += sizeof(r); | ||
| #endif | ||
| return r; | ||
| } | ||
|
Comment on lines
114
to
126
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think memread_float (and similar: memwrite_float, sd_read_float, etc..) for memread_float, this would look like: uint32_t u = memread_dword(reader);
float f;
memcpy(&f, &u, 4);
return f;this way, they don't need to perform any byte swapping and can be focused on just the uint-to-float bit cast.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh,, I see your point.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memread_dword performs a byteswap. memread_float is currently only used to read some tournament mode pilot variables we ignore, unsure what you mean by tested and working |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,12 +110,18 @@ uint8_t sd_read_ubyte(sd_reader *reader) { | |
| uint16_t sd_read_uword(sd_reader *reader) { | ||
| uint16_t d = 0; | ||
| sd_read_buf(reader, (char *)&d, 2); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap16(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| uint32_t sd_read_udword(sd_reader *reader) { | ||
| uint32_t d = 0; | ||
| sd_read_buf(reader, (char *)&d, 4); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap32(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
|
|
@@ -128,18 +134,31 @@ int8_t sd_read_byte(sd_reader *reader) { | |
| int16_t sd_read_word(sd_reader *reader) { | ||
| int16_t d = 0; | ||
| sd_read_buf(reader, (char *)&d, 2); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap16(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| int32_t sd_read_dword(sd_reader *reader) { | ||
| int32_t d = 0; | ||
| sd_read_buf(reader, (char *)&d, 4); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap32(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| float sd_read_float(sd_reader *reader) { | ||
| float f = 0; | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| uint32_t r = 0; | ||
| sd_read_buf(reader, (char *)&r, 4); | ||
| r = __builtin_bswap32(r); | ||
| memcpy(&f, &r, sizeof(f)); | ||
| #else | ||
| sd_read_buf(reader, (char *)&f, 4); | ||
| #endif | ||
| return f; | ||
| } | ||
|
|
||
|
|
@@ -152,12 +171,18 @@ uint8_t sd_peek_ubyte(sd_reader *reader) { | |
| uint16_t sd_peek_uword(sd_reader *reader) { | ||
| uint16_t d = 0; | ||
| sd_peek_buf(reader, (char *)&d, 2); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap16(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| uint32_t sd_peek_udword(sd_reader *reader) { | ||
| uint32_t d = 0; | ||
| sd_peek_buf(reader, (char *)&d, 4); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap32(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
|
|
@@ -170,18 +195,27 @@ int8_t sd_peek_byte(sd_reader *reader) { | |
| int16_t sd_peek_word(sd_reader *reader) { | ||
| int16_t d = 0; | ||
| sd_peek_buf(reader, (char *)&d, 2); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap16(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| int32_t sd_peek_dword(sd_reader *reader) { | ||
| int32_t d = 0; | ||
| sd_peek_buf(reader, (char *)&d, 4); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| d = __builtin_bswap32(d); | ||
| #endif | ||
| return d; | ||
| } | ||
|
|
||
| float sd_peek_float(sd_reader *reader) { | ||
| float f = 0; | ||
| sd_peek_buf(reader, (char *)&f, 4); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| f = __builtin_bswap16(f); | ||
| #endif | ||
|
Comment on lines
214
to
+218
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. __builtin_bswap16 does not take an argument of type float, it takes a uint16_t. Also: bswap16 is the wrong number of bits, should be bswap32. (same as other review comment: please implement sd_peek_float in terms of sd_peek_dword)
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the exceptions were definitely from doing float f = __buildin_bswap32((float)x); |
||
| return f; | ||
| } | ||
|
|
||
|
|
@@ -213,6 +247,16 @@ int sd_read_line(const sd_reader *reader, char *buffer, int maxlen) { | |
| if(fgets(buffer, maxlen, reader->handle) == NULL) { | ||
| return 1; | ||
| } | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| int len = maxlen; | ||
| for(int i = 0; i < len / 4; i += 1) { | ||
| ((int *)buffer)[i] = __builtin_bswap32(((int *)buffer)[i]); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
please memcpy to a uint32_t local variable (and uint16_t local var for the final-2-bytes bytes-swap) |
||
| } | ||
|
|
||
| if((len & 3) == 2) { | ||
| ((uint16_t *)buffer)[(len / 2) - 1] = __builtin_bswap16(((uint16_t *)buffer)[(len / 2) - 1]); | ||
| } | ||
| #endif | ||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -231,6 +275,15 @@ void sd_read_str(sd_reader *r, str *dst) { | |
| if(len > 0) { | ||
| char *buf = omf_calloc(1, len + 1); | ||
| sd_read_buf(r, buf, len); | ||
| #ifdef BIG_ENDIAN_BUILD | ||
| for(int i = 0; i < len / 4; i += 1) { | ||
| ((int *)buf)[i] = __builtin_bswap32(((int *)buf)[i]); | ||
| } | ||
|
|
||
| if((len & 3) == 2) { | ||
| ((uint16_t *)buf)[(len / 2) - 1] = __builtin_bswap16(((uint16_t *)buf)[(len / 2) - 1]); | ||
| } | ||
| #endif | ||
| str_from_c(dst, buf); | ||
| omf_free(buf); | ||
| } else { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buf+pos is not insufficiently aligned to be a (uint16_t *)
please use the memcpy from the existing code, and keep your #ifdef block as small as possible (your sd_peek_dword is a good example of how it should look).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've thought about this, and it hasn't been an issue with the current game assets. I don't want to slow it down more than needed.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on a platform with "free" unaligned reads (x86, N64?), memcpy'ing the four bytes should compile to equivalent assembly as the hazardous uint16 reads (which are innocuous on x86(/n64?) without ubsan).
Dereferencing an unaligned pointer is undefined behavior, and traps on more-or-less common architectures (the ARM family, which even supported big endian back in armv5).
Have you observed a pessimization when using memcpy in these functions, or a big difference in assembly? I would expect GCC to be very good at optimizing a four byte memcpy.