1//===-- SIModeRegisterDefaults.cpp ------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SIModeRegisterDefaults.h"
10#include "GCNSubtarget.h"
11
12using namespace llvm;
13
14SIModeRegisterDefaults::SIModeRegisterDefaults(const Function &F,
15                                               const GCNSubtarget &ST) {
16  *this = getDefaultForCallingConv(F.getCallingConv());
17
18  if (ST.hasIEEEMode()) {
19    StringRef IEEEAttr = F.getFnAttribute("amdgpu-ieee").getValueAsString();
20    if (!IEEEAttr.empty())
21      IEEE = IEEEAttr == "true";
22  }
23
24  if (ST.hasDX10ClampMode()) {
25    StringRef DX10ClampAttr =
26        F.getFnAttribute("amdgpu-dx10-clamp").getValueAsString();
27    if (!DX10ClampAttr.empty())
28      DX10Clamp = DX10ClampAttr == "true";
29  }
30
31  StringRef DenormF32Attr =
32      F.getFnAttribute("denormal-fp-math-f32").getValueAsString();
33  if (!DenormF32Attr.empty())
34    FP32Denormals = parseDenormalFPAttribute(DenormF32Attr);
35
36  StringRef DenormAttr =
37      F.getFnAttribute("denormal-fp-math").getValueAsString();
38  if (!DenormAttr.empty()) {
39    DenormalMode DenormMode = parseDenormalFPAttribute(DenormAttr);
40    if (DenormF32Attr.empty())
41      FP32Denormals = DenormMode;
42    FP64FP16Denormals = DenormMode;
43  }
44}
45
46using namespace AMDGPU;
47
48/// Combine f32 and f64 rounding modes into a combined rounding mode value.
49static constexpr uint32_t getModeRegisterRoundMode(uint32_t HWFP32Val,
50                                                   uint32_t HWFP64Val) {
51  return HWFP32Val << F32FltRoundOffset | HWFP64Val << F64FltRoundOffset;
52}
53
54static constexpr uint64_t encodeFltRoundsTable(uint32_t FltRoundsVal,
55                                               uint32_t HWF32Val,
56                                               uint32_t HWF64Val) {
57  uint32_t ModeVal = getModeRegisterRoundMode(HWF32Val, HWF64Val);
58  if (FltRoundsVal > TowardNegative)
59    FltRoundsVal -= ExtendedFltRoundOffset;
60
61  uint32_t BitIndex = ModeVal << 2;
62  return static_cast<uint64_t>(FltRoundsVal) << BitIndex;
63}
64
65// Encode FLT_ROUNDS value where the two rounding modes are the same and use a
66// standard value
67static constexpr uint64_t
68encodeFltRoundsTableSame(AMDGPUFltRounds FltRoundsMode, uint32_t HWVal) {
69  return encodeFltRoundsTable(FltRoundsMode, HWVal, HWVal);
70}
71
72// Convert mode register encoded rounding mode to AMDGPUFltRounds
73static constexpr AMDGPUFltRounds
74decodeIndexFltRoundConversionTable(uint32_t HWMode) {
75  uint32_t TableRead = (FltRoundConversionTable >> (HWMode << 2)) & 0xf;
76  if (TableRead > TowardNegative)
77    TableRead += ExtendedFltRoundOffset;
78  return static_cast<AMDGPUFltRounds>(TableRead);
79}
80
81static constexpr uint32_t HWTowardZero = FP_ROUND_ROUND_TO_ZERO;
82static constexpr uint32_t HWNearestTiesToEven = FP_ROUND_ROUND_TO_NEAREST;
83static constexpr uint32_t HWTowardPositive = FP_ROUND_ROUND_TO_INF;
84static constexpr uint32_t HWTowardNegative = FP_ROUND_ROUND_TO_NEGINF;
85
86const uint64_t AMDGPU::FltRoundConversionTable =
87    encodeFltRoundsTableSame(TowardZeroF32_TowardZeroF64, HWTowardZero) |
88    encodeFltRoundsTableSame(NearestTiesToEvenF32_NearestTiesToEvenF64,
89                             HWNearestTiesToEven) |
90    encodeFltRoundsTableSame(TowardPositiveF32_TowardPositiveF64,
91                             HWTowardPositive) |
92    encodeFltRoundsTableSame(TowardNegativeF32_TowardNegativeF64,
93                             HWTowardNegative) |
94
95    encodeFltRoundsTable(TowardZeroF32_NearestTiesToEvenF64, HWTowardZero,
96                         HWNearestTiesToEven) |
97    encodeFltRoundsTable(TowardZeroF32_TowardPositiveF64, HWTowardZero,
98                         HWTowardPositive) |
99    encodeFltRoundsTable(TowardZeroF32_TowardNegativeF64, HWTowardZero,
100                         HWTowardNegative) |
101
102    encodeFltRoundsTable(NearestTiesToEvenF32_TowardZeroF64,
103                         HWNearestTiesToEven, HWTowardZero) |
104    encodeFltRoundsTable(NearestTiesToEvenF32_TowardPositiveF64,
105                         HWNearestTiesToEven, HWTowardPositive) |
106    encodeFltRoundsTable(NearestTiesToEvenF32_TowardNegativeF64,
107                         HWNearestTiesToEven, HWTowardNegative) |
108
109    encodeFltRoundsTable(TowardPositiveF32_TowardZeroF64, HWTowardPositive,
110                         HWTowardZero) |
111    encodeFltRoundsTable(TowardPositiveF32_NearestTiesToEvenF64,
112                         HWTowardPositive, HWNearestTiesToEven) |
113    encodeFltRoundsTable(TowardPositiveF32_TowardNegativeF64, HWTowardPositive,
114                         HWTowardNegative) |
115
116    encodeFltRoundsTable(TowardNegativeF32_TowardZeroF64, HWTowardNegative,
117                         HWTowardZero) |
118    encodeFltRoundsTable(TowardNegativeF32_NearestTiesToEvenF64,
119                         HWTowardNegative, HWNearestTiesToEven) |
120    encodeFltRoundsTable(TowardNegativeF32_TowardPositiveF64, HWTowardNegative,
121                         HWTowardPositive);
122
123// Verify evaluation of FltRoundConversionTable
124
125// If both modes are the same, should return the standard values.
126static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
127                  HWTowardZero, HWTowardZero)) == AMDGPUFltRounds::TowardZero);
128static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
129                  HWNearestTiesToEven, HWNearestTiesToEven)) ==
130              AMDGPUFltRounds::NearestTiesToEven);
131static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
132                  HWTowardPositive, HWTowardPositive)) ==
133              AMDGPUFltRounds::TowardPositive);
134static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
135                  HWTowardNegative, HWTowardNegative)) ==
136              AMDGPUFltRounds::TowardNegative);
137
138static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
139                  HWTowardZero, HWNearestTiesToEven)) ==
140              TowardZeroF32_NearestTiesToEvenF64);
141static_assert(decodeIndexFltRoundConversionTable(
142                  getModeRegisterRoundMode(HWTowardZero, HWTowardPositive)) ==
143              TowardZeroF32_TowardPositiveF64);
144static_assert(decodeIndexFltRoundConversionTable(
145                  getModeRegisterRoundMode(HWTowardZero, HWTowardNegative)) ==
146              TowardZeroF32_TowardNegativeF64);
147
148static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
149                  HWNearestTiesToEven, HWTowardZero)) ==
150              NearestTiesToEvenF32_TowardZeroF64);
151static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
152                  HWNearestTiesToEven, HWTowardPositive)) ==
153              NearestTiesToEvenF32_TowardPositiveF64);
154static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
155                  HWNearestTiesToEven, HWTowardNegative)) ==
156              NearestTiesToEvenF32_TowardNegativeF64);
157
158static_assert(decodeIndexFltRoundConversionTable(
159                  getModeRegisterRoundMode(HWTowardPositive, HWTowardZero)) ==
160              TowardPositiveF32_TowardZeroF64);
161static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
162                  HWTowardPositive, HWNearestTiesToEven)) ==
163              TowardPositiveF32_NearestTiesToEvenF64);
164static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
165                  HWTowardPositive, HWTowardNegative)) ==
166              TowardPositiveF32_TowardNegativeF64);
167
168static_assert(decodeIndexFltRoundConversionTable(
169                  getModeRegisterRoundMode(HWTowardNegative, HWTowardZero)) ==
170              TowardNegativeF32_TowardZeroF64);
171static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
172                  HWTowardNegative, HWNearestTiesToEven)) ==
173              TowardNegativeF32_NearestTiesToEvenF64);
174static_assert(decodeIndexFltRoundConversionTable(getModeRegisterRoundMode(
175                  HWTowardNegative, HWTowardPositive)) ==
176              TowardNegativeF32_TowardPositiveF64);
177