This is an archive of the discontinued LLVM Phabricator instance.

[LAA] Support runtime checks for select GEP base pointers.
ClosedPublic

Authored by fhahn on Nov 23 2021, 4:02 PM.

Details

Summary

Scaffolding support for generating runtime checks for multiple SCEV expressions
per pointer. The initial version just adds support for looking through
a single select.

The more sophisticated logic for analyzing forks is in D108699

Diff Detail

Event Timeline

fhahn created this revision.Nov 23 2021, 4:02 PM
fhahn requested review of this revision.Nov 23 2021, 4:02 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 23 2021, 4:02 PM
fhahn retitled this revision from [LAA] Support runtime checks for select GEP base pointers. to [LAA] Support runtime checks for select GEP base pointers. (WIP).Nov 23 2021, 4:14 PM
fhahn updated this revision to Diff 390350.Nov 29 2021, 7:25 AM

rebased on top of precommitted tests, simplified code

fhahn edited the summary of this revision. (Show Details)Nov 29 2021, 1:58 PM
fhahn added reviewers: Ayal, anemet, david-arm, huntergr.
bsmith added a subscriber: bsmith.Feb 28 2022, 3:01 AM
fhahn updated this revision to Diff 421813.Apr 10 2022, 2:57 PM

Rebase and stripped down logic for translating pointers to bare minimum.

Herald added a project: Restricted Project. · View Herald TranscriptApr 10 2022, 2:57 PM
fhahn retitled this revision from [LAA] Support runtime checks for select GEP base pointers. (WIP) to [LAA] Support runtime checks for select GEP base pointers..Apr 11 2022, 4:28 AM
fhahn edited the summary of this revision. (Show Details)
huntergr accepted this revision.May 4 2022, 1:42 AM

LGTM

This revision is now accepted and ready to land.May 4 2022, 1:42 AM
This revision was landed with ongoing or failed builds.May 12 2022, 11:34 AM
This revision was automatically updated to reflect the committed changes.

This patch is causing false reports with msan. I am trying to creduce the code. It's with TensorFlow, so far it's quite complicated.

I see that before the patch the pass produced

vector.memcheck:                                  ; preds = %vector.scevcheck
  %scevgep77 = getelementptr i32, i32* %retval.0.i.sroa.sel, i64 1, !dbg !1439
  %scevgep7778 = bitcast i32* %scevgep77 to i8*, !dbg !1439
  %bound0 = icmp ult i8* %scevgep73, %scevgep7778, !dbg !1439
  %bound1 = icmp ult i8* %retval.0.i.sroa.sel76, %scevgep7475, !dbg !1439
  %found.conflict = and i1 %bound0, %bound1, !dbg !1439
  br i1 %found.conflict, label %scalar.ph, label %vector.ph

After the patch it's more complicated:

vector.memcheck:                                  ; preds = %vector.scevcheck
  %scevgep79 = getelementptr %"union.absl::container_internal::map_slot_type", %"union.absl::container_internal::map_slot_type"* %33, i64 0, i32 0, i32 1, i32 1, i32 0, i32 2, !dbg !1439
  %scevgep7980 = bitcast i32* %scevgep79 to i8*, !dbg !1439
  %scevgep81 = getelementptr %"union.absl::container_internal::map_slot_type", %"union.absl::container_internal::map_slot_type"* %33, i64 0, i32 0, i32 1, i32 2, i64 0, !dbg !1439
  %bound0 = icmp ult i8* %scevgep73, %scevgep78, !dbg !1439
  %bound1 = icmp ult i8* %scevgep7677, %scevgep7475, !dbg !1439
  %found.conflict = and i1 %bound0, %bound1, !dbg !1439
  %bound082 = icmp ult i8* %scevgep73, %scevgep81, !dbg !1439
  %bound183 = icmp ult i8* %scevgep7980, %scevgep7475, !dbg !1439
  %found.conflict84 = and i1 %bound082, %bound183, !dbg !1439
  %conflict.rdx = or i1 %found.conflict, %found.conflict84, !dbg !1439
  br i1 %conflict.rdx, label %scalar.ph, label %vector.ph

Then then when Msan instruments the code, it detects branch on uninitialized %conflict.rdx

I will continue to minimize the reproducer.
Should we revert the patch, because it breaks Msan and maybe there is a chance the bounds are calculated incorrectly?

fhahn added a comment.May 31 2022, 8:57 AM

I will continue to minimize the reproducer.
Should we revert the patch, because it breaks Msan and maybe there is a chance the bounds are calculated incorrectly?

Thanks for the report, I'll take a look. I already have suspicion of what's going wrong. Hopefully I'll be able to write up a test case & fix today. If not, we can revert tomorrow.

I will continue to minimize the reproducer.
Should we revert the patch, because it breaks Msan and maybe there is a chance the bounds are calculated incorrectly?

Thanks for the report, I'll take a look. I already have suspicion of what's going wrong.

My current reproducer is

#include "third_party/absl/container/flat_hash_map.h"
#include "third_party/tensorflow/core/framework/tensor.h"

int main() {
  absl::flat_hash_map<std::string, int> ids_map;
  std::vector<std::string> ids = {"1405217"};
  int d = 0;
  tensorflow::Tensor tensor(tensorflow::DataTypeToEnum<float>::v(),
                            {1, 20, 50, 1});
  tensor.flat<float>().setConstant(0);

  auto tm = tensor.tensor<float, 4>();
  int i = 0;
  for (const auto& other_agent_id : ids) {
    auto it = ids_map.find(other_agent_id);
    const int& f = it != ids_map.end() ? it->second : d;
    for (int j = 0; j < 50; ++j) {
      tm(0, i, j, 0) = f;
    }
    ++i;
  }
}

Not sure if it's helpful, as it requires TF with dependencies build with msan:
-O2 -fsanitize=memory -fsanitize-memory-param-retval -fsanitize-memory-use-after-dtor

Hopefully I'll be able to write up a test case & fix today. If not, we can revert tomorrow.

Thanks, revert will help, as out internal release is blocked on this patch.

alexfh added a subscriber: alexfh.Jun 1 2022, 6:25 AM

I've reverted the commit in 7aa8a678826dea86ff3e6c7df9d2a8a6ef868f5d to unblock our internal release.

@fhahn
This is reduced reproducer:

struct c {
  int b;
};
struct e {
  int &operator*() { return ae->b; }
  bool operator!=(e) __attribute__((noinline)) { return 0; }
  c *ae;
};
int a;
float g;
int main() {
  e b, d;
  int &f = d != b ? *d : a;
  for (int h = 0; h < 50; ++h)
    g = f;
}

clang++ -cc1 -triple x86_64-grtev4-linux-gnu -emit-obj -mframe-pointer=non-leaf -relaxed-aliasing -mconstructor-aliases -O2 -fsanitize=memory -Werror -Wreturn-type -fsanitize-memory-use-after-dtor -fsanitize-memory-param-retval -vectorize-loops -o t.o -x c++ t.cc
clang++ t.o -fsanitize=memory -fuse-ld=lld -o t -g0 -s -Wl,--strip-all

./t

==350572==WARNING: MemorySanitizer: use-of-uninitialized-value
SUMMARY: MemorySanitizer: use-of-uninitialized-value

@fhahn
This is reduced reproducer:

Thanks! I think I was able to isolate the bits that caused problems:

  1. Unecessarily looking through selects outside the loop
  2. Introducing branches on undef/poison when looking through selects.

I recommitted the change in e9cced27390ba38eac1144aa1240281a1edadec0. I couldn't test with msan though, as it's not available on macOS. Please let me know if you see further issues.

@fhahn
This is reduced reproducer:

Thanks! I think I was able to isolate the bits that caused problems:

  1. Unecessarily looking through selects outside the loop
  2. Introducing branches on undef/poison when looking through selects.

I recommitted the change in e9cced27390ba38eac1144aa1240281a1edadec0. I couldn't test with msan though, as it's not available on macOS. Please let me know if you see further issues.

Thanks! Out test works with e9cced27390ba38eac1144aa1240281a1edadec0