From: Patrick Palka <ppalka@redhat.com>
To: gcc-patches@gcc.gnu.org
Cc: libstdc++@gcc.gnu.org, Patrick Palka <ppalka@redhat.com>
Subject: [PATCH 2/4] libstdc++: Apply modifications to our local copy of Ryu
Date: Tue, 14 Jul 2020 15:41:44 -0400 [thread overview]
Message-ID: <20200714194146.3978209-2-ppalka@redhat.com> (raw)
In-Reply-To: <20200714194146.3978209-1-ppalka@redhat.com>
This performs the following modifications to our local copy of Ryu in
order to make it more easily usable for our std::to_chars implementation:
* Remove all #includes
* Remove copy_special_str routines
* Adjust the exponent formatting to match printf
* Remove some functions we're not going to use
* Add an out-parameter to d2exp_buffered_n for the scientific exponent
* Store the sign bit inside struct floating_decimal_[32|64]
* Rename [df]2s_buffered_n and change their return type
libstdc++-v3/ChangeLog:
* src/c++17/ryu/common.h, src/c++17/ryu/d2fixed.c,
src/c++17/ryu/d2fixed_full_table.h, src/c++17/ryu/d2s.c,
src/c++17/ryu/d2s_intrinsics.h, src/c++17/ryu/f2s.c,
src/c++17/ryu/f2s_intrinsics.h: Apply local modifications.
---
libstdc++-v3/src/c++17/ryu/common.h | 19 ----
libstdc++-v3/src/c++17/ryu/d2fixed.c | 98 ++-----------------
.../src/c++17/ryu/d2fixed_full_table.h | 1 -
libstdc++-v3/src/c++17/ryu/d2s.c | 56 +++--------
libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h | 4 -
libstdc++-v3/src/c++17/ryu/f2s.c | 52 +++-------
libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h | 4 -
libstdc++-v3/src/c++17/ryu/generic_128.c | 7 +-
8 files changed, 43 insertions(+), 198 deletions(-)
diff --git a/libstdc++-v3/src/c++17/ryu/common.h b/libstdc++-v3/src/c++17/ryu/common.h
index 7dc130947ac..f8ee147db04 100644
--- a/libstdc++-v3/src/c++17/ryu/common.h
+++ b/libstdc++-v3/src/c++17/ryu/common.h
@@ -17,9 +17,6 @@
#ifndef RYU_COMMON_H
#define RYU_COMMON_H
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
#if defined(_M_IX86) || defined(_M_ARM)
#define RYU_32_BIT_PLATFORM
@@ -83,22 +80,6 @@ static inline uint32_t log10Pow5(const int32_t e) {
return (((uint32_t) e) * 732923) >> 20;
}
-static inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) {
- if (mantissa) {
- memcpy(result, "NaN", 3);
- return 3;
- }
- if (sign) {
- result[0] = '-';
- }
- if (exponent) {
- memcpy(result + sign, "Infinity", 8);
- return sign + 8;
- }
- memcpy(result + sign, "0E0", 3);
- return sign + 3;
-}
-
static inline uint32_t float_to_bits(const float f) {
uint32_t bits = 0;
memcpy(&bits, &f, sizeof(float));
diff --git a/libstdc++-v3/src/c++17/ryu/d2fixed.c b/libstdc++-v3/src/c++17/ryu/d2fixed.c
index 5f479abb91b..642a29d3010 100644
--- a/libstdc++-v3/src/c++17/ryu/d2fixed.c
+++ b/libstdc++-v3/src/c++17/ryu/d2fixed.c
@@ -23,23 +23,11 @@
//
// -DRYU_AVOID_UINT128 Avoid using uint128_t. Slower, depending on your compiler.
-#include "ryu/ryu.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
#ifdef RYU_DEBUG
-#include <inttypes.h>
-#include <stdio.h>
#endif
-#include "ryu/common.h"
-#include "ryu/digit_table.h"
-#include "ryu/d2fixed_full_table.h"
-#include "ryu/d2s_intrinsics.h"
#define DOUBLE_MANTISSA_BITS 52
#define DOUBLE_EXPONENT_BITS 11
@@ -328,33 +316,6 @@ static inline uint32_t lengthForIndex(const uint32_t idx) {
return (log10Pow2(16 * (int32_t) idx) + 1 + 16 + 8) / 9;
}
-static inline int copy_special_str_printf(char* const result, const bool sign, const uint64_t mantissa) {
-#if defined(_MSC_VER)
- // TODO: Check that -nan is expected output on Windows.
- if (sign) {
- result[0] = '-';
- }
- if (mantissa) {
- if (mantissa < (1ull << (DOUBLE_MANTISSA_BITS - 1))) {
- memcpy(result + sign, "nan(snan)", 9);
- return sign + 9;
- }
- memcpy(result + sign, "nan", 3);
- return sign + 3;
- }
-#else
- if (mantissa) {
- memcpy(result, "nan", 3);
- return 3;
- }
- if (sign) {
- result[0] = '-';
- }
-#endif
- memcpy(result + sign, "Infinity", 8);
- return sign + 8;
-}
-
int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
const uint64_t bits = double_to_bits(d);
#ifdef RYU_DEBUG
@@ -372,20 +333,10 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) {
- return copy_special_str_printf(result, ieeeSign, ieeeMantissa);
+ __builtin_abort();
}
if (ieeeExponent == 0 && ieeeMantissa == 0) {
- int index = 0;
- if (ieeeSign) {
- result[index++] = '-';
- }
- result[index++] = '0';
- if (precision > 0) {
- result[index++] = '.';
- memset(result + index, '0', precision);
- index += precision;
- }
- return index;
+ __builtin_abort();
}
int32_t e2;
@@ -549,21 +500,9 @@ int d2fixed_buffered_n(double d, uint32_t precision, char* result) {
return index;
}
-void d2fixed_buffered(double d, uint32_t precision, char* result) {
- const int len = d2fixed_buffered_n(d, precision, result);
- result[len] = '\0';
-}
-
-char* d2fixed(double d, uint32_t precision) {
- char* const buffer = (char*)malloc(2000);
- const int index = d2fixed_buffered_n(d, precision, buffer);
- buffer[index] = '\0';
- return buffer;
-}
-
-int d2exp_buffered_n(double d, uint32_t precision, char* result) {
+int d2exp_buffered_n(double d, uint32_t precision, char* result, int* exp_out) {
const uint64_t bits = double_to_bits(d);
#ifdef RYU_DEBUG
printf("IN=");
@@ -580,22 +519,10 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u)) {
- return copy_special_str_printf(result, ieeeSign, ieeeMantissa);
+ __builtin_abort();
}
if (ieeeExponent == 0 && ieeeMantissa == 0) {
- int index = 0;
- if (ieeeSign) {
- result[index++] = '-';
- }
- result[index++] = '0';
- if (precision > 0) {
- result[index++] = '.';
- memset(result + index, '0', precision);
- index += precision;
- }
- memcpy(result + index, "e+00", 4);
- index += 4;
- return index;
+ __builtin_abort();
}
int32_t e2;
@@ -785,6 +712,9 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
}
}
}
+ if (exp_out) {
+ *exp_out = exp;
+ }
result[index++] = 'e';
if (exp < 0) {
result[index++] = '-';
@@ -805,15 +735,3 @@ int d2exp_buffered_n(double d, uint32_t precision, char* result) {
return index;
}
-
-void d2exp_buffered(double d, uint32_t precision, char* result) {
- const int len = d2exp_buffered_n(d, precision, result);
- result[len] = '\0';
-}
-
-char* d2exp(double d, uint32_t precision) {
- char* const buffer = (char*)malloc(2000);
- const int index = d2exp_buffered_n(d, precision, buffer);
- buffer[index] = '\0';
- return buffer;
-}
diff --git a/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h b/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h
index 70857652161..1fa252959e6 100644
--- a/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h
+++ b/libstdc++-v3/src/c++17/ryu/d2fixed_full_table.h
@@ -17,7 +17,6 @@
#ifndef RYU_D2FIXED_FULL_TABLE_H
#define RYU_D2FIXED_FULL_TABLE_H
-#include <stdint.h>
#define TABLE_SIZE 64
diff --git a/libstdc++-v3/src/c++17/ryu/d2s.c b/libstdc++-v3/src/c++17/ryu/d2s.c
index aa0da52da71..3225808c463 100644
--- a/libstdc++-v3/src/c++17/ryu/d2s.c
+++ b/libstdc++-v3/src/c++17/ryu/d2s.c
@@ -27,28 +27,15 @@
// size by about 10x (only one case, and only double) at the cost of some
// performance. Currently requires MSVC intrinsics.
-#include "ryu/ryu.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
#ifdef RYU_DEBUG
-#include <inttypes.h>
-#include <stdio.h>
#endif
-#include "ryu/common.h"
-#include "ryu/digit_table.h"
-#include "ryu/d2s_intrinsics.h"
// Include either the small or the full lookup tables depending on the mode.
#if defined(RYU_OPTIMIZE_SIZE)
-#include "ryu/d2s_small_table.h"
#else
-#include "ryu/d2s_full_table.h"
#endif
#define DOUBLE_MANTISSA_BITS 52
@@ -86,9 +73,10 @@ typedef struct floating_decimal_64 {
// Decimal exponent's range is -324 to 308
// inclusive, and can fit in a short if needed.
int32_t exponent;
+ bool sign;
} floating_decimal_64;
-static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent) {
+static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) {
int32_t e2;
uint64_t m2;
if (ieeeExponent == 0) {
@@ -308,13 +296,14 @@ static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_
floating_decimal_64 fd;
fd.exponent = exp;
fd.mantissa = output;
+ fd.sign = ieeeSign;
return fd;
}
-static inline int to_chars(const floating_decimal_64 v, const bool sign, char* const result) {
+static inline int to_chars(const floating_decimal_64 v, char* const result) {
// Step 5: Print the decimal representation.
int index = 0;
- if (sign) {
+ if (v.sign) {
result[index++] = '-';
}
@@ -397,29 +386,28 @@ static inline int to_chars(const floating_decimal_64 v, const bool sign, char* c
}
// Print the exponent.
- result[index++] = 'E';
+ result[index++] = 'e';
int32_t exp = v.exponent + (int32_t) olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
- }
+ } else
+ result[index++] = '+';
if (exp >= 100) {
const int32_t c = exp % 10;
memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2);
result[index + 2] = (char) ('0' + c);
index += 3;
- } else if (exp >= 10) {
+ } else {
memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
index += 2;
- } else {
- result[index++] = (char) ('0' + exp);
}
return index;
}
-static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent,
+static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign,
floating_decimal_64* const v) {
const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
@@ -448,10 +436,11 @@ static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t iee
// Note: since 2^53 < 10^16, there is no need to adjust decimalLength17().
v->mantissa = m2 >> -e2;
v->exponent = 0;
+ v->sign = ieeeSign;
return true;
}
-int d2s_buffered_n(double f, char* result) {
+floating_decimal_64 floating_to_fd64(double f) {
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
const uint64_t bits = double_to_bits(f);
@@ -469,11 +458,11 @@ int d2s_buffered_n(double f, char* result) {
const uint32_t ieeeExponent = (uint32_t) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
- return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
+ __builtin_abort();
}
floating_decimal_64 v;
- const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v);
+ const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, ieeeSign, &v);
if (isSmallInt) {
// For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
// For scientific notation we need to move these zeros into the exponent.
@@ -489,21 +478,8 @@ int d2s_buffered_n(double f, char* result) {
++v.exponent;
}
} else {
- v = d2d(ieeeMantissa, ieeeExponent);
+ v = d2d(ieeeMantissa, ieeeExponent, ieeeSign);
}
- return to_chars(v, ieeeSign, result);
-}
-
-void d2s_buffered(double f, char* result) {
- const int index = d2s_buffered_n(f, result);
-
- // Terminate the string.
- result[index] = '\0';
-}
-
-char* d2s(double f) {
- char* const result = (char*) malloc(25);
- d2s_buffered(f, result);
- return result;
+ return v;
}
diff --git a/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h b/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h
index ea590a60d25..fa993e6fad6 100644
--- a/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h
+++ b/libstdc++-v3/src/c++17/ryu/d2s_intrinsics.h
@@ -17,11 +17,8 @@
#ifndef RYU_D2S_INTRINSICS_H
#define RYU_D2S_INTRINSICS_H
-#include <assert.h>
-#include <stdint.h>
// Defines RYU_32_BIT_PLATFORM if applicable.
-#include "ryu/common.h"
// ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined.
// Let's do the same for now.
@@ -37,7 +34,6 @@ typedef __uint128_t uint128_t;
#if defined(HAS_64_BIT_INTRINSICS)
-#include <intrin.h>
static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
return _umul128(a, b, productHi);
diff --git a/libstdc++-v3/src/c++17/ryu/f2s.c b/libstdc++-v3/src/c++17/ryu/f2s.c
index 255ecbe599c..5e635958aa1 100644
--- a/libstdc++-v3/src/c++17/ryu/f2s.c
+++ b/libstdc++-v3/src/c++17/ryu/f2s.c
@@ -18,22 +18,11 @@
// Runtime compiler options:
// -DRYU_DEBUG Generate verbose debugging output to stdout.
-#include "ryu/ryu.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
#ifdef RYU_DEBUG
-#include <stdio.h>
#endif
-#include "ryu/common.h"
-#include "ryu/f2s_intrinsics.h"
-#include "ryu/digit_table.h"
#define FLOAT_MANTISSA_BITS 23
#define FLOAT_EXPONENT_BITS 8
@@ -45,9 +34,10 @@ typedef struct floating_decimal_32 {
// Decimal exponent's range is -45 to 38
// inclusive, and can fit in a short if needed.
int32_t exponent;
+ bool sign;
} floating_decimal_32;
-static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent) {
+static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_t ieeeExponent, const bool ieeeSign) {
int32_t e2;
uint32_t m2;
if (ieeeExponent == 0) {
@@ -224,13 +214,14 @@ static inline floating_decimal_32 f2d(const uint32_t ieeeMantissa, const uint32_
floating_decimal_32 fd;
fd.exponent = exp;
fd.mantissa = output;
+ fd.sign = ieeeSign;
return fd;
}
-static inline int to_chars(const floating_decimal_32 v, const bool sign, char* const result) {
+static inline int to_chars(const floating_decimal_32 v, char* const result) {
// Step 5: Print the decimal representation.
int index = 0;
- if (sign) {
+ if (v.sign) {
result[index++] = '-';
}
@@ -288,24 +279,22 @@ static inline int to_chars(const floating_decimal_32 v, const bool sign, char* c
}
// Print the exponent.
- result[index++] = 'E';
+ result[index++] = 'e';
int32_t exp = v.exponent + (int32_t) olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
- }
-
- if (exp >= 10) {
- memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
- index += 2;
} else {
- result[index++] = (char) ('0' + exp);
+ result[index++] = '+';
}
+ memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
+ index += 2;
+
return index;
}
-int f2s_buffered_n(float f, char* result) {
+floating_decimal_32 floating_to_fd32(float f) {
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
const uint32_t bits = float_to_bits(f);
@@ -324,22 +313,9 @@ int f2s_buffered_n(float f, char* result) {
// Case distinction; exit early for the easy cases.
if (ieeeExponent == ((1u << FLOAT_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
- return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
+ __builtin_abort();
}
- const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent);
- return to_chars(v, ieeeSign, result);
-}
-
-void f2s_buffered(float f, char* result) {
- const int index = f2s_buffered_n(f, result);
-
- // Terminate the string.
- result[index] = '\0';
-}
-
-char* f2s(float f) {
- char* const result = (char*) malloc(16);
- f2s_buffered(f, result);
- return result;
+ const floating_decimal_32 v = f2d(ieeeMantissa, ieeeExponent, ieeeSign);
+ return v;
}
diff --git a/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h b/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h
index bb822c9a0c0..db751a41329 100644
--- a/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h
+++ b/libstdc++-v3/src/c++17/ryu/f2s_intrinsics.h
@@ -18,18 +18,14 @@
#define RYU_F2S_INTRINSICS_H
// Defines RYU_32_BIT_PLATFORM if applicable.
-#include "ryu/common.h"
#if defined(RYU_FLOAT_FULL_TABLE)
-#include "ryu/f2s_full_table.h"
#else
#if defined(RYU_OPTIMIZE_SIZE)
-#include "ryu/d2s_small_table.h"
#else
-#include "ryu/d2s_full_table.h"
#endif
#define FLOAT_POW5_INV_BITCOUNT (DOUBLE_POW5_INV_BITCOUNT - 64)
#define FLOAT_POW5_BITCOUNT (DOUBLE_POW5_BITCOUNT - 64)
diff --git a/libstdc++-v3/src/c++17/ryu/generic_128.c b/libstdc++-v3/src/c++17/ryu/generic_128.c
index 2eb8da8aba8..fca6ecb8412 100644
--- a/libstdc++-v3/src/c++17/ryu/generic_128.c
+++ b/libstdc++-v3/src/c++17/ryu/generic_128.c
@@ -320,14 +320,17 @@ int generic_to_chars(const struct floating_decimal_128 v, char* const result) {
}
// Print the exponent.
- result[index++] = 'E';
+ result[index++] = 'e';
int32_t exp = v.exponent + olength - 1;
if (exp < 0) {
result[index++] = '-';
exp = -exp;
- }
+ } else
+ result[index++] = '+';
uint32_t elength = decimalLength(exp);
+ if (elength == 1)
+ ++elength;
for (uint32_t i = 0; i < elength; ++i) {
const uint32_t c = exp % 10;
exp /= 10;
--
2.28.0.rc0
next prev parent reply other threads:[~2020-07-14 19:41 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-14 19:41 [PATCH 1/4] libstdc++: Import parts of the Ryu library Patrick Palka
2020-07-14 19:41 ` Patrick Palka [this message]
2020-07-15 18:12 ` [PATCH 2/4] libstdc++: Apply modifications to our local copy of Ryu Patrick Palka
2020-12-17 14:35 ` Jonathan Wakely
2020-07-14 19:41 ` [PATCH 3/4] libstdc++: Add floating-point std::to_chars implementation Patrick Palka
2020-07-15 18:21 ` Patrick Palka
2020-07-17 4:23 ` Patrick Palka
2020-07-17 16:24 ` Patrick Palka
2020-07-20 3:37 ` Patrick Palka
2020-07-20 12:31 ` Jonathan Wakely
2020-07-20 12:53 ` Patrick Palka
2020-07-20 14:13 ` Jonathan Wakely
2020-07-20 14:46 ` Patrick Palka
2020-07-22 15:56 ` Patrick Palka
2020-08-19 21:57 ` Patrick Palka
2020-12-17 14:32 ` Jonathan Wakely
2020-12-18 4:13 ` Patrick Palka
2020-12-18 13:24 ` Christophe Lyon
2020-12-18 14:58 ` Jonathan Wakely
2020-12-18 15:00 ` Patrick Palka
2020-12-18 16:52 ` Christophe Lyon
2020-12-18 17:03 ` Patrick Palka
2020-12-18 18:28 ` Christophe Lyon
2020-12-20 21:44 ` Maciej W. Rozycki
2020-12-21 17:06 ` Patrick Palka
2020-12-21 23:09 ` Maciej W. Rozycki
2020-07-14 19:41 ` [PATCH 4/4] libstdc++: Import MSVC floating-point std::to_chars testcases Patrick Palka
2020-07-14 19:49 ` Patrick Palka
2020-12-17 14:37 ` Jonathan Wakely
2020-07-14 19:46 ` [PATCH 1/4] libstdc++: Import parts of the Ryu library Patrick Palka
2020-07-25 11:44 ` Václav Haisman
2020-07-26 13:09 ` Patrick Palka
2020-12-17 14:34 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200714194146.3978209-2-ppalka@redhat.com \
--to=ppalka@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).