[WebAssembly] Use functions instead of macros for const SIMD intrinsics

To improve hygiene, consistency, and usability, it would be good to replace all
the macro intrinsics in wasm_simd128.h with functions. The reason for using
macros in the first place was to enforce the use of constants for some arguments
using `_Static_assert` with `__builtin_constant_p`. This commit switches to
using functions and uses the `__diagnose_if__` attribute rather than
`_Static_assert` to enforce constantness.

The remaining macro intrinsics cannot be made into functions until the builtin
functions they are implemented with can be replaced with normal code patterns
because the builtin functions themselves require that their arguments are
constants.

This commit also fixes a bug with the const_splat intrinsics in which the f32x4
and f64x2 variants were incorrectly producing integer vectors.

Differential Revision: https://reviews.llvm.org/D102018
This commit is contained in:
Thomas Lively 2021-05-07 11:50:19 -07:00
parent 724604901a
commit 1e9c39a3f9
2 changed files with 78 additions and 75 deletions

View File

@ -48,8 +48,9 @@ typedef unsigned int __u32x2
__attribute__((__always_inline__, __nodebug__, __target__("simd128"), \
__min_vector_width__(128)))
#define __REQUIRE_CONSTANT(e) \
_Static_assert(__builtin_constant_p(e), "Expected constant")
#define __REQUIRE_CONSTANT(c) \
__attribute__((__diagnose_if__(!__builtin_constant_p(c), \
#c " must be constant", "error")))
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_load(const void *__mem) {
// UB-free unaligned access copied from xmmintrin.h
@ -246,88 +247,90 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_make(double __c0,
return (v128_t)(__f64x2){__c0, __c1};
}
#define wasm_i8x16_const(__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7, __c8, \
__c9, __c10, __c11, __c12, __c13, __c14, __c15) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
__REQUIRE_CONSTANT(__c2); \
__REQUIRE_CONSTANT(__c3); \
__REQUIRE_CONSTANT(__c4); \
__REQUIRE_CONSTANT(__c5); \
__REQUIRE_CONSTANT(__c6); \
__REQUIRE_CONSTANT(__c7); \
__REQUIRE_CONSTANT(__c8); \
__REQUIRE_CONSTANT(__c9); \
__REQUIRE_CONSTANT(__c10); \
__REQUIRE_CONSTANT(__c11); \
__REQUIRE_CONSTANT(__c12); \
__REQUIRE_CONSTANT(__c13); \
__REQUIRE_CONSTANT(__c14); \
__REQUIRE_CONSTANT(__c15); \
(v128_t)(__i8x16){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7, \
__c8, __c9, __c10, __c11, __c12, __c13, __c14, __c15}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS
wasm_i8x16_const(int8_t __c0, int8_t __c1, int8_t __c2, int8_t __c3,
int8_t __c4, int8_t __c5, int8_t __c6, int8_t __c7,
int8_t __c8, int8_t __c9, int8_t __c10, int8_t __c11,
int8_t __c12, int8_t __c13, int8_t __c14, int8_t __c15)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2)
__REQUIRE_CONSTANT(__c3) __REQUIRE_CONSTANT(__c4)
__REQUIRE_CONSTANT(__c5) __REQUIRE_CONSTANT(__c6)
__REQUIRE_CONSTANT(__c7) __REQUIRE_CONSTANT(__c8)
__REQUIRE_CONSTANT(__c9) __REQUIRE_CONSTANT(__c10)
__REQUIRE_CONSTANT(__c11) __REQUIRE_CONSTANT(__c12)
__REQUIRE_CONSTANT(__c13) __REQUIRE_CONSTANT(__c14)
__REQUIRE_CONSTANT(__c15) {
return (v128_t)(__i8x16){__c0, __c1, __c2, __c3, __c4, __c5,
__c6, __c7, __c8, __c9, __c10, __c11,
__c12, __c13, __c14, __c15};
}
#define wasm_i16x8_const(__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
__REQUIRE_CONSTANT(__c2); \
__REQUIRE_CONSTANT(__c3); \
__REQUIRE_CONSTANT(__c4); \
__REQUIRE_CONSTANT(__c5); \
__REQUIRE_CONSTANT(__c6); \
__REQUIRE_CONSTANT(__c7); \
(v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS
wasm_i16x8_const(int16_t __c0, int16_t __c1, int16_t __c2, int16_t __c3,
int16_t __c4, int16_t __c5, int16_t __c6, int16_t __c7)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2)
__REQUIRE_CONSTANT(__c3) __REQUIRE_CONSTANT(__c4)
__REQUIRE_CONSTANT(__c5) __REQUIRE_CONSTANT(__c6)
__REQUIRE_CONSTANT(__c7) {
return (v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7};
}
#define wasm_i32x4_const(__c0, __c1, __c2, __c3) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
__REQUIRE_CONSTANT(__c2); \
__REQUIRE_CONSTANT(__c3); \
(v128_t)(__i32x4){__c0, __c1, __c2, __c3}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS
wasm_i32x4_const(int32_t __c0, int32_t __c1, int32_t __c2, int32_t __c3)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2)
__REQUIRE_CONSTANT(__c3) {
return (v128_t)(__i32x4){__c0, __c1, __c2, __c3};
}
#define wasm_i64x2_const(__c0, __c1) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
(v128_t)(__i64x2){__c0, __c1}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_const(int64_t __c0,
int64_t __c1)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) {
return (v128_t)(__i64x2){__c0, __c1};
}
#define wasm_f32x4_const(__c0, __c1, __c2, __c3) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
__REQUIRE_CONSTANT(__c2); \
__REQUIRE_CONSTANT(__c3); \
(v128_t)(__f32x4){__c0, __c1, __c2, __c3}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS
wasm_f32x4_const(float __c0, float __c1, float __c2, float __c3)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2)
__REQUIRE_CONSTANT(__c3) {
return (v128_t)(__f32x4){__c0, __c1, __c2, __c3};
}
#define wasm_f64x2_const(__c0, __c1) \
__extension__({ \
__REQUIRE_CONSTANT(__c0); \
__REQUIRE_CONSTANT(__c1); \
(v128_t)(__f64x2){__c0, __c1}; \
})
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_const(double __c0,
double __c1)
__REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) {
return (v128_t)(__f64x2){__c0, __c1};
}
#define wasm_i8x16_const_splat(__c) \
wasm_i8x16_const(__c, __c, __c, __c, __c, __c, __c, __c, __c, __c, __c, __c, \
__c, __c, __c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_const_splat(int8_t __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__i8x16){__c, __c, __c, __c, __c, __c, __c, __c,
__c, __c, __c, __c, __c, __c, __c, __c};
}
#define wasm_i16x8_const_splat(__c) \
wasm_i16x8_const(__c, __c, __c, __c, __c, __c, __c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_const_splat(int16_t __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__i16x8){__c, __c, __c, __c, __c, __c, __c, __c};
}
#define wasm_i32x4_const_splat(__c) wasm_i32x4_const(__c, __c, __c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_const_splat(int32_t __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__i32x4){__c, __c, __c, __c};
}
#define wasm_i64x2_const_splat(__c) wasm_i64x2_const(__c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_const_splat(int64_t __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__i64x2){__c, __c};
}
#define wasm_f32x4_const_splat(__c) wasm_i32x4_const(__c, __c, __c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_const_splat(float __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__f32x4){__c, __c, __c, __c};
}
#define wasm_f64x2_const_splat(__c) wasm_i64x2_const(__c, __c)
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_const_splat(double __c)
__REQUIRE_CONSTANT(__c) {
return (v128_t)(__f64x2){__c, __c};
}
static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_splat(int8_t __a) {
return (v128_t)(__i8x16){__a, __a, __a, __a, __a, __a, __a, __a,

View File

@ -420,7 +420,7 @@ v128_t test_i64x2_const_splat() {
// CHECK-LABEL: @test_f32x4_const_splat(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <4 x i32> <i32 42, i32 42, i32 42, i32 42>
// CHECK-NEXT: ret <4 x i32> <i32 1109917696, i32 1109917696, i32 1109917696, i32 1109917696>
//
v128_t test_f32x4_const_splat() {
return wasm_f32x4_const_splat(42);
@ -428,7 +428,7 @@ v128_t test_f32x4_const_splat() {
// CHECK-LABEL: @test_f64x2_const_splat(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <4 x i32> <i32 42, i32 0, i32 42, i32 0>
// CHECK-NEXT: ret <4 x i32> <i32 0, i32 1078263808, i32 0, i32 1078263808>
//
v128_t test_f64x2_const_splat() {
return wasm_f64x2_const_splat(42);