AGENTS.md
This commit is contained in:
parent
087c8b32c3
commit
b701059c8c
7 changed files with 331 additions and 62 deletions
|
|
@ -6,8 +6,8 @@ import std;
|
|||
import :VectorF32;
|
||||
|
||||
namespace Crafter {
|
||||
template<typename T>
|
||||
constexpr T ToRadian(T degrees) {
|
||||
export template<typename T>
|
||||
constexpr T ToRadian(T degrees) {
|
||||
return degrees * (std::numbers::pi / 180);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,10 +186,17 @@ namespace Crafter {
|
|||
template <std::array<std::uint8_t, Len> ShuffleValues>
|
||||
static consteval bool CheckEpi32Shuffle() {
|
||||
if constexpr (PerLane == 8) {
|
||||
for(std::uint8_t i = 1; i < Len; i+=2) {
|
||||
if(ShuffleValues[i-1] != ShuffleValues[i] - 1) {
|
||||
return false;
|
||||
}
|
||||
// 16-bit lanes move as 32-bit words: every output word has to
|
||||
// take both halves of one source word, in order. The check
|
||||
// used to accept any two consecutive sources, (1, 2) included,
|
||||
// so Shuffle<{{1,2,0}}> on a VectorF16 took the epi32 path and
|
||||
// came out wrong. An odd Len puts the second slot half a word
|
||||
// off, so only Packing 1 can qualify then, and its last lane
|
||||
// has to be a word's low half.
|
||||
if (Len % 2 != 0 && Packing > 1) return false;
|
||||
for (std::uint8_t i = 0; i < Len; i += 2) {
|
||||
if (ShuffleValues[i] % 2 != 0) return false;
|
||||
if (i + 1 < Len && ShuffleValues[i + 1] != ShuffleValues[i] + 1) return false;
|
||||
}
|
||||
}
|
||||
for(std::uint8_t i = 0; i < Len; i++) {
|
||||
|
|
@ -300,9 +307,13 @@ namespace Crafter {
|
|||
|
||||
template <std::array<std::uint8_t, Len> ShuffleValues>
|
||||
static consteval std::uint8_t GetShuffleMaskEpi32() {
|
||||
// One 2-bit field per 32-bit word, four words to the immediate; a
|
||||
// word holds perWord elements, so a 16-bit lane index is halved
|
||||
// (the old shift of 4 * i for halves ran off the 8-bit immediate).
|
||||
constexpr std::uint8_t perWord = 4 / sizeof(T);
|
||||
std::uint8_t mask = 0;
|
||||
for(std::uint8_t i = 0; i < std::min(Len, std::uint8_t(8)); i+=4/sizeof(T)) {
|
||||
mask = mask | (ShuffleValues[i] & 0b11) << (8 / sizeof(T) * i);
|
||||
for (std::uint8_t i = 0; i < std::min<std::uint8_t>(Len, 4 * perWord); i += perWord) {
|
||||
mask = mask | (((ShuffleValues[i] / perWord) & 0b11) << (2 * (i / perWord)));
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -443,50 +443,21 @@ namespace Crafter {
|
|||
}
|
||||
}
|
||||
|
||||
// Through Shuffle, as VectorF32::Cross is: it checks whether every lane
|
||||
// move stays inside its 128-bit lane and takes a full permute when one
|
||||
// does not. This used to call _mm*_shuffle_epi8 directly, which
|
||||
// shuffles bytes per 128-bit lane only, so in a 256- or 512-bit
|
||||
// register a 3-vector whose halves straddle a lane boundary (the third
|
||||
// of every eight for Packing 8, say) came out wrong.
|
||||
constexpr static VectorF16<Len, Packing> Cross(VectorF16<Len, Packing> a, VectorF16<Len, Packing> b) requires(Len == 3) {
|
||||
if constexpr(std::is_same_v<typename VectorBase<Len, Packing, _Float16>::VectorType, __m128h>) {
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask1 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{1,2,0}}>();
|
||||
__m128i shuffleVec1 = _mm_loadu_epi8(shuffleMask1.data());
|
||||
__m128h row1 = _mm_castsi128_ph(_mm_shuffle_epi8(_mm_castph_si128(a.v), shuffleVec1));
|
||||
__m128h row4 = _mm_castsi128_ph(_mm_shuffle_epi8(_mm_castph_si128(b.v), shuffleVec1));
|
||||
VectorF16<Len, Packing> row1 = a.template Shuffle<{{1,2,0}}>();
|
||||
VectorF16<Len, Packing> row4 = b.template Shuffle<{{1,2,0}}>();
|
||||
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask3 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{2,0,1}}>();
|
||||
__m128i shuffleVec3 = _mm_loadu_epi8(shuffleMask3.data());
|
||||
__m128h row3 = _mm_castsi128_ph(_mm_shuffle_epi8(_mm_castph_si128(a.v), shuffleVec3));
|
||||
__m128h row2 = _mm_castsi128_ph(_mm_shuffle_epi8(_mm_castph_si128(b.v), shuffleVec3));
|
||||
VectorF16<Len, Packing> row3 = a.template Shuffle<{{2,0,1}}>();
|
||||
VectorF16<Len, Packing> row2 = b.template Shuffle<{{2,0,1}}>();
|
||||
|
||||
__m128h result = _mm_mul_ph(row3, row4);
|
||||
return _mm_fmsub_ph(row1,row2,result);
|
||||
} else if constexpr (std::is_same_v<typename VectorBase<Len, Packing, _Float16>::VectorType, __m256h>) {
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask1 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{1,2,0}}>();
|
||||
__m512i shuffleVec1 = _mm512_castsi256_si512(_mm256_loadu_epi8(shuffleMask1.data()));
|
||||
__m256h row1 = _mm256_castsi256_ph(_mm512_castsi512_si256(_mm512_shuffle_epi8(_mm512_castsi256_si512(_mm256_castph_si256(a.v)), shuffleVec1)));
|
||||
__m256h row4 = _mm256_castsi256_ph(_mm512_castsi512_si256(_mm512_shuffle_epi8(_mm512_castsi256_si512(_mm256_castph_si256(b.v)), shuffleVec1)));
|
||||
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask3 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{2,0,1}}>();
|
||||
|
||||
__m512i shuffleVec3 = _mm512_castsi256_si512(_mm256_loadu_epi8(shuffleMask3.data()));
|
||||
__m256h row3 = _mm256_castsi256_ph(_mm512_castsi512_si256(_mm512_shuffle_epi8(_mm512_castsi256_si512(_mm256_castph_si256(a.v)), shuffleVec3)));
|
||||
__m256h row2 = _mm256_castsi256_ph(_mm512_castsi512_si256(_mm512_shuffle_epi8(_mm512_castsi256_si512(_mm256_castph_si256(b.v)), shuffleVec3)));
|
||||
|
||||
__m256h result = _mm256_mul_ph(row3, row4);
|
||||
return _mm256_fmsub_ph(row1,row2,result);
|
||||
} else {
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask1 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{1,2,0}}>();
|
||||
|
||||
__m512i shuffleVec1 = _mm512_loadu_epi8(shuffleMask1.data());
|
||||
__m512h row1 = _mm512_castsi512_ph(_mm512_shuffle_epi8(_mm512_castph_si512(a.v), shuffleVec1));
|
||||
__m512h row4 = _mm512_castsi512_ph(_mm512_shuffle_epi8(_mm512_castph_si512(b.v), shuffleVec1));
|
||||
|
||||
constexpr std::array<std::uint8_t, VectorBase<Len, Packing, _Float16>::AlignmentElement*2> shuffleMask3 = VectorBase<Len, Packing, _Float16>::template GetShuffleMaskEpi8<{{2,0,1}}>();
|
||||
|
||||
__m512i shuffleVec3 = _mm512_loadu_epi8(shuffleMask3.data());
|
||||
__m512h row3 = _mm512_castsi512_ph(_mm512_shuffle_epi8(_mm512_castph_si512(a.v), shuffleVec3));
|
||||
__m512h row2 = _mm512_castsi512_ph(_mm512_shuffle_epi8(_mm512_castph_si512(b.v), shuffleVec3));
|
||||
|
||||
__m512h result = _mm512_mul_ph(row3, row4);
|
||||
return _mm512_fmsub_ph(row1,row2,result);
|
||||
}
|
||||
VectorF16<Len, Packing> result = row3 * row4;
|
||||
return VectorF16<Len, Packing>::MulitplySub(row1, row2, result);
|
||||
}
|
||||
|
||||
constexpr static _Float16 Dot(VectorF16<Len, Packing> a, VectorF16<Len, Packing> b) requires(Packing == 1) {
|
||||
|
|
@ -1007,12 +978,10 @@ namespace Crafter {
|
|||
return v + t * q.template Shuffle<{{3,3,3,3}}>() + Cross(qv, t);
|
||||
}
|
||||
|
||||
constexpr static VectorF16<4, 2> RotatePivot(VectorF16<3, Packing> v, VectorF16<4, Packing> q, VectorF16<3, Packing> pivot) requires(Len == 3) {
|
||||
VectorF16<Len, Packing> translated = v - pivot;
|
||||
VectorF16<3, Packing> qv(q.v);
|
||||
VectorF16<Len, Packing> t = Cross(qv, translated) * _Float16(2);
|
||||
VectorF16<Len, Packing> rotated = translated + t * q.template Shuffle<{{3,3,3,3}}>() + Cross(qv, t);
|
||||
return rotated + pivot;
|
||||
// Through Rotate, like the other backends; see VectorF32's note.
|
||||
constexpr static VectorF16<3, Packing> RotatePivot(VectorF16<3, Packing> v, VectorF16<4, Packing> q, VectorF16<3, Packing> pivot) requires(Len == 3) {
|
||||
VectorF16<3, Packing> translated = v - pivot;
|
||||
return Rotate(translated, q) + pivot;
|
||||
}
|
||||
|
||||
constexpr static VectorF16<4, Packing> QuanternionFromEuler(VectorF16<3, Packing> EulerHalf) requires(Len == 4) {
|
||||
|
|
|
|||
|
|
@ -1366,12 +1366,13 @@ namespace Crafter {
|
|||
return v + t * q.template Shuffle<{{3,3,3,3}}>() + Cross(qv, t);
|
||||
}
|
||||
|
||||
constexpr static VectorF32<4, 2> RotatePivot(VectorF32<3, Packing> v, VectorF32<4, Packing> q, VectorF32<3, Packing> pivot) requires(Len == 3) {
|
||||
VectorF32<Len, Packing> translated = v - pivot;
|
||||
VectorF32<3, Packing> qv(q.v);
|
||||
VectorF32<Len, Packing> t = Cross(qv, translated) * float(2);
|
||||
VectorF32<Len, Packing> rotated = translated + t * q.template Shuffle<{{3,3,3,3}}>() + Cross(qv, t);
|
||||
return rotated + pivot;
|
||||
// Through Rotate, like the other backends: it repacks the quaternion's
|
||||
// xyz lanes into the 3-vector layout. This used to repeat Rotate's
|
||||
// arithmetic with the register taken as is (qv(q.v)), which only lines
|
||||
// up for Packing 1, and to return a VectorF32<4, 2> whatever the shape.
|
||||
constexpr static VectorF32<3, Packing> RotatePivot(VectorF32<3, Packing> v, VectorF32<4, Packing> q, VectorF32<3, Packing> pivot) requires(Len == 3) {
|
||||
VectorF32<3, Packing> translated = v - pivot;
|
||||
return Rotate(translated, q) + pivot;
|
||||
}
|
||||
|
||||
constexpr static VectorF32<4, Packing> QuanternionFromEuler(VectorF32<3, Packing> EulerHalf) requires(Len == 4) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue