Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attribute of typedef dropped, leads to failure of extraction. #68

Closed
5c4lar opened this issue Jul 8, 2024 · 12 comments · Fixed by #69 or #76
Closed

Attribute of typedef dropped, leads to failure of extraction. #68

5c4lar opened this issue Jul 8, 2024 · 12 comments · Fixed by #69 or #76
Labels
bug Something isn't working

Comments

@5c4lar
Copy link

5c4lar commented Jul 8, 2024

Minimal example to check this:

typedef unsigned short int sa_family_t;
typedef unsigned int __socklen_t;
typedef __socklen_t socklen_t;
typedef int ares_socket_t;
typedef socklen_t ares_socklen_t;

struct sockaddr {
  sa_family_t sa_family;
  char sa_data[14];
};

typedef union {
  struct sockaddr *__restrict __sockaddr__;
} __SOCKADDR_ARG __attribute__((__transparent_union__));

extern int getsockname(int __fd, __SOCKADDR_ARG __addr,
                       socklen_t *__restrict __len)
    __attribute__((__nothrow__));

int main() {
  struct sockaddr *src_addr;
  ares_socket_t sock;
  ares_socklen_t len;
  getsockname(sock, src_addr, &len);
}

extract with the following command

clang-extract exp.c  -DCE_EXTRACT_FUNCTIONS=main -DCE_DUMP_PASSES                                        05:51:01
exp.c:34:21: error: passing 'struct sockaddr *' to parameter of incompatible type '__SOCKADDR_ARG'
   34 |   getsockname(sock, src_addr, &len);
      |                     ^~~~~~~~
exp.c:25:49: note: passing argument to parameter '__addr' here
   25 | extern int getsockname(int __fd, __SOCKADDR_ARG __addr,
      |                                                 ^

Error on pass: ClosurePass

The original source should have been compiled with clang, examine the dumpped pass, the __attribute__((__transparent_union__)) is dropped:

/** clang-extract: from exp.c:1:1  */
typedef unsigned short int sa_family_t;

/** clang-extract: from exp.c:2:1  */
typedef unsigned int __socklen_t;

/** clang-extract: from exp.c:3:1  */
typedef __socklen_t socklen_t;

/** clang-extract: from exp.c:4:1  */
typedef int ares_socket_t;

/** clang-extract: from exp.c:5:1  */
typedef socklen_t ares_socklen_t;

/** clang-extract: from exp.c:10:1  */
struct sockaddr;

/** clang-extract: from exp.c:12:1  */
typedef union {
  struct sockaddr *__restrict __sockaddr__;
} __SOCKADDR_ARG;

/** clang-extract: from exp.c:16:1  */
extern int getsockname(int __fd, __SOCKADDR_ARG __addr,
                       socklen_t *__restrict __len)
    __attribute__((__nothrow__));

/** clang-extract: from exp.c:20:1  */
int main() {
  struct sockaddr *src_addr;
  ares_socket_t sock;
  ares_socklen_t len;
  getsockname(sock, src_addr, &len);
}
@giulianobelinassi giulianobelinassi added the bug Something isn't working label Jul 8, 2024
@giulianobelinassi
Copy link
Collaborator

Confirmed. We may need to patch PrettyPrint::Get_Expanded_Loc to also look for the attributes applied to the structs or unions that the typedef bounds to.

@giulianobelinassi
Copy link
Collaborator

@5c4lar can you check if PR #69 fixes your problem?

@5c4lar
Copy link
Author

5c4lar commented Jul 9, 2024

@5c4lar can you check if PR #69 fixes your problem?

Yes, it fixes the problem! Thanks for your timely response!

@5c4lar
Copy link
Author

5c4lar commented Jul 16, 2024

@giulianobelinassi Hi! I found a new case that will make the extraction fail, can you have a look at it?

typedef long long __m64 __attribute__((__vector_size__(8), __aligned__(8)));

typedef int __v2si __attribute__((__vector_size__(8)));

static __inline__ __m64
    __attribute__((__always_inline__, __nodebug__, __target__("mmx,no-evex512"),
                   __min_vector_width__(64)))
    _mm_cmpgt_pi32(__m64 __m1, __m64 __m2) {
  return (__m64)__builtin_ia32_pcmpgtd((__v2si)__m1, (__v2si)__m2);
}
clang-extract -Wno-everything test.c -DCE_EXTRACT_FUNCTIONS=_mm_cmpgt_pi32 -DCE_OUTPUT_FILE=-
test.c:12:40: error: invalid conversion between vector type '__m64' (vector of 1 'long long' value) and integer type '__v2si' (aka 'int') of different size
   12 |   return (__m64)__builtin_ia32_pcmpgtd((__v2si)__m1, (__v2si)__m2);
      |                                        ^~~~~~~~~~~~
test.c:12:54: error: invalid conversion between vector type '__m64' (vector of 1 'long long' value) and integer type '__v2si' (aka 'int') of different size
   12 |   return (__m64)__builtin_ia32_pcmpgtd((__v2si)__m1, (__v2si)__m2);
      |                                                      ^~~~~~~~~~~~

Error on pass: ClosurePass

It seems that this is also because of the dropped attribute of typedef. But why is that of _m64 kept, but that of __v2si dropped?

cat test.dump.3.ClosurePass.c
/** clang-extract: from test.c:224:1  */
typedef long long __m64 __attribute__((__vector_size__(8), __aligned__(8)));

/** clang-extract: from test.c:226:1  */
typedef int __v2si;

/** clang-extract: from test.c:564:1  */
static __inline__ __m64
    __attribute__((__always_inline__, __nodebug__, __target__("mmx,no-evex512"),
                   __min_vector_width__(64)))
    _mm_cmpgt_pi32(__m64 __m1, __m64 __m2) {
  return (__m64)__builtin_ia32_pcmpgtd((__v2si)__m1, (__v2si)__m2);
}

@giulianobelinassi
Copy link
Collaborator

Reopening this. I will take a look at it tomorrow.

@giulianobelinassi
Copy link
Collaborator

It looks like some attributes are not stored in the Decl itself but rather the QualType of the Decl. From clang's DeclPrinter.cpp:

void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
  if (!Policy.SuppressSpecifiers) {
    Out << "typedef ";

    if (D->isModulePrivate())
      Out << "__module_private__ ";
  }
  QualType Ty = D->getTypeSourceInfo()->getType();
  Ty.print(Out, Policy, D->getName(), Indentation);
  prettyPrintAttributes(D);
}

Hence we also need to analyze the QualTypes for the attributes.

@giulianobelinassi
Copy link
Collaborator

@5c4lar Please check if #76 fixes this issue.

@5c4lar
Copy link
Author

5c4lar commented Jul 18, 2024

@giulianobelinassi The previous testcase is fixed. But when I test it on other functions in the same project, there seems to be lots of other cases.

typedef short __v8hi __attribute__((__vector_size__(16)));

typedef long long __m128i __attribute__((__vector_size__(16), __aligned__(16)));

typedef signed char __v16qs __attribute__((__vector_size__(16)));

static __inline__ __m128i __attribute__((__always_inline__, __nodebug__, __target__("sse4.1,no-evex512"), __min_vector_width__(128))) _mm_cvtepi8_epi16(__m128i __V) {
  return (__m128i) __builtin_convertvector(
      __builtin_shufflevector((__v16qs)__V, (__v16qs)__V, 0, 1, 2, 3, 4, 5, 6,
                              7),
      __v8hi);
}
/** clang-extract: from test.c:3:1 */
typedef long long __m128i __attribute__((__vector_size__(16), __aligned__(16)));

/** clang-extract: from test.c:5:1 */
typedef signed char __v16qs __attribute__((__vector_size__(16)));

/** clang-extract: from test.c:7:1 */
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__, __target__("sse4.1,no-evex512"), __min_vector_width__(128))) _mm_cvtepi8_epi16(__m128i __V) {
  return (__m128i) __builtin_convertvector(
      __builtin_shufflevector((__v16qs)__V, (__v16qs)__V, 0, 1, 2, 3, 4, 5, 6,
                              7),
      __v8hi);
}

For example, the typedef of __v8hi is dropped completely here.

@5c4lar
Copy link
Author

5c4lar commented Jul 18, 2024

And here is another case:

typedef float __v8sf __attribute__ ((__vector_size__ (32)));

typedef unsigned int __v8su __attribute__ ((__vector_size__ (32)));

typedef float __m256 __attribute__ ((__vector_size__ (32), __aligned__(32)));

typedef long long __m256i __attribute__((__vector_size__(32), __aligned__(32)));

static __inline__ __m256 __attribute__((__always_inline__, __nodebug__, __target__("avx512vl,no-evex512"), __min_vector_width__(256)))
_mm256_cvtepu32_ps (__m256i __A) {
  return (__m256)__builtin_convertvector((__v8su)__A, __v8sf);
}

where the definition of __v8sf will be dropped

@giulianobelinassi
Copy link
Collaborator

So it turns out that __builtin_convertvector is not a function but rather a specific kind of Expr in clang AST:

FunctionDecl 0x557b7ebd4e90 <line:7:1, line:12:1> line:7:135 _mm_cvtepi8_epi16 '__m128i (__m128i)' static inline
| |-ParmVarDecl 0x557b7ebd4d80 <col:153, col:161> col:161 used __V '__m128i':'__attribute__((__vector_size__(2 * sizeof(long long)))) long long'
| |-CompoundStmt 0x557b7ebd56b0 <col:166, line:12:1>                           
| | `-ReturnStmt 0x557b7ebd56a0 <line:8:3, line:11:13>                                                                                                                                        | |   `-CStyleCastExpr 0x557b7ebd5678 <line:8:10, line:11:13> '__m128i':'__attribute__((__vector_size__(2 * sizeof(long long)))) long long' <BitCast>                                         
| |     `-ConvertVectorExpr 0x557b7ebd5640 <line:8:20, line:11:13> '__v8hi':'__attribute__((__vector_size__(8 * sizeof(short)))) short'
| |       `-ShuffleVectorExpr 0x557b7ebd5550 <line:9:7, line:10:32> '__attribute__((__vector_size__(8 * sizeof(signed char)))) signed char'
| |         |-CStyleCastExpr 0x557b7ebd52c8 <line:9:31, col:40> '__v16qs':'__attribute__((__vector_size__(16 * sizeof(signed char)))) signed char' <BitCast>
| |         | `-ImplicitCastExpr 0x557b7ebd52b0 <col:40> '__m128i':'__attribute__((__vector_size__(2 * sizeof(long long)))) long long' <LValueToRValue> part_of_explicit_cast
| |         |   `-DeclRefExpr 0x557b7ebd5280 <col:40> '__m128i':'__attribute__((__vector_size__(2 * sizeof(long long)))) long long' lvalue ParmVar 0x557b7ebd4d80 '__V' '__m128i':'__attribute
__((__vector_size__(2 * sizeof(long long)))) long long' 

And this escapes the Closure computation because of that. I will submit a patch to it soon.

@giulianobelinassi
Copy link
Collaborator

@5c4lar I updated #76 with a fix for this. Please check if it works :)

@5c4lar
Copy link
Author

5c4lar commented Jul 19, 2024

@giulianobelinassi Thanks! The solution works well for the scenarios we've discussed previously. However, I've encountered a new situation where clang successfully compiles the code, but clang-extract encounters an error. This issue seems to be unrelated to our previous discussions, so I'll create a separate issue to address it specifically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants