[clang] d425720 - [clang][Interp] Implement __builtin_strlen
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 17 04:11:04 PDT 2023
Author: Timm Bäder
Date: 2023-08-17T13:10:46+02:00
New Revision: d425720aed48fd2c058a126ac961576d48c9732b
URL: https://github.com/llvm/llvm-project/commit/d425720aed48fd2c058a126ac961576d48c9732b
DIFF: https://github.com/llvm/llvm-project/commit/d425720aed48fd2c058a126ac961576d48c9732b.diff
LOG: [clang][Interp] Implement __builtin_strlen
Differential Revision: https://reviews.llvm.org/D156042
Added:
Modified:
clang/lib/AST/Interp/InterpBuiltin.cpp
clang/test/AST/Interp/builtin-functions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index 5702859996dca2..b4e75593dc4a5f 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -56,6 +56,41 @@ static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
llvm_unreachable("Int isn't 16 or 32 bit?");
}
+static void pushSizeT(InterpState &S, uint64_t Val) {
+ const TargetInfo &TI = S.getCtx().getTargetInfo();
+ unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
+
+ switch (SizeTWidth) {
+ case 64:
+ S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val));
+ break;
+ case 32:
+ S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val));
+ break;
+ case 16:
+ S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val));
+ break;
+ default:
+ llvm_unreachable("We don't handle this size_t size.");
+ }
+}
+
+static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
+ const TargetInfo &TI = S.getCtx().getTargetInfo();
+ unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
+
+ switch (SizeTWidth) {
+ case 64:
+ return Ret<PT_Uint64>(S, OpPC, Result);
+ case 32:
+ return Ret<PT_Uint32>(S, OpPC, Result);
+ case 16:
+ return Ret<PT_Uint16>(S, OpPC, Result);
+ }
+
+ llvm_unreachable("size_t isn't 64 or 32 bit?");
+}
+
static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame) {
const Pointer &A = getParam<Pointer>(Frame, 0);
@@ -95,6 +130,34 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame) {
+ const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
+
+ if (!CheckArray(S, OpPC, StrPtr))
+ return false;
+
+ if (!CheckLive(S, OpPC, StrPtr, AK_Read))
+ return false;
+
+ assert(StrPtr.getFieldDesc()->isPrimitiveArray());
+
+ size_t Len = 0;
+ for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
+ const Pointer &ElemPtr = StrPtr.atIndex(I);
+
+ if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
+ return false;
+
+ uint8_t Val = ElemPtr.deref<uint8_t>();
+ if (Val == 0)
+ break;
+ }
+
+ pushSizeT(S, Len);
+ return true;
+}
+
static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *F,
bool Signaling) {
@@ -338,6 +401,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (interp__builtin_strcmp(S, OpPC, Frame))
return retInt(S, OpPC, Dummy);
break;
+ case Builtin::BI__builtin_strlen:
+ if (interp__builtin_strlen(S, OpPC, Frame))
+ return retSizeT(S, OpPC, Dummy);
+ break;
case Builtin::BI__builtin_nan:
case Builtin::BI__builtin_nanf:
case Builtin::BI__builtin_nanl:
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 3fd04759e67996..55ebab1122d58e 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -1,9 +1,11 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
-// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
-// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter %s -verify
-// RUN: %clang_cc1 -std=c++20 -verify=ref %s -Wno-constant-evaluated
-// RUN: %clang_cc1 -triple avr -std=c++20 -fexperimental-new-constant-interpreter %s -verify
-// RUN: %clang_cc1 -triple avr -std=c++20 -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -Wno-string-plus-int -fexperimental-new-constant-interpreter -triple i686 %s -verify
+// RUN: %clang_cc1 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter -triple i686 %s -verify
+// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
namespace strcmp {
@@ -40,6 +42,70 @@ namespace strcmp {
// ref-note {{dereferenced one-past-the-end}}
}
+/// Copied from constant-expression-cxx11.cpp
+namespace strlen {
+constexpr const char *a = "foo\0quux";
+ constexpr char b[] = "foo\0quux";
+ constexpr int f() { return 'u'; }
+ constexpr char c[] = { 'f', 'o', 'o', 0, 'q', f(), 'u', 'x', 0 };
+
+ static_assert(__builtin_strlen("foo") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux" + 4) == 4, "");
+
+ constexpr bool check(const char *p) {
+ return __builtin_strlen(p) == 3 &&
+ __builtin_strlen(p + 1) == 2 &&
+ __builtin_strlen(p + 2) == 1 &&
+ __builtin_strlen(p + 3) == 0 &&
+ __builtin_strlen(p + 4) == 4 &&
+ __builtin_strlen(p + 5) == 3 &&
+ __builtin_strlen(p + 6) == 2 &&
+ __builtin_strlen(p + 7) == 1 &&
+ __builtin_strlen(p + 8) == 0;
+ }
+
+ static_assert(check(a), "");
+ static_assert(check(b), "");
+ static_assert(check(c), "");
+
+ constexpr int over1 = __builtin_strlen(a + 9); // expected-error {{constant expression}} \
+ // expected-note {{one-past-the-end}} \
+ // expected-note {{in call to}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{one-past-the-end}}
+ constexpr int over2 = __builtin_strlen(b + 9); // expected-error {{constant expression}} \
+ // expected-note {{one-past-the-end}} \
+ // expected-note {{in call to}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{one-past-the-end}}
+ constexpr int over3 = __builtin_strlen(c + 9); // expected-error {{constant expression}} \
+ // expected-note {{one-past-the-end}} \
+ // expected-note {{in call to}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{one-past-the-end}}
+
+ constexpr int under1 = __builtin_strlen(a - 1); // expected-error {{constant expression}} \
+ // expected-note {{cannot refer to element -1}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{cannot refer to element -1}}
+ constexpr int under2 = __builtin_strlen(b - 1); // expected-error {{constant expression}} \
+ // expected-note {{cannot refer to element -1}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{cannot refer to element -1}}
+ constexpr int under3 = __builtin_strlen(c - 1); // expected-error {{constant expression}} \
+ // expected-note {{cannot refer to element -1}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{cannot refer to element -1}}
+
+ constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
+ constexpr int bad = __builtin_strlen(d); // expected-error {{constant expression}} \
+ // expected-note {{one-past-the-end}} \
+ // expected-note {{in call to}} \
+ // ref-error {{constant expression}} \
+ // ref-note {{one-past-the-end}}
+}
+
namespace nan {
constexpr double NaN1 = __builtin_nan("");
More information about the cfe-commits
mailing list