fhahn created this revision. fhahn added reviewers: rjmccall, jfb, scanon, rsmith, hfinkel. Herald added a subscriber: dexonsmith. Herald added a project: clang. fhahn requested review of this revision.
Currently the 'swizzle' accessors .even/.odd/.lo/.hi return a scalar instead of a vector with a single element when the result has a single element. The current behavior of Clang can lead to unexpected failures when working with ext_vector_types in templates that paramterize the number of elements. In the example below, currently `c.even` returns a scalar, which is then converted to `char` and broadcasted to both elements of `b`. typedef uint16_t __attribute__ ((__ext_vector_type__(2))) ushort2; typedef uint8_t __attribute__ ((__ext_vector_type__(2))) uchar2; ushort2 c = 0x0102; uchar2 b = (uchar2) c.even; This patch changes the behavior so that swizzels return single element vectors in that case. This should make the behavior consistent with vectors with more than 1 element. Just from looking at the implementation, it seems like the current behavior is mostly a side-effect of the implementation, where the handling of element accesses and swizzels is combined. This patch changes existing behavior and may break some code that relies on the current behavior. Unfortunately I could not find any specification for the ext_vector_type so it is hard to tell if the existing behavior is actually intentional or not. At least there are no unit tests for the current behavior. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D89699 Files: clang/lib/Sema/SemaExprMember.cpp clang/test/CodeGen/ext-vector.c clang/test/Sema/ext_vector_components.c Index: clang/test/Sema/ext_vector_components.c =================================================================== --- clang/test/Sema/ext_vector_components.c +++ clang/test/Sema/ext_vector_components.c @@ -72,3 +72,12 @@ float2 hi(float3 x) { return x.hi; } float2 ev(float3 x) { return x.even; } float2 od(float3 x) { return x.odd; } + +float lo2(float2 x) { return x.lo; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float hi2(float2 x) { return x.hi; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float ev2(float2 x) { return x.even; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float od2(float2 x) { return x.odd; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} Index: clang/test/CodeGen/ext-vector.c =================================================================== --- clang/test/CodeGen/ext-vector.c +++ clang/test/CodeGen/ext-vector.c @@ -2,6 +2,7 @@ typedef __attribute__(( ext_vector_type(4) )) float float4; typedef __attribute__(( ext_vector_type(2) )) float float2; +typedef __attribute__((ext_vector_type(1))) float float1; typedef __attribute__(( ext_vector_type(4) )) int int4; typedef __attribute__(( ext_vector_type(4) )) unsigned int uint4; @@ -17,6 +18,7 @@ return V.wzyx+V; } +float1 vec1; float2 vec2, vec2_2; float4 vec4, vec4_2; float f; @@ -338,3 +340,44 @@ // CHECK: shufflevector {{.*}} <i32 10, i32 11, i32 12, i32 13> vec4_2 = vec16.sabcd; } + +void test_swizzle() { + // CHECK: [[L0_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[ODD:%.+]] = shufflevector <4 x float> [[L0_VEC4]], <4 x float> undef, <2 x i32> <i32 1, i32 3> + // CHECK-NEXT: [[L1_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[EVEN:%.+]] = shufflevector <4 x float> [[L1_VEC4]], <4 x float> undef, <2 x i32> <i32 0, i32 2> + // CHECK-NEXT: [[FADD:%.+]] = fadd <2 x float> [[ODD]], [[EVEN]] + // CHECK-NEXT: store <2 x float> [[FADD]], <2 x float>* @vec2, align 8 + vec2 = vec4.odd + vec4.even; + + // CHECK-NEXT: [[L2_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[LO:%.+]] = shufflevector <4 x float> [[L2_VEC4]], <4 x float> undef, <2 x i32> <i32 0, i32 1> + // CHECK-NEXT: [[L3_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[HI:%.+]] = shufflevector <4 x float> [[L3_VEC4]], <4 x float> undef, <2 x i32> <i32 2, i32 3> + // CHECK-NEXT: [[FSUB:%.+]] = fsub <2 x float> [[LO]], [[HI]] + // CHECK-NEXT: store <2 x float> [[FSUB]], <2 x float>* @vec2, align 8 + vec2 = vec4.lo - vec4.hi; + + // CHECK-NEXT: [[L4_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[ODD2:%.+]] = shufflevector <4 x float> [[L4_VEC4]], <4 x float> undef, <2 x i32> <i32 1, i32 3> + // CHECK-NEXT: [[L5_VEC4_2:%.+]] = load <4 x float>, <4 x float>* @vec4_2, align 16 + // CHECK-NEXT: [[ODD3:%.+]] = shufflevector <2 x float> [[ODD2]], <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef> + // CHECK-NEXT: [[RES:%.+]] = shufflevector <4 x float> [[L5_VEC4_2]], <4 x float> [[ODD3]], <4 x i32> <i32 0, i32 1, i32 4, i32 5> + // CHECK-NEXT: store <4 x float> [[RES]], <4 x float>* @vec4_2, align 16 + + vec4_2.hi = vec4.odd; + + // CHECK-NEXT: [[L0_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[HI_2:%.+]] = shufflevector <2 x float> [[L0_VEC2]], <2 x float> undef, <1 x i32> <i32 1> + // CHECK-NEXT: [[L1_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[LO_2:%.+]] = shufflevector <2 x float> [[L1_VEC2]], <2 x float> undef, <1 x i32> zeroinitializer + // CHECK-NEXT: [[FADD1:%.+]] = fadd <1 x float> [[HI_2]], [[LO_2]] + // CHECK-NEXT: [[L2_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[ODD_2:%.+]] = shufflevector <2 x float> [[L2_VEC2]], <2 x float> undef, <1 x i32> <i32 1> + // CHECK-NEXT: [[FADD2:%.+]] = fadd <1 x float> [[FADD1]], [[ODD]] + // CHECK-NEXT: [[L3_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[EVEN_2:%.+]] = shufflevector <2 x float> [[L3_VEC2]], <2 x float> undef, <1 x i32> zeroinitializer + // CHECK-NEXT: [[FADD3:%.+]] = fadd <1 x float> [[FADD2]], [[EVEN_2]] + // CHECK-NEXT: store <1 x float> [[FADD3]], <1 x float>* @vec1, align 4 + vec1 = vec2.hi + vec2.lo + vec2.odd + vec2.even; +} Index: clang/lib/Sema/SemaExprMember.cpp =================================================================== --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -406,7 +406,7 @@ if (HexSwizzle) CompSize--; - if (CompSize == 1) + if (CompSize == 1 && !HalvingSwizzle) return vecType->getElementType(); if (HasRepeated) VK = VK_RValue;
Index: clang/test/Sema/ext_vector_components.c =================================================================== --- clang/test/Sema/ext_vector_components.c +++ clang/test/Sema/ext_vector_components.c @@ -72,3 +72,12 @@ float2 hi(float3 x) { return x.hi; } float2 ev(float3 x) { return x.even; } float2 od(float3 x) { return x.odd; } + +float lo2(float2 x) { return x.lo; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float hi2(float2 x) { return x.hi; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float ev2(float2 x) { return x.even; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} +float od2(float2 x) { return x.odd; } +// expected-error@-1 {{returning 'float __attribute__((ext_vector_type(1)))' (vector of 1 'float' value) from a function with incompatible result type 'float'}} Index: clang/test/CodeGen/ext-vector.c =================================================================== --- clang/test/CodeGen/ext-vector.c +++ clang/test/CodeGen/ext-vector.c @@ -2,6 +2,7 @@ typedef __attribute__(( ext_vector_type(4) )) float float4; typedef __attribute__(( ext_vector_type(2) )) float float2; +typedef __attribute__((ext_vector_type(1))) float float1; typedef __attribute__(( ext_vector_type(4) )) int int4; typedef __attribute__(( ext_vector_type(4) )) unsigned int uint4; @@ -17,6 +18,7 @@ return V.wzyx+V; } +float1 vec1; float2 vec2, vec2_2; float4 vec4, vec4_2; float f; @@ -338,3 +340,44 @@ // CHECK: shufflevector {{.*}} <i32 10, i32 11, i32 12, i32 13> vec4_2 = vec16.sabcd; } + +void test_swizzle() { + // CHECK: [[L0_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[ODD:%.+]] = shufflevector <4 x float> [[L0_VEC4]], <4 x float> undef, <2 x i32> <i32 1, i32 3> + // CHECK-NEXT: [[L1_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[EVEN:%.+]] = shufflevector <4 x float> [[L1_VEC4]], <4 x float> undef, <2 x i32> <i32 0, i32 2> + // CHECK-NEXT: [[FADD:%.+]] = fadd <2 x float> [[ODD]], [[EVEN]] + // CHECK-NEXT: store <2 x float> [[FADD]], <2 x float>* @vec2, align 8 + vec2 = vec4.odd + vec4.even; + + // CHECK-NEXT: [[L2_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[LO:%.+]] = shufflevector <4 x float> [[L2_VEC4]], <4 x float> undef, <2 x i32> <i32 0, i32 1> + // CHECK-NEXT: [[L3_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[HI:%.+]] = shufflevector <4 x float> [[L3_VEC4]], <4 x float> undef, <2 x i32> <i32 2, i32 3> + // CHECK-NEXT: [[FSUB:%.+]] = fsub <2 x float> [[LO]], [[HI]] + // CHECK-NEXT: store <2 x float> [[FSUB]], <2 x float>* @vec2, align 8 + vec2 = vec4.lo - vec4.hi; + + // CHECK-NEXT: [[L4_VEC4:%.+]] = load <4 x float>, <4 x float>* @vec4, align 16 + // CHECK-NEXT: [[ODD2:%.+]] = shufflevector <4 x float> [[L4_VEC4]], <4 x float> undef, <2 x i32> <i32 1, i32 3> + // CHECK-NEXT: [[L5_VEC4_2:%.+]] = load <4 x float>, <4 x float>* @vec4_2, align 16 + // CHECK-NEXT: [[ODD3:%.+]] = shufflevector <2 x float> [[ODD2]], <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef> + // CHECK-NEXT: [[RES:%.+]] = shufflevector <4 x float> [[L5_VEC4_2]], <4 x float> [[ODD3]], <4 x i32> <i32 0, i32 1, i32 4, i32 5> + // CHECK-NEXT: store <4 x float> [[RES]], <4 x float>* @vec4_2, align 16 + + vec4_2.hi = vec4.odd; + + // CHECK-NEXT: [[L0_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[HI_2:%.+]] = shufflevector <2 x float> [[L0_VEC2]], <2 x float> undef, <1 x i32> <i32 1> + // CHECK-NEXT: [[L1_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[LO_2:%.+]] = shufflevector <2 x float> [[L1_VEC2]], <2 x float> undef, <1 x i32> zeroinitializer + // CHECK-NEXT: [[FADD1:%.+]] = fadd <1 x float> [[HI_2]], [[LO_2]] + // CHECK-NEXT: [[L2_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[ODD_2:%.+]] = shufflevector <2 x float> [[L2_VEC2]], <2 x float> undef, <1 x i32> <i32 1> + // CHECK-NEXT: [[FADD2:%.+]] = fadd <1 x float> [[FADD1]], [[ODD]] + // CHECK-NEXT: [[L3_VEC2:%.+]] = load <2 x float>, <2 x float>* @vec2, align 8 + // CHECK-NEXT: [[EVEN_2:%.+]] = shufflevector <2 x float> [[L3_VEC2]], <2 x float> undef, <1 x i32> zeroinitializer + // CHECK-NEXT: [[FADD3:%.+]] = fadd <1 x float> [[FADD2]], [[EVEN_2]] + // CHECK-NEXT: store <1 x float> [[FADD3]], <1 x float>* @vec1, align 4 + vec1 = vec2.hi + vec2.lo + vec2.odd + vec2.even; +} Index: clang/lib/Sema/SemaExprMember.cpp =================================================================== --- clang/lib/Sema/SemaExprMember.cpp +++ clang/lib/Sema/SemaExprMember.cpp @@ -406,7 +406,7 @@ if (HexSwizzle) CompSize--; - if (CompSize == 1) + if (CompSize == 1 && !HalvingSwizzle) return vecType->getElementType(); if (HasRepeated) VK = VK_RValue;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits