1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_BASE_CHECKS_H_
18 #define BERBERIS_BASE_CHECKS_H_
19 
20 #include <array>
21 #include <cinttypes>
22 
23 #include "berberis/base/config.h"
24 #include "berberis/base/logging.h"
25 
26 // Helpers for building message format, without incurring any function calls when the condition
27 // does not fail.
28 
29 namespace berberis {
30 
31 class FmtSpec {
32  private:
Get(int32_t)33   constexpr static const char (&Get(int32_t))[sizeof "%" PRId32] { return "%" PRId32; }
Get(uint32_t)34   constexpr static const char (&Get(uint32_t))[sizeof "%" PRIu32] { return "%" PRIu32; }
Get(int64_t)35   constexpr static const char (&Get(int64_t))[sizeof "%" PRId64] { return "%" PRId64; }
Get(uint64_t)36   constexpr static const char (&Get(uint64_t))[sizeof "%" PRIu64] { return "%" PRIu64; }
Get(double)37   constexpr static const char (&Get(double))[sizeof "%f"] { return "%f"; }
Get(const void *)38   constexpr static const char (&Get(const void*))[sizeof "%p"] { return "%p"; }
39 
40  public:
41   template <typename Type>
42   constexpr static auto& kValue = FmtSpec::Get(static_cast<std::decay_t<Type>>(0));
43 
44   template <size_t prefix_len, size_t op_len, size_t spec1_len, size_t spec2_len>
Fmt(const char (& prefix)[prefix_len],const char (& op)[op_len],const char (& spec1)[spec1_len],const char (& spec2)[spec2_len])45   constexpr static std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> Fmt(
46       const char (&prefix)[prefix_len], const char (&op)[op_len], const char (&spec1)[spec1_len],
47       const char (&spec2)[spec2_len]) {
48     std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> fmt{};
49     auto pos = begin(fmt);
50     Append(&pos, prefix, prefix_len);
51     Append(&pos, spec1, spec1_len);
52     Append(&pos, op, op_len);
53     Append(&pos, spec2, spec2_len);
54     return fmt;
55   }
56 
57  private:
58   template <typename Iterator>
Append(Iterator * pos,const char * text,size_t len)59   constexpr static void Append(Iterator* pos, const char* text, size_t len) {
60     while (--len > 0) *(*pos)++ = *text++;
61   }
62 };
63 
ValueForFmtSpec(auto && value)64 constexpr auto&& ValueForFmtSpec(auto&& value) {
65   return std::forward<decltype(value)>(value);
66 }
67 
68 }  // namespace berberis
69 
70 #define BERBERIS_VALUE_STR_IMPL(v) #v
71 #define BERBERIS_VALUE_STR(v) BERBERIS_VALUE_STR_IMPL(v)
72 #define BERBERIS_CHECK_PREFIX __FILE__ ":" BERBERIS_VALUE_STR(__LINE__) ": CHECK failed: "
73 
74 // Log fatal error.
75 // NEVER stripped - side effects always apply.
76 
77 #define FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
78 
79 #define UNREACHABLE() FATAL("This code is (supposed to be) unreachable.")
80 
81 #define FATAL_UNIMPL_INSN_IF_NOT_BRINGUP()            \
82   if (!berberis::config::kInstructionsBringupMode) {  \
83     FATAL("Unimplemented instruction: %s", __func__); \
84   }
85 
86 #ifdef CHECK
87 #undef CHECK
88 #endif
89 #define CHECK(cond) LOG_ALWAYS_FATAL_IF(!(cond), "%s", BERBERIS_CHECK_PREFIX #cond)
90 
91 // TODO(b/232598137): fix multiple evaluation of v1 and v2!
92 // TODO(b/232598137): change message from '1 == 0' to 'x == y (1 == 0)'!
93 #define BERBERIS_CHECK_OP(op, v1, v2)                                                         \
94   LOG_ALWAYS_FATAL_IF(                                                                        \
95       !((v1)op(v2)), /* // NOLINT */                                                          \
96       []() {                                                                                  \
97         using ::berberis::ValueForFmtSpec;                                                    \
98         constexpr static auto __fmt =                                                         \
99             berberis::FmtSpec::Fmt(BERBERIS_CHECK_PREFIX,                                     \
100                                    " " #op " ",                                               \
101                                    berberis::FmtSpec::kValue<decltype(ValueForFmtSpec(v1))>,  \
102                                    berberis::FmtSpec::kValue<decltype(ValueForFmtSpec(v2))>); \
103         return __fmt.data();                                                                  \
104       }(),                                                                                    \
105       ({                                                                                      \
106         using ::berberis::ValueForFmtSpec;                                                    \
107         ValueForFmtSpec(v1);                                                                  \
108       }),                                                                                     \
109       ({                                                                                      \
110         using ::berberis::ValueForFmtSpec;                                                    \
111         ValueForFmtSpec(v2);                                                                  \
112       }))
113 
114 #ifdef CHECK_EQ
115 #undef CHECK_EQ
116 #endif
117 #define CHECK_EQ(v1, v2) BERBERIS_CHECK_OP(==, v1, v2)
118 
119 #ifdef CHECK_NE
120 #undef CHECK_NE
121 #endif
122 #define CHECK_NE(v1, v2) BERBERIS_CHECK_OP(!=, v1, v2)
123 
124 #ifdef CHECK_LT
125 #undef CHECK_LT
126 #endif
127 #define CHECK_LT(v1, v2) BERBERIS_CHECK_OP(<, v1, v2)
128 
129 #ifdef CHECK_LE
130 #undef CHECK_LE
131 #endif
132 #define CHECK_LE(v1, v2) BERBERIS_CHECK_OP(<=, v1, v2)
133 
134 #ifdef CHECK_GT
135 #undef CHECK_GT
136 #endif
137 #define CHECK_GT(v1, v2) BERBERIS_CHECK_OP(>, v1, v2)
138 
139 #ifdef CHECK_GE
140 #undef CHECK_GE
141 #endif
142 #define CHECK_GE(v1, v2) BERBERIS_CHECK_OP(>=, v1, v2)
143 
144 // Log fatal error.
145 // ATTENTION - stripped from release builds, be careful with side effects!
146 
147 #ifdef DCHECK
148 #undef DCHECK
149 #endif
150 #if LOG_NDEBUG
151 #define DCHECK(cond)
152 #else
153 #define DCHECK(cond) CHECK(cond)
154 #endif
155 
156 #if LOG_NDEBUG
157 #define BERBERIS_DCHECK_OP(op, v1, v2)
158 #else
159 #define BERBERIS_DCHECK_OP(op, v1, v2) BERBERIS_CHECK_OP(op, v1, v2)
160 #endif
161 
162 #ifdef DCHECK_EQ
163 #undef DCHECK_EQ
164 #endif
165 #define DCHECK_EQ(v1, v2) BERBERIS_DCHECK_OP(==, v1, v2)
166 
167 #ifdef DCHECK_NE
168 #undef DCHECK_NE
169 #endif
170 #define DCHECK_NE(v1, v2) BERBERIS_DCHECK_OP(!=, v1, v2)
171 
172 #ifdef DCHECK_LT
173 #undef DCHECK_LT
174 #endif
175 #define DCHECK_LT(v1, v2) BERBERIS_DCHECK_OP(<, v1, v2)
176 
177 #ifdef DCHECK_LE
178 #undef DCHECK_LE
179 #endif
180 #define DCHECK_LE(v1, v2) BERBERIS_DCHECK_OP(<=, v1, v2)
181 
182 #ifdef DCHECK_GT
183 #undef DCHECK_GT
184 #endif
185 #define DCHECK_GT(v1, v2) BERBERIS_DCHECK_OP(>, v1, v2)
186 
187 #ifdef DCHECK_GE
188 #undef DCHECK_GE
189 #endif
190 #define DCHECK_GE(v1, v2) BERBERIS_DCHECK_OP(>=, v1, v2)
191 
192 #endif  // BERBERIS_BASE_CHECKS_H_
193