File: exceptions.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (87 lines) | stat: -rw-r--r-- 3,295 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//===-- runtime/exceptions.cpp --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// Map Fortran ieee_arithmetic module exceptions to fenv.h exceptions.

#include "flang/Runtime/exceptions.h"
#include "terminator.h"
#include "flang/Runtime/magic-numbers.h"
#include <cfenv>

#ifndef __FE_DENORM
#define __FE_DENORM 0 // denorm is nonstandard
#endif

namespace Fortran::runtime {

extern "C" {

std::int32_t RTNAME(MapException)(int32_t except) {
  Terminator terminator{__FILE__, __LINE__};

  static constexpr int32_t mask{_FORTRAN_RUNTIME_IEEE_INVALID |
      _FORTRAN_RUNTIME_IEEE_DENORM | _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO |
      _FORTRAN_RUNTIME_IEEE_OVERFLOW | _FORTRAN_RUNTIME_IEEE_UNDERFLOW |
      _FORTRAN_RUNTIME_IEEE_INEXACT};
  if (except == 0 || except != (except & mask)) {
    terminator.Crash("Invalid exception value: %d", except);
  }

  // Fortran and fenv.h values are identical; return the value.
  if constexpr (_FORTRAN_RUNTIME_IEEE_INVALID == FE_INVALID &&
      _FORTRAN_RUNTIME_IEEE_DENORM == __FE_DENORM &&
      _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO == FE_DIVBYZERO &&
      _FORTRAN_RUNTIME_IEEE_OVERFLOW == FE_OVERFLOW &&
      _FORTRAN_RUNTIME_IEEE_UNDERFLOW == FE_UNDERFLOW &&
      _FORTRAN_RUNTIME_IEEE_INEXACT == FE_INEXACT) {
    return except;
  }

  // fenv.h calls that take exception arguments are able to process multiple
  // exceptions in one call, such as FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID.
  // And intrinsic module procedures that manage exceptions are elemental
  // procedures that may specify multiple exceptions, such as ieee_all.
  // However, general elemental call processing places single scalar arguments
  // in a loop. As a consequence, argument 'except' here will be a power of
  // two, corresponding to a single exception. If code generation were
  // modified to bypass normal elemental call processing for calls with
  // ieee_usual, ieee_all, or user-specified array arguments, this switch
  // could be extended to support that.

  // Fortran and fenv.h values differ.
  switch (except) {
  case _FORTRAN_RUNTIME_IEEE_INVALID:
    return FE_INVALID;
  case _FORTRAN_RUNTIME_IEEE_DENORM:
    if (__FE_DENORM) {
      return __FE_DENORM;
    }
    break;
  case _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO:
    return FE_DIVBYZERO;
  case _FORTRAN_RUNTIME_IEEE_OVERFLOW:
    return FE_OVERFLOW;
  case _FORTRAN_RUNTIME_IEEE_UNDERFLOW:
    return FE_UNDERFLOW;
  case _FORTRAN_RUNTIME_IEEE_INEXACT:
    return FE_INEXACT;
  }

  terminator.Crash("Invalid exception set: %d", except);
}

// Verify that the size of ieee_modes_type and ieee_status_type objects from
// intrinsic module file __fortran_ieee_exceptions.f90 are large enough to
// hold fenv_t object.
// TODO: fenv_t can be way larger than
//	sizeof(int) * _FORTRAN_RUNTIME_IEEE_FENV_T_EXTENT
// on some systems, e.g. Solaris, so omit object size comparison for now.
// TODO: consider femode_t object size comparison once its more mature.

} // extern "C"
} // namespace Fortran::runtime