llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.84k stars 11.47k forks source link

MSAN reports false positives on interleaved storage on ARM AArch64 #72848

Open vrabaud opened 9 months ago

vrabaud commented 9 months ago

On clang 18, the following test simply reports: "WARNING: MemorySanitizer: use-of-uninitialized-value". It seems to be the case for different kinds of input. Even displaying the first element of the outputs fails.

#include <iostream>
#include <arm_neon.h>
TEST(Msan,interlace) {
  int16x8x2_t vec2;
  vec2.val[0] = vdupq_n_s16(1);
  vec2.val[1] = vdupq_n_s16(2);
  int16_t dst2[8*2];
  vst2q_s16(dst2, vec2);
  for(int16_t i: dst2) std::cout << (int)i << ",";
  std::cout << std::endl;

  uint8x16x3_t vec3;
  vec3.val[0] = vdupq_n_u8(3);
  vec3.val[1] = vdupq_n_u8(4);
  vec3.val[2] = vdupq_n_u8(5);
  uint8_t dst3[16*3];  
  vst3q_u8(dst3, vec3);
  for(uint8_t i: dst3) std::cout << (int)i << ",";
  std::cout << std::endl;
}
llvmbot commented 9 months ago

@llvm/issue-subscribers-backend-aarch64

Author: Vincent Rabaud (vrabaud)

On clang 18, the following test simply reports: "WARNING: MemorySanitizer: use-of-uninitialized-value". It seems to be the case for different kinds of input. Even displaying the first element of the outputs fails. ```c++ #include <iostream> #include <arm_neon.h> TEST(Msan,interlace) { int16x8x2_t vec2; vec2.val[0] = vdupq_n_s16(1); vec2.val[1] = vdupq_n_s16(2); int16_t dst2[8*2]; vst2q_s16(dst2, vec2); for(int16_t i: dst2) std::cout << (int)i << ","; std::cout << std::endl; uint8x16x3_t vec3; vec3.val[0] = vdupq_n_u8(3); vec3.val[1] = vdupq_n_u8(4); vec3.val[2] = vdupq_n_u8(5); uint8_t dst3[16*3]; vst3q_u8(dst3, vec3); for(uint8_t i: dst3) std::cout << (int)i << ","; std::cout << std::endl; } ```
brianosman commented 9 months ago

We're seeing similar failures with vst3_lane_u8: https://godbolt.org/z/nWq8EYzTf

Running that on an ARM device with MSAN triggers use-of-uninitialized-value

ramosian-glider commented 9 months ago

First off, this clearly has nothing to do with the vararg support patch, as there are no varargs.

I suspect that MSan is lacking the Neon intrinsics support. The following code:

  int16_t dst2[8*2];
  vst2q_s16(dst2, vec2);
  std::cout << (int)dst2[0] << ",";

gets compiled into the following IR:

...
  %dst3 = alloca [48 x i8], align 1
  call void @llvm.lifetime.start.p0(i64 32, ptr nonnull %dst2) #9
  %0 = ptrtoint ptr %dst2 to i64
  %1 = xor i64 %0, 193514046488576
  %2 = inttoptr i64 %1 to ptr
  call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(32) %2, i8 -1, i64 32, i1 false)
  call void @llvm.aarch64.neon.st2.v8i16.p0(<8 x i16> <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>, <8 x i16> <i16 2, i16 2, i16 2, i16 2, i16 2, i16 2, i16 2, i16 2>, ptr nonnull %dst2)
  %_msld = load i16, ptr %2, align 4
  %_mscmp175.not = icmp eq i16 %_msld, 0
  br i1 %_mscmp175.not, label %4, label %3

3:
  call void @__msan_warning_noreturn() #10
  unreachable
ramosian-glider commented 9 months ago

CC @eugenis

ramosian-glider commented 9 months ago

Godbolt link for posterity: https://godbolt.org/z/MMz3qvj69

thurstond commented 1 month ago

This particular test case works with mainline LLVM as of last week: "[msan] Implement support for Arm NEON vst{2,3,4} instructions" (https://github.com/llvm/llvm-project/pull/99360)

Currently, it only works for VST with integer operands (since it was a particularly common use case). There is followup work planned to implement support for VST with floating-point operands, non-interleaved vector store (VST1x{2,3,4}), and vector loads.