[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