Skip to content

Commit 56dd30a

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:b6603e1bf11dee4761e49af6581c8b8f074b705d into amd-gfx:3ab64ddfc135
Local branch amd-gfx 3ab64dd Merged main:2847020dbd9b8f932ee564651ec72ce15fa37d07 into amd-gfx:95a2ef3ad1f2 Remote branch main b6603e1 [mlir] [dataflow] Refactoring the definition of program points in data flow analysis (llvm#105656)
2 parents 3ab64dd + b6603e1 commit 56dd30a

20 files changed

+408
-209
lines changed

compiler-rt/lib/nsan/nsan.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,21 +409,21 @@ __nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,
409409
}
410410
}
411411

412-
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
412+
alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
413413
thread_local uptr __nsan_shadow_ret_tag = 0;
414414

415-
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
415+
alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
416416
thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *
417417
sizeof(__float128)];
418418

419-
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
419+
alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
420420
thread_local uptr __nsan_shadow_args_tag = 0;
421421

422422
// Maximum number of args. This should be enough for anyone (tm). An alternate
423423
// scheme is to have the generated code create an alloca and make
424424
// __nsan_shadow_args_ptr point ot the alloca.
425425
constexpr const int kMaxNumArgs = 128;
426-
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
426+
alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
427427
thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *
428428
sizeof(__float128)];
429429

@@ -445,6 +445,32 @@ int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
445445
const InternalFT check_value = value;
446446
const InternalFT check_shadow = Shadow;
447447

448+
// We only check for NaNs in the value, not the shadow.
449+
if (flags().check_nan && isnan(check_value)) {
450+
GET_CALLER_PC_BP;
451+
BufferedStackTrace stack;
452+
stack.Unwind(pc, bp, nullptr, false);
453+
if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {
454+
// FIXME: optionally print.
455+
return flags().resume_after_suppression ? kResumeFromValue
456+
: kContinueWithShadow;
457+
}
458+
Decorator D;
459+
Printf("%s", D.Warning());
460+
Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
461+
Printf("%s", D.Default());
462+
stack.Print();
463+
if (flags().halt_on_error) {
464+
if (common_flags()->abort_on_error)
465+
Printf("ABORTING\n");
466+
else
467+
Printf("Exiting\n");
468+
Die();
469+
}
470+
// Performing other tests for NaN values is meaningless when dealing with numbers.
471+
return kResumeFromValue;
472+
}
473+
448474
// See this article for an interesting discussion of how to compare floats:
449475
// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
450476
static constexpr const FT Eps = FTInfo<FT>::kEpsilon;

compiler-rt/lib/nsan/nsan_flags.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,5 @@ NSAN_FLAG(bool, enable_loadtracking_stats, false,
4848
"due to invalid or unknown types.")
4949
NSAN_FLAG(bool, poison_in_free, true, "")
5050
NSAN_FLAG(bool, print_stats_on_exit, false, "If true, print stats on exit.")
51+
NSAN_FLAG(bool, check_nan, false,
52+
"If true, check the floating-point number is nan")

compiler-rt/test/nsan/nan.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clangxx_nsan -O0 -g %s -o %t
2+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -O3 -g %s -o %t
5+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
6+
7+
// RUN: %clangxx_nsan -O0 -g %s -o %t
8+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1 not %run %t
9+
10+
#include <cmath>
11+
#include <cstdio>
12+
13+
// This function returns a NaN value for triggering the NaN detection.
14+
__attribute__((noinline)) float ReturnNaN(float p, float q) {
15+
float ret = p / q;
16+
return ret;
17+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
18+
}
19+
20+
int main() {
21+
float val = ReturnNaN(0., 0.);
22+
printf("%f\n", val);
23+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
24+
return 0;
25+
}

compiler-rt/test/nsan/softmax.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=softmax %s -o %t
2+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
3+
4+
// RUN: %clangxx_nsan -O3 -g -DSOFTMAX=softmax %s -o %t
5+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0,log2_max_relative_error=19 %run %t 2>&1 | FileCheck %s
6+
7+
// RUN: %clangxx_nsan -O0 -g -DSOFTMAX=stable_softmax %s -o %t
8+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1,log2_max_relative_error=19 %run %t
9+
10+
// RUN: %clangxx_nsan -O3 -g -DSOFTMAX=stable_softmax %s -o %t
11+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=1,log2_max_relative_error=19 %run %t
12+
13+
#include<iostream>
14+
#include<vector>
15+
#include<algorithm>
16+
#include<cmath>
17+
18+
// unstable softmax
19+
template <typename T>
20+
__attribute__((noinline)) void softmax(std::vector<T> &values) {
21+
T sum_exp = 0.0;
22+
for (auto &i: values) {
23+
i = std::exp(i);
24+
sum_exp += i;
25+
}
26+
for (auto &i: values) {
27+
i /= sum_exp;
28+
}
29+
}
30+
31+
// use max value to avoid overflow
32+
// \sigma_i exp(x_i) / \sum_j exp(x_j) = \sigma_i exp(x_i - max(x)) / \sum_j exp(x_j - max(x))
33+
template <typename T>
34+
__attribute__((noinline)) void stable_softmax(std::vector<T> &values) {
35+
T sum_exp = 0.0;
36+
T max_values = *std::max_element(values.begin(), values.end());
37+
for (auto &i: values) {
38+
i = std::exp(i - max_values);
39+
sum_exp += i;
40+
}
41+
for (auto &i:values) {
42+
i /= sum_exp;
43+
}
44+
}
45+
46+
int main() {
47+
std::vector<double> data = {1000, 1001, 1002};
48+
SOFTMAX(data);
49+
for (auto i: data) {
50+
printf("%f", i);
51+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
52+
}
53+
return 0;
54+
}

compiler-rt/test/nsan/vec_sqrt.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clangxx_nsan -O0 -g -mavx %s -o %t
2+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
3+
// RUN: %clangxx_nsan -O3 -g -mavx %s -o %t
4+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
5+
6+
#include <cmath>
7+
#include <immintrin.h>
8+
#include <iostream>
9+
10+
void simd_sqrt(const float *input, float *output, size_t size) {
11+
size_t i = 0;
12+
for (; i + 7 < size; i += 8) {
13+
__m256 vec = _mm256_loadu_ps(&input[i]);
14+
__m256 result = _mm256_sqrt_ps(vec);
15+
_mm256_storeu_ps(&output[i], result);
16+
}
17+
for (; i < size; ++i) {
18+
output[i] = std::sqrt(input[i]);
19+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
20+
}
21+
}
22+
23+
int main() {
24+
float input[] = {1.0, 2.0, -3.0, 4.0, 5.0, 6.0, 7.0,
25+
8.0, 9.0, -10.0, 11.0, 12.0, 13.0, 14.0,
26+
15.0, -16.0, 17.0, -18.0, -19.0, -20.0};
27+
float output[20];
28+
simd_sqrt(input, output, 20);
29+
for (int i = 0; i < 20; ++i) {
30+
std::cout << output[i] << std::endl;
31+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
32+
}
33+
return 0;
34+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clangxx_nsan -O0 -g -mavx %s -o %t
2+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
3+
// RUN: %clangxx_nsan -O3 -g -mavx %s -o %t
4+
// RUN: NSAN_OPTIONS=check_nan=true,halt_on_error=0 %run %t 2>&1 | FileCheck %s
5+
#include <iostream>
6+
#include <cmath>
7+
8+
typedef float v8sf __attribute__ ((vector_size(32)));
9+
10+
v8sf simd_sqrt(v8sf a) {
11+
return __builtin_elementwise_sqrt(a);
12+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
13+
}
14+
15+
int main() {
16+
v8sf a = {-1.0, -2.0, -3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
17+
a = simd_sqrt(a);
18+
19+
// This prevents DCE.
20+
for (size_t i = 0; i < 8; ++i) {
21+
std::cout << a[i] << std::endl;
22+
// CHECK: WARNING: NumericalStabilitySanitizer: NaN detected
23+
}
24+
return 0;
25+
}

llvm/include/llvm/Config/llvm-config.h.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* Indicate that this is LLVM compiled from the amd-gfx branch. */
1818
#define LLVM_HAVE_BRANCH_AMD_GFX
19-
#define LLVM_MAIN_REVISION 509555
19+
#define LLVM_MAIN_REVISION 509557
2020

2121
/* Define if LLVM_ENABLE_DUMP is enabled */
2222
#cmakedefine LLVM_ENABLE_DUMP

mlir/include/mlir/Analysis/DataFlow/DeadCodeAnalysis.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ namespace dataflow {
3535
//===----------------------------------------------------------------------===//
3636

3737
/// This is a simple analysis state that represents whether the associated
38-
/// program point (either a block or a control-flow edge) is live.
38+
/// lattice anchor (either a block or a control-flow edge) is live.
3939
class Executable : public AnalysisState {
4040
public:
4141
using AnalysisState::AnalysisState;
4242

43-
/// Set the state of the program point to live.
43+
/// Set the state of the lattice anchor to live.
4444
ChangeResult setToLive();
4545

46-
/// Get whether the program point is live.
46+
/// Get whether the lattice anchor is live.
4747
bool isLive() const { return live; }
4848

4949
/// Print the liveness.
5050
void print(raw_ostream &os) const override;
5151

52-
/// When the state of the program point is changed to live, re-invoke
52+
/// When the state of the lattice anchor is changed to live, re-invoke
5353
/// subscribed analyses on the operations in the block and on the block
5454
/// itself.
5555
void onUpdate(DataFlowSolver *solver) const override;
@@ -60,8 +60,8 @@ class Executable : public AnalysisState {
6060
}
6161

6262
private:
63-
/// Whether the program point is live. Optimistically assume that the program
64-
/// point is dead.
63+
/// Whether the lattice anchor is live. Optimistically assume that the lattice
64+
/// anchor is dead.
6565
bool live = false;
6666

6767
/// A set of analyses that should be updated when this state changes.
@@ -140,10 +140,10 @@ class PredecessorState : public AnalysisState {
140140
// CFGEdge
141141
//===----------------------------------------------------------------------===//
142142

143-
/// This program point represents a control-flow edge between a block and one
143+
/// This lattice anchor represents a control-flow edge between a block and one
144144
/// of its successors.
145145
class CFGEdge
146-
: public GenericProgramPointBase<CFGEdge, std::pair<Block *, Block *>> {
146+
: public GenericLatticeAnchorBase<CFGEdge, std::pair<Block *, Block *>> {
147147
public:
148148
using Base::Base;
149149

mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,16 @@ class AbstractDenseForwardDataFlowAnalysis : public DataFlowAnalysis {
9191
const AbstractDenseLattice &before,
9292
AbstractDenseLattice *after) = 0;
9393

94-
/// Get the dense lattice after the execution of the given program point.
95-
virtual AbstractDenseLattice *getLattice(ProgramPoint point) = 0;
94+
/// Get the dense lattice after the execution of the given lattice anchor.
95+
virtual AbstractDenseLattice *getLattice(LatticeAnchor anchor) = 0;
9696

9797
/// Get the dense lattice after the execution of the given program point and
98-
/// add it as a dependency to a program point. That is, every time the lattice
99-
/// after point is updated, the dependent program point must be visited, and
100-
/// the newly triggered visit might update the lattice after dependent.
98+
/// add it as a dependency to a lattice anchor. That is, every time the
99+
/// lattice after anchor is updated, the dependent program point must be
100+
/// visited, and the newly triggered visit might update the lattice after
101+
/// dependent.
101102
const AbstractDenseLattice *getLatticeFor(ProgramPoint dependent,
102-
ProgramPoint point);
103+
LatticeAnchor anchor);
103104

104105
/// Set the dense lattice at control flow entry point and propagate an update
105106
/// if it changed.
@@ -249,9 +250,9 @@ class DenseForwardDataFlowAnalysis
249250
}
250251

251252
protected:
252-
/// Get the dense lattice after this program point.
253-
LatticeT *getLattice(ProgramPoint point) override {
254-
return getOrCreate<LatticeT>(point);
253+
/// Get the dense lattice on this lattice anchor.
254+
LatticeT *getLattice(LatticeAnchor anchor) override {
255+
return getOrCreate<LatticeT>(anchor);
255256
}
256257

257258
/// Set the dense lattice at control flow entry point and propagate an update
@@ -331,16 +332,16 @@ class AbstractDenseBackwardDataFlowAnalysis : public DataFlowAnalysis {
331332
const AbstractDenseLattice &after,
332333
AbstractDenseLattice *before) = 0;
333334

334-
/// Get the dense lattice before the execution of the program point. That is,
335+
/// Get the dense lattice before the execution of the lattice anchor. That is,
335336
/// before the execution of the given operation or after the execution of the
336337
/// block.
337-
virtual AbstractDenseLattice *getLattice(ProgramPoint point) = 0;
338+
virtual AbstractDenseLattice *getLattice(LatticeAnchor anchor) = 0;
338339

339-
/// Get the dense lattice before the execution of the program point `point`
340-
/// and declare that the `dependent` program point must be updated every time
341-
/// `point` is.
340+
/// Get the dense lattice before the execution of the program point in
341+
/// `anchor` and declare that the `dependent` program point must be updated
342+
/// every time `point` is.
342343
const AbstractDenseLattice *getLatticeFor(ProgramPoint dependent,
343-
ProgramPoint point);
344+
LatticeAnchor anchor);
344345

345346
/// Set the dense lattice before at the control flow exit point and propagate
346347
/// the update if it changed.
@@ -500,9 +501,9 @@ class DenseBackwardDataFlowAnalysis
500501
}
501502

502503
protected:
503-
/// Get the dense lattice at the given program point.
504-
LatticeT *getLattice(ProgramPoint point) override {
505-
return getOrCreate<LatticeT>(point);
504+
/// Get the dense lattice at the given lattice anchor.
505+
LatticeT *getLattice(LatticeAnchor anchor) override {
506+
return getOrCreate<LatticeT>(anchor);
506507
}
507508

508509
/// Set the dense lattice at control flow exit point (after the terminator)

mlir/include/mlir/Analysis/DataFlow/IntegerRangeAnalysis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class IntegerRangeAnalysis
5050
/// At an entry point, we cannot reason about interger value ranges.
5151
void setToEntryState(IntegerValueRangeLattice *lattice) override {
5252
propagateIfChanged(lattice, lattice->join(IntegerValueRange::getMaxRange(
53-
lattice->getPoint())));
53+
lattice->getAnchor())));
5454
}
5555

5656
/// Visit an operation. Invoke the transfer function on each operation that

mlir/include/mlir/Analysis/DataFlow/SparseAnalysis.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class AbstractSparseLattice : public AnalysisState {
3636
/// Lattices can only be created for values.
3737
AbstractSparseLattice(Value value) : AnalysisState(value) {}
3838

39-
/// Return the program point this lattice is located at.
40-
Value getPoint() const { return AnalysisState::getPoint().get<Value>(); }
39+
/// Return the value this lattice is located at.
40+
Value getAnchor() const { return AnalysisState::getAnchor().get<Value>(); }
4141

4242
/// Join the information contained in 'rhs' into this lattice. Returns
4343
/// if the value of the lattice changed.
@@ -86,8 +86,8 @@ class Lattice : public AbstractSparseLattice {
8686
public:
8787
using AbstractSparseLattice::AbstractSparseLattice;
8888

89-
/// Return the program point this lattice is located at.
90-
Value getPoint() const { return point.get<Value>(); }
89+
/// Return the value this lattice is located at.
90+
Value getAnchor() const { return anchor.get<Value>(); }
9191

9292
/// Return the value held by this lattice. This requires that the value is
9393
/// initialized.

0 commit comments

Comments
 (0)