https://github.com/eleviant updated https://github.com/llvm/llvm-project/pull/196392
>From 9f2baf5de8177e88dd18812cef0e89875b64dade Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 14 Apr 2026 16:17:11 +0200 Subject: [PATCH 1/5] [clang] Introduce -fstable-pointer-subtraction flag The C and C++ standards require both operands of a pointer subtraction to refer to elements of the same array object. Clang/LLVM currently relies on this rule in several optimizations: * `inbounds` GEP introduces UB-based assumptions once the computed address escapes the bounds of the originating object. * `sdiv exact` assumes that the byte offset between two pointers is an exact multiple of the pointee size when lowering pointer subtraction. While `-fwrapv-pointer` allows Clang to emit regular GEPs instead of `inbounds` GEPs, there is currently no equivalent mechanism to avoid generating `sdiv exact` for pointer subtraction operations. This becomes an issue for low-level code such as kernels and boot loaders, where pointer arithmetic is often performed over externally defined memory layouts rather than well-typed C objects. In such cases, the assumptions required by `sdiv exact` may not hold, causing the result to become poison and enabling incorrect optimizations. Introduce `-fstable-pointer-subtraction` to suppress these assumptions and preserve stable pointer subtraction semantics in the generated IR. --- clang/include/clang/Basic/LangOptions.def | 2 ++ clang/include/clang/Options/Options.td | 7 +++++++ clang/lib/CodeGen/CGExprScalar.cpp | 2 ++ clang/test/CodeGen/ptr-subtract-stable.c | 15 +++++++++++++++ 4 files changed, 26 insertions(+) create mode 100644 clang/test/CodeGen/ptr-subtract-stable.c diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 1fb491a54a278..0bccf316f2daf 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -534,6 +534,8 @@ LANGOPT(EnableLifetimeSafetyTUAnalysis, 1, 0, Benign, "Lifetime safety at transl LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type") LANGOPT(Reflection , 1, 0, NotCompatible, "C++26 Reflection") +LANGOPT(StablePointerSubtraction, 1, 0, NotCompatible, "Make unaligned pointer subtraction stable") + #undef LANGOPT #undef ENUM_LANGOPT #undef VALUE_LANGOPT diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index bad443efb6c65..37ee6ded12388 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4895,6 +4895,13 @@ def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>, def fwrapv_pointer : Flag<["-"], "fwrapv-pointer">, Group<f_Group>, Visibility<[ClangOption, CLOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Treat pointer overflow as two's complement">; +def fstable_pointer_subtraction : + Flag<["-"], "fstable-pointer-subtraction">, Group<f_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText< + "Allow stable subtraction of pointers not aligned to object boundaries" + >, + MarshallingInfoFlag<LangOpts<"StablePointerSubtraction">>; def fno_wrapv_pointer : Flag<["-"], "fno-wrapv-pointer">, Group<f_Group>, Visibility<[ClangOption, CLOption, FlangOption]>; def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 81016d3d5d308..8783b43846434 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5021,6 +5021,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { divisor = CGF.CGM.getSize(elementSize); } + if (CGF.getLangOpts().StablePointerSubtraction) + return Builder.CreateSDiv(diffInChars, divisor, "sub.ptr.div"); // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since // pointer difference in C is only defined in the case where both operands // are pointing to elements of an array. diff --git a/clang/test/CodeGen/ptr-subtract-stable.c b/clang/test/CodeGen/ptr-subtract-stable.c new file mode 100644 index 0000000000000..d18dd16cb4982 --- /dev/null +++ b/clang/test/CodeGen/ptr-subtract-stable.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm -O2 -triple x86_64-windows-msvc -fstable-pointer-subtraction -fms-extensions %s -o - | FileCheck %s + +// Check that pointer subtraction isn't nuw/nsv and sdiv isn't exact +// CHECK-LABEL: i64 @sub(ptr noundef %p, ptr noundef %q) +// CHECK-NEXT: entry: +// CHECK-NEXT: %sub.ptr.lhs.cast = ptrtoint ptr %p to i64 +// CHECK-NEXT: %sub.ptr.rhs.cast = ptrtoint ptr %q to i64 +// CHECK-NEXT: %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast +// CHECK-NEXT: %sub.ptr.div = sdiv i64 %sub.ptr.sub, 4 +// CHECK-NEXT: ret i64 %sub.ptr.div + +__declspec(noinline) long long sub(long* p, long* q) { + return p - q; +} + >From 599d6013112828791ec3a837bb0cb1f7c21fb914 Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Wed, 27 May 2026 13:30:22 +0200 Subject: [PATCH 2/5] Add DocBrief --- clang/include/clang/Options/Options.td | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 37ee6ded12388..76a09b37118db 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4901,6 +4901,12 @@ def fstable_pointer_subtraction : HelpText< "Allow stable subtraction of pointers not aligned to object boundaries" >, + DocBrief< + "When subtracting two pointers, do not assume that the byte difference is an " + "exact multiple of the pointee type size. The computed result is rounded " + "toward zero instead of producing a poison value. Users should prefer casting " + "pointers to ``char *`` before subtracting instead of relying on this flag." + >, MarshallingInfoFlag<LangOpts<"StablePointerSubtraction">>; def fno_wrapv_pointer : Flag<["-"], "fno-wrapv-pointer">, Group<f_Group>, Visibility<[ClangOption, CLOption, FlangOption]>; >From 0d3eb5ec649d61fc02e560bfbdca37edf084b09e Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 2 Jun 2026 13:19:54 +0200 Subject: [PATCH 3/5] Added documentation --- clang/docs/UsersManual.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clang/docs/UsersManual.md b/clang/docs/UsersManual.md index 756f2784dc076..d01ccfb9a784b 100644 --- a/clang/docs/UsersManual.md +++ b/clang/docs/UsersManual.md @@ -2972,6 +2972,22 @@ are listed below. ``aligned`` attribute, this option is ignored. ``` +```{eval-rst} +.. option:: -fstable-pointer-subtraction + + The C and C++ standards require both operands of a pointer subtraction to + refer to elements of the same array object. Clang normally exploits this + rule when lowering pointer subtraction operations, for example by emitting + IR constructs such as ``sdiv exact`` that rely on the computed byte offset + being an exact multiple of the pointee size. + + ``-fstable-pointer-subtraction`` disables these assumptions and emits IR + that preserves the behavior of pointer subtraction even when the standard + requirements are violated. This is primarily intended for low-level code, + such as kernels and boot loaders, that performs pointer arithmetic over + externally defined memory layouts rather than ordinary C or C++ objects. +``` + (strict_aliasing)= (strict-aliasing)= >From bca8826654061ae067ec2b10bf0fe59a6aa2971c Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 30 Jun 2026 17:47:31 +0200 Subject: [PATCH 4/5] Add release notes --- clang/docs/ReleaseNotes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 052838ef0af0d..c799fc5a81609 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -113,6 +113,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the ### New Compiler Flags +- New option `-fstable-pointer-subtraction` added to preserve stable semantics + when subtracting pointers to unrelated objects. + ### Deprecated Compiler Flags ### Modified Compiler Flags >From 7a30ba3e4a187c0d104b483dec1c364016271500 Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Thu, 16 Jul 2026 18:34:07 +0200 Subject: [PATCH 5/5] Pass option down to frontend --- clang/lib/Driver/ToolChains/Clang.cpp | 3 +++ clang/test/CodeGen/ptr-subtract-stable.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index bdf72f848aeff..329b5d0f96e45 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5382,6 +5382,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-funified-lto"); } + if (Args.hasArg(options::OPT_fstable_pointer_subtraction)) + CmdArgs.push_back("-fstable-pointer-subtraction"); + // If CollectArgsForIntegratedAssembler() isn't called below, claim the args // it claims when not running an assembler. Otherwise, clang would emit // "argument unused" warnings for assembler flags when e.g. adding "-E" to diff --git a/clang/test/CodeGen/ptr-subtract-stable.c b/clang/test/CodeGen/ptr-subtract-stable.c index d18dd16cb4982..6193e289b12a0 100644 --- a/clang/test/CodeGen/ptr-subtract-stable.c +++ b/clang/test/CodeGen/ptr-subtract-stable.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -O2 -triple x86_64-windows-msvc -fstable-pointer-subtraction -fms-extensions %s -o - | FileCheck %s +// RUN: %clang -S -emit-llvm -O2 --target=x86_64-windows-msvc -fstable-pointer-subtraction -fms-extensions %s -o - | FileCheck %s // Check that pointer subtraction isn't nuw/nsv and sdiv isn't exact // CHECK-LABEL: i64 @sub(ptr noundef %p, ptr noundef %q) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
