Skip to content

Inlining drops a parameter's aligned(1) pointee type: _mm_loadu_si128 becomes an aligned load #439

Open

Description

@mborland

Issue Summary

The conversion from const v2di * to const v2di_u * produces no cast node, because EDG treats the two types as the same type. For an unmodified parameter with a constant-valued argument, the inliner remaps the parameter to the argument expression itself (vrk_constant_expr, inline.c:476). Inside the
inlined body, *p then dereferences the caller's const v2di *, and gcc assumes the 16-byte alignment of v2di.

The typedef itself is emitted correctly:

typedef long long __m128i_u __attribute((vector_size(16))) attribute((aligned(1))) attribute((may_alias));

Just above, at inline.c:453-470, there is already a special case for gcc and clang targets: it uses a temporary when a function-pointer cast's type isn't identical. This case needs a similar check. When the parameter's type and the argument's type differ in a way that matters to gcc (pointee alignment or
may_alias coming from a typedef), cast the argument to the parameter type or use a temporary of the parameter type.

Reproducing Source Code

  typedef long long v2di __attribute__((__vector_size__(16)));                                                                                                                                                                                                                                                     
  typedef long long v2di_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1)));                                                                                                                                                                                                                    
  static inline __attribute__((__always_inline__)) v2di load(const v2di_u *p) { return *p; }                                                                                                                                                                                                                       
  v2di inl(const v2di *p)  { return load((const v2di_u *)p); }   // OK                                                                                                                                                                                                                                             
  v2di inl2(const v2di *p) { return load(p); }                   // wrong 

Command-line Options

cpfe --c++17 --gnu_version=150301

Type of Issue

[Front End] This code SHOULD compile with these options.

Additional Details

  v2di _Z3inlPKDv2_x( const v2di *p) { return *((const v2di_u *)p); }   /* OK */                                                                                                                                                                                                                                   
  v2di _Z4inl2PKDv2_x( const v2di *p) { return *p; }                    /* aligned(1) lost */                                                                                                                                                                                                                      

With --no_inlining, load keeps its const v2di_u * parameter and the code is correct.

inl2 is exactly how the intrinsic is used. GCC's <emmintrin.h> defines _mm_loadu_si128(__m128i_u const *__P) { return *__P; }, and callers pass a __m128i const *. The same applies to the other loadu and storeu intrinsics, from SSE through AVX-512.

Reproducing (Standard) Configuration(s)

No response

Reproducing (Non-standard) Configuration

No response

I acknowledge that:

  • I have checked open issues and existing discussions before filing this report.
  • The reproducing source code that I have provided does not depend on headers that I have not included with my submission.
  • I have reduced the reproducing source code to the best of my ability.
  • I have selected at least one standard configuration or uploaded a non-standard configuration dump.
  • I understand code shared via this form is NOT confidential.
  • I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests.
  • I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under project license unless I included a LICENSE.txt file in my .zip or .tar.gz upload. If I included a LICENSE.txt file, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions