2012-01-29 29 views
7

Tôi gặp sự cố với phương pháp SSE mà tôi đang viết thực hiện xử lý âm thanh. Tôi đã thực hiện một chức năng ngẫu nhiên SSE dựa trên giấy của Intel ở đây:SSE nội tại gây ra hoạt động nổi bình thường để trả về -1. # INV

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

Tôi cũng có một phương pháp mà đang thực hiện chuyển đổi từ phao để S16 sử dụng SSE cũng có, việc chuyển đổi được thực hiện khá đơn giản như sau:

unsigned int Float_S16LE(float *data, const unsigned int samples, uint8_t *dest) 
{ 
    int16_t *dst = (int16_t*)dest; 
    const __m128 mul = _mm_set_ps1((float)INT16_MAX); 
    __m128 rand; 
    const uint32_t even = count & ~0x3; 
    for(uint32_t i = 0; i < even; i += 4, data += 4, dst += 4) 
    { 
    /* random round to dither */ 
    FloatRand4(-0.5f, 0.5f, NULL, &rand); 

    __m128 rmul = _mm_add_ps(mul, rand); 
    __m128 in = _mm_mul_ps(_mm_load_ps(data),rmul); 
    __m64 con = _mm_cvtps_pi16(in); 

    memcpy(dst, &con, sizeof(int16_t) * 4); 
    } 
} 

FloatRand4 được định nghĩa như sau:

static inline void FloatRand4(const float min, const float max, float result[4], __m128 *sseresult = NULL) 
{ 
    const float delta = (max - min)/2.0f; 
    const float factor = delta/(float)INT32_MAX; 
    ... 
} 

Nếu sseresult != NULL cácKết quảđược trả về và result không được sử dụng. Điều này thực hiện hoàn hảo trên vòng đầu tiên, nhưng trên vòng lặp tiếp theo delta trở thành -1.#INF thay vì 1.0. Nếu tôi nhận xét ra dòng __m64 con = _mm_cvtps_pi16(in); sự cố sẽ biến mất.

Tôi nghĩ rằng FPU đang đi vào trạng thái không xác định hoặc điều gì đó.

+0

_mm_cvtps_pi16 là một ý tưởng tồi. Sử dụng kết hợp _mm_cvtps_epi32, _mm_packs_epi32 và _mm_store_si128/_mm_storeu_si128 để chuyển đổi 8 float thành 8 int16_t và sự cố của bạn đã biến mất! –

Trả lời

9

Trộn SSE Integer số học và (thường xuyên) Floating điểm môn toán. Có thể tạo ra kết quả lạ vì cả hai đều đang hoạt động trên cùng một thanh ghi. Nếu bạn sử dụng:

_mm_empty() 

FPU được đặt lại thành trạng thái chính xác. Microsoft có Guidelines for When to Use EMMS

+0

Chính xác vấn đề, cảm ơn! – Geoffrey

+1

không phải chỉ vì _mm_cvtps_pi16? Tôi nghĩ _mm_empty chỉ là MMX. Vì vậy, tôi sẽ thay thế điều này, vì _mm_empty tốn kém AFAIK. – Sam

+0

Có, giải pháp chính xác hơn là loại bỏ các chỉ dẫn FPU đó và dính vào SSE cho đến khi hoàn thành, nhưng đây là câu trả lời đúng vì nó giải thích tại sao nó lại xảy ra. – Geoffrey

1
  • _mm_load_ps không được đảm bảo thực hiện tải được căn chỉnh. dữ liệu float * có thể được căn chỉnh thành 4 byte thay vì 16 _ => _mm_loadu_ps
  • memcpy có thể sẽ tiêu diệt các lợi ích đạt được với SSE, bạn nên sử dụng lệnh cửa hàng cho __m64 nhưng ở đây một lần nữa, chú ý đến căn chỉnh. Nếu không thể thực hiện luồng không có dấu hoặc lưu trữ __m64, tôi sẽ giữ nó trong một _m128i và thực hiện ghi mặt nạ bằng _mm_maskmoveu_si128 hoặc lưu trữ 8 byte đó bằng tay.

http://msdn.microsoft.com/en-us/library/bytwczae.aspx

+0

Cảm ơn lời khuyên, tôi nên đã tuyên bố rằng mã liên kết được bỏ qua từ mẫu được đăng, tất cả dữ liệu được truyền cho phương pháp này đều được căn chỉnh. – Geoffrey

+0

Bạn sẽ lưu trữ 8 byte bằng tay như thế nào? – Geoffrey

+1

Tôi nghĩ về một liên minh với một mảng uint8_t [8] để sao chép thủ công. Nhưng luôn luôn có vấn đề, rằng các cấu trúc như vậy (và memcpy) có thể gây ra 'lưu trữ để tải'. Vì vậy, việc chuyển __int64 (hoặc hai trong số chúng) vào thanh ghi 128bit và làm _mm_maskmoveu_si128 hoặc _mm_stream * tương ứng sẽ hiệu quả hơn. Phát trực tuyến tránh ô nhiễm bộ nhớ cache với đầu ra, điều này có thể được quan tâm, kể từ khi được viết, bạn không cần lại nó ngay lập tức. – Sam

Các vấn đề liên quan