読者です 読者をやめる 読者になる 読者になる

とりあえず動いた memcpy4

 

// g++ -g -Wall -std=c++14 -o memcpy4 memcpy4.cpp
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <cassert>
#include <iostream>
using namespace std; #define ASSERTF(assertion, ...) do { if (!(assertion)) { assertf(__FILE__, __LINE__, __func__, __VA_ARGS__); }} while(0) void assertf(const char* file, int line, const char* func, const char* format, ...) { va_list ap; printf("%s:%d:%s: assertion failed: ", file, line, func); va_start(ap, format); vprintf(format, ap); va_end(ap); abort(); } // 4byte 単位でしかハードアクセスできないメモリコピー void memcpy4(void* dest, void* src, size_t size) { //memcpy(dest, src, size); size_t remain_size = size; // 残りのサイズ(バイト数) size_t copy_total = 0; // 読み取りバッファから書き込みバッファにコピーした総バイト数 // 読み取りデータの情報 size_t rd_boff = (size_t)src & 3; // 読み取り開始オフセット //size_t rd_eoff = rd_boff + size; // 読み取り終了オフセット(この値を含まない) size_t rd_beg = (size_t)src & ~3; // 読み取り開始アドレス //size_t rd_end = rd_beg + ((rd_eoff + 3) & ~3); // 読み取り終了アドレス(この値を含まない) // 書き込みデータの情報 size_t wr_boff = (size_t)dest & 3; // 書き込み開始オフセット size_t wr_eoff = wr_boff + size; // 書き込み終了オフセット(この値を含まない) size_t wr_beg = (size_t)dest & ~3; // 書き込み開始アドレス size_t wr_end = wr_beg + ((wr_eoff + 3) & ~3); // 書き込み終了アドレス(この値を含まない) // 読み取りバッファの情報 uint32_t rd_buf = 0; size_t rd_pos = rd_boff; size_t rd_remain = ((remain_size < 4) ? remain_size : 4) - rd_pos; // 書き込みバッファの情報 uint32_t wr_buf = 0; size_t wr_pos = wr_boff; size_t wr_remain = ((remain_size < 4) ? remain_size : 4) - wr_pos; // 読み取りバッファから書き込みバッファへのコピーサイズ size_t copy_size = (rd_remain < wr_remain) ? rd_remain : wr_remain; // 読み取りアドレス uint32_t* rd_addr = (uint32_t*) rd_beg; // 書き込みアドレス uint32_t* wr_addr = (uint32_t*) wr_beg; // 最初の一回目に wr_buf に読み込んでおくべきかどうか bool is_first_preload = ((wr_boff & 3) != (wr_beg & 3));
// 最後の一回で wr_buf に読み込んでおくべきかどうか
bool is_last_preload = ((wr_eoff & 3) != (wr_end & 3)); // 読み取りバッファに最初のデータを取得 rd_buf = *rd_addr; rd_addr += 1; // 最初の書き込みが 4byte アラインでない場合、範囲外のデータを壊さ // ないように書き込みバッファに読み込んでおく if (is_first_preload) { wr_buf = *wr_addr; } while ((size_t)wr_addr < wr_end) { rd_pos &= 3; rd_remain = (rd_remain != 0) ? rd_remain : ((remain_size < 4) ? remain_size : 4); wr_pos &= 3; wr_remain = (wr_remain != 0) ? wr_remain : ((remain_size < 4) ? remain_size : 4); copy_size = (rd_remain < wr_remain) ? rd_remain : wr_remain; for (size_t i = 0; i < copy_size; ++i) { ((char*)&wr_buf)[wr_pos + i] = ((char*)&rd_buf)[rd_pos + i]; } rd_pos += copy_size; rd_remain -= copy_size; wr_pos += copy_size; wr_remain -= copy_size; copy_total += copy_size; if (wr_remain == 0) { *wr_addr = wr_buf; wr_addr += 1; remain_size = size - copy_total; // 最後の書き込みが 4byte アラインでない場合、範囲外のデー // タを壊さないように書き込みバッファを読み込んでおく if (((size_t)wr_addr == wr_end - 4) && is_last_preload ) { wr_buf = *wr_addr; } } if (rd_remain == 0) { rd_buf = *rd_addr; rd_addr += 1; } } } int main(int argc, char* argv[]) { //assert(false); const size_t asize = 24; alignas(4) char obuf[asize] = {0}; alignas(4) char ibuf[asize] = {0}; size_t i; size_t opos; size_t ipos; size_t len; // input data for (i = 0; i < asize; ++i) { ibuf[i] = i; } for (opos = 0; opos <= 4; ++opos) { for (ipos = 0; ipos <= 4; ++ipos) { for (len = 8; len <= 16; ++len) { memset(obuf, 0, asize); memcpy4(obuf + opos, ibuf + ipos, len); for (i = 0; i < asize; ++i) { printf("%2d ", obuf[i]); } printf("\n"); fflush(stdout); for (i = 0; i < opos; ++i) { ASSERTF(obuf[i] == 0, "i=%d opos=%d ipos=%d len=%d obuf[i]=%d\n", (int)i, (int)opos, (int)ipos, (int)len, (int)obuf[i]); } for (; i < (opos + len); ++i) { ASSERTF(obuf[i] == ibuf[i - opos + ipos], "i=%d opos=%d ipos=%d len=%d obuf[i]=%d\n", (int)i, (int)opos, (int)ipos, (int)len, (int)obuf[i]); } for (; i < asize; ++i) { ASSERTF(obuf[i] == 0, "i=%d opos=%d ipos=%d len=%d obuf[i]=%d\n", (int)i, (int)opos, (int)ipos, (int)len, (int)obuf[i]); } } } } return 0; }