2016-08-18 3 views
4

나는 부동 소수점 값의 배열을 가지고 있으며, 나는 그것들 모두의 합계를 취한 다음 그 합계로 모든 것을 나누는 것과 같이 쉽게 vectorizable 연산을 할 필요가있다. 또한 배열의 개별 요소에 액세스 (대부분 읽기)해야합니다. 나는 배열의 벡터화를 가능하게하기 위해 SIMD 타입을 사용할 수 있다고 생각했다.이 변환은 SIMD의 배열에서 일반 숫자 유형으로 정의되지 않은 동작입니까?

extern crate simd; 

use simd::x86::avx::f32x8; 

fn main() { 
    let values8: [f32x8; 100] = [f32x8::splat(1.1); 100]; 
    let values: &[f32; 800] = unsafe { std::mem::transmute(&values8) }; 

    println!("{}", values[333]); 
} 
: 나는 배열의 개별 요소와 많은 일을해야 할 것입니다 때마다, 나는 그렇게처럼, 대신에 참조하는 일반 부동 소수점 값의 배열에 대한 참조로 배열 및 액세스를 버리는 것

이것은 컴파일되고 정상적으로 작동하는 것 같습니다. I read 때문에 그러나 나는이 정의되지 않은 동작이 걱정 해요 : 비에 repr (C) 유형 간의

변형의이 UB

이다 내가 생각 SIMD 유형 (simd::x86::avx::f32x8을 같은)이다 repr(simd) 내가 돈 [f32; 800]repr(C)이라고 생각하지 마십시오.

이러한 부동 소수점 값을 얻기 위해 extract 메서드를 SIMD 형식에서 사용할 수 있지만 앞에서 설명한 변환 ​​- 투 - 규칙 배열 방식을 사용하면 코드가 훨씬 간단 해집니다.

+0

나는 반 방법이 될 것입니다 VEC가하는 것처럼 f32x8'은'대출'<[f32]>를 구현하지 않는 이유'좋은 이유가 거기에 있는지 알고 싶네 집. 어쩌면 레이아웃/순서가 호환되는 것은 아닙니다. –

답변

2

this Pre-RFC의 초기 정의는

하는에 repr (SIMD) 타입의 필드에 대한 내부 기준을 불법이라고 주장 때문에 논리 값의 표현 부울은 비트가 채워지도록 변경해야 할 수도 있습니다. SIMD 지원을 제공하는 공식 외부 라이브러리에는 개인 필드가 있으므로 일반적으로 관찰 할 수 없습니다.

이것은 분명히 simd 형식을 배열로 바꾸는 것을 금지합니다.

실제로는 RFC changed입니다. 따라서 분명히 내부 내용을 참조 할 수 있습니다. RFC는 또한 레이아웃과 정렬이 플랫폼에 달려 있다고 말합니다.

내가 f32x8처럼 사소한 SIMD 유형에 패딩을 추가하지 마십시오 알고있는 모든 플랫폼 때문에, 당신은 f32x8의 레이아웃 측면에서 [f32; 8]가 8 개 f32들 단단히 포함으로 "동일한"이라고 가정 할 수있다 32 바이트 메모리로 압축되어 있습니다. 그러나 순서는 임의적 일 수 있습니다.


내가 SIMD 형태를 생각 SIMD (같은 : 86 : AVX :: f32x8)에 repr (SIMD)이다 "비에 repr (C) 유형 간의 변형의는 UB는"나는 생각하지 않는다 [f32; 800]은 repr (C)입니다.

기술적으로 당신은 어느 쪽도 repr(simd) 타입도 아니고 [f32; 800]을 변형의되지 않으며, 다른 참조에 대한 참조를 변형의있다,하지만 결과는 동일합니다.


@Chris Emerson이 언급했듯이, 예를 들어 안전하지 않은 것은 평생 사슬을 끊은 것입니다. 그것을 복원하기 위해, 추상화 경계를 만듭니다

fn simd_slice(simd: &[f32x8; 100]) -> &[f32; 800] { 
    unsafe { &*(simd as *const [f32x8; 100] as *const [f32; 800]) } 
} 
+0

* "순서는 임의적 일 수 있습니다."*이 예제에서는'values8 [0] .extract (5)'는 반드시'values ​​[5]'와 같은 값을 반환하지 않는다는 뜻입니까? – kmky

+1

예, 그것이 그 진술의 의미입니다. 순서는 플랫폼에 따라 다르기 때문에 llvm이 simd로 수행하는 작업이나 simd로 수행하는 아키텍처를 읽어야 할 수도 있습니다. –

1

특정 보장이 없으면 (내가 찾을 수 없음) 사용자가 안전하다고 결론 지을 수 없다고 생각합니다.

실제로 위에서 쓴 것처럼 약간 다른 이유 때문에 확실히 안전하지 않습니다. 당신은 values8에 대한 참조를 뽑았습니다. 이것은 borrow checker에 의해 추적되지 않습니다; 그것은 나를 이렇게하자

extern crate simd; 

use simd::f32x4; 

fn main() { 
    let mut values8: [f32x4; 100] = [f32x4::splat(1.1); 100]; 
    let values: &[f32; 400] = unsafe { std::mem::transmute(&values8) }; 

    let t = &mut values8[4]; 
    println!("{}", values[333]); // but there's a mutable reference! 
} 
+0

하지만 대부분의 경우 이미 변환을 수행하는 것이 정의되지 않은 동작인지 또는 나중에 메모리 기반 방식으로 결과 참조 변수를 사용한다고 가정하고 변환을 수행하는 것이 좋습니다. – kmky

+0

그냥 메모리 안전 방식으로 사용하면 메모리가 안전하지 않으므로 추상화 경계가 필요합니다. 따라서 모든 안전하지 못한 것을 기능에 버리면 수명을 올바르게 설정하면 그 기능 밖에서 잘못 사용할 수 없습니다. –

관련 문제