From ea2e66aa8b6e363b89df66dc44275a0d7ecd70ce Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 12 Mar 2025 09:50:50 -0700 Subject: [PATCH] [LLVM][ConstantFold] Undefined values are not constant (#130713) llvm.is.constant (and therefore Clang's __builtin_constant_p()) need to report undefined values as non-constant or future DCE choices end up making no sense. This was encountered while building the Linux kernel which uses __builtin_constant_p() while trying to evaluate if it is safe to use a compile-time constant resolution for string lengths or if it must kick over to a full runtime call to strlen(). Obviously an undefined variable cannot be known at compile-time, so __builtin_constant_p() needs to return false. This change will also mean that Clang will match GCC's behavior under the same conditions. Fixes #130649 --- llvm/lib/IR/Constants.cpp | 2 ++ .../constant-intrinsics.ll | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index 9e3e739fae3d..36f413645761 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -841,6 +841,8 @@ Constant *Constant::mergeUndefsWith(Constant *C, Constant *Other) { } bool Constant::isManifestConstant() const { + if (isa(this)) + return false; if (isa(this)) return true; if (isa(this) || isa(this)) { diff --git a/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll b/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll index 32bd2fff2732..2801c3d2a977 100644 --- a/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll +++ b/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll @@ -120,3 +120,21 @@ define i1 @global_array() { %1 = call i1 @llvm.is.constant.i64(i64 ptrtoint (ptr @real_mode_blob_end to i64)) ret i1 %1 } + +;; Ensure that is.constant of undef gets lowered reasonably to "false" in +;; optimized codegen: specifically that the "true" branch is eliminated. +;; CHECK-NOT: tail call i32 @subfun_1() +;; CHECK: tail call i32 @subfun_2() +;; CHECK-NOT: tail call i32 @subfun_1() +define i32 @test_undef_branch() nounwind { + %v = call i1 @llvm.is.constant.i32(i32 undef) + br i1 %v, label %True, label %False + +True: + %call1 = tail call i32 @subfun_1() + ret i32 %call1 + +False: + %call2 = tail call i32 @subfun_2() + ret i32 %call2 +}