Skip to content

Commit d425720

Browse files
committed
[clang][Interp] Implement __builtin_strlen
Differential Revision: https://reviews.llvm.org/D156042
1 parent 1740cf3 commit d425720

File tree

2 files changed

+139
-6
lines changed

2 files changed

+139
-6
lines changed

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,41 @@ static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
5656
llvm_unreachable("Int isn't 16 or 32 bit?");
5757
}
5858

59+
static void pushSizeT(InterpState &S, uint64_t Val) {
60+
const TargetInfo &TI = S.getCtx().getTargetInfo();
61+
unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
62+
63+
switch (SizeTWidth) {
64+
case 64:
65+
S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val));
66+
break;
67+
case 32:
68+
S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val));
69+
break;
70+
case 16:
71+
S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val));
72+
break;
73+
default:
74+
llvm_unreachable("We don't handle this size_t size.");
75+
}
76+
}
77+
78+
static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
79+
const TargetInfo &TI = S.getCtx().getTargetInfo();
80+
unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
81+
82+
switch (SizeTWidth) {
83+
case 64:
84+
return Ret<PT_Uint64>(S, OpPC, Result);
85+
case 32:
86+
return Ret<PT_Uint32>(S, OpPC, Result);
87+
case 16:
88+
return Ret<PT_Uint16>(S, OpPC, Result);
89+
}
90+
91+
llvm_unreachable("size_t isn't 64 or 32 bit?");
92+
}
93+
5994
static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
6095
const InterpFrame *Frame) {
6196
const Pointer &A = getParam<Pointer>(Frame, 0);
@@ -95,6 +130,34 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
95130
return true;
96131
}
97132

133+
static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
134+
const InterpFrame *Frame) {
135+
const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
136+
137+
if (!CheckArray(S, OpPC, StrPtr))
138+
return false;
139+
140+
if (!CheckLive(S, OpPC, StrPtr, AK_Read))
141+
return false;
142+
143+
assert(StrPtr.getFieldDesc()->isPrimitiveArray());
144+
145+
size_t Len = 0;
146+
for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
147+
const Pointer &ElemPtr = StrPtr.atIndex(I);
148+
149+
if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
150+
return false;
151+
152+
uint8_t Val = ElemPtr.deref<uint8_t>();
153+
if (Val == 0)
154+
break;
155+
}
156+
157+
pushSizeT(S, Len);
158+
return true;
159+
}
160+
98161
static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
99162
const InterpFrame *Frame, const Function *F,
100163
bool Signaling) {
@@ -338,6 +401,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
338401
if (interp__builtin_strcmp(S, OpPC, Frame))
339402
return retInt(S, OpPC, Dummy);
340403
break;
404+
case Builtin::BI__builtin_strlen:
405+
if (interp__builtin_strlen(S, OpPC, Frame))
406+
return retSizeT(S, OpPC, Dummy);
407+
break;
341408
case Builtin::BI__builtin_nan:
342409
case Builtin::BI__builtin_nanf:
343410
case Builtin::BI__builtin_nanl:

clang/test/AST/Interp/builtin-functions.cpp

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
2-
// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
3-
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter %s -verify
4-
// RUN: %clang_cc1 -std=c++20 -verify=ref %s -Wno-constant-evaluated
5-
// RUN: %clang_cc1 -triple avr -std=c++20 -fexperimental-new-constant-interpreter %s -verify
6-
// RUN: %clang_cc1 -triple avr -std=c++20 -verify=ref %s -Wno-constant-evaluated
1+
// RUN: %clang_cc1 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
2+
// RUN: %clang_cc1 -Wno-string-plus-int -fexperimental-new-constant-interpreter -triple i686 %s -verify
3+
// RUN: %clang_cc1 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
4+
// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
5+
// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter -triple i686 %s -verify
6+
// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
7+
// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify
8+
// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated
79

810

911
namespace strcmp {
@@ -40,6 +42,70 @@ namespace strcmp {
4042
// ref-note {{dereferenced one-past-the-end}}
4143
}
4244

45+
/// Copied from constant-expression-cxx11.cpp
46+
namespace strlen {
47+
constexpr const char *a = "foo\0quux";
48+
constexpr char b[] = "foo\0quux";
49+
constexpr int f() { return 'u'; }
50+
constexpr char c[] = { 'f', 'o', 'o', 0, 'q', f(), 'u', 'x', 0 };
51+
52+
static_assert(__builtin_strlen("foo") == 3, "");
53+
static_assert(__builtin_strlen("foo\0quux") == 3, "");
54+
static_assert(__builtin_strlen("foo\0quux" + 4) == 4, "");
55+
56+
constexpr bool check(const char *p) {
57+
return __builtin_strlen(p) == 3 &&
58+
__builtin_strlen(p + 1) == 2 &&
59+
__builtin_strlen(p + 2) == 1 &&
60+
__builtin_strlen(p + 3) == 0 &&
61+
__builtin_strlen(p + 4) == 4 &&
62+
__builtin_strlen(p + 5) == 3 &&
63+
__builtin_strlen(p + 6) == 2 &&
64+
__builtin_strlen(p + 7) == 1 &&
65+
__builtin_strlen(p + 8) == 0;
66+
}
67+
68+
static_assert(check(a), "");
69+
static_assert(check(b), "");
70+
static_assert(check(c), "");
71+
72+
constexpr int over1 = __builtin_strlen(a + 9); // expected-error {{constant expression}} \
73+
// expected-note {{one-past-the-end}} \
74+
// expected-note {{in call to}} \
75+
// ref-error {{constant expression}} \
76+
// ref-note {{one-past-the-end}}
77+
constexpr int over2 = __builtin_strlen(b + 9); // expected-error {{constant expression}} \
78+
// expected-note {{one-past-the-end}} \
79+
// expected-note {{in call to}} \
80+
// ref-error {{constant expression}} \
81+
// ref-note {{one-past-the-end}}
82+
constexpr int over3 = __builtin_strlen(c + 9); // expected-error {{constant expression}} \
83+
// expected-note {{one-past-the-end}} \
84+
// expected-note {{in call to}} \
85+
// ref-error {{constant expression}} \
86+
// ref-note {{one-past-the-end}}
87+
88+
constexpr int under1 = __builtin_strlen(a - 1); // expected-error {{constant expression}} \
89+
// expected-note {{cannot refer to element -1}} \
90+
// ref-error {{constant expression}} \
91+
// ref-note {{cannot refer to element -1}}
92+
constexpr int under2 = __builtin_strlen(b - 1); // expected-error {{constant expression}} \
93+
// expected-note {{cannot refer to element -1}} \
94+
// ref-error {{constant expression}} \
95+
// ref-note {{cannot refer to element -1}}
96+
constexpr int under3 = __builtin_strlen(c - 1); // expected-error {{constant expression}} \
97+
// expected-note {{cannot refer to element -1}} \
98+
// ref-error {{constant expression}} \
99+
// ref-note {{cannot refer to element -1}}
100+
101+
constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
102+
constexpr int bad = __builtin_strlen(d); // expected-error {{constant expression}} \
103+
// expected-note {{one-past-the-end}} \
104+
// expected-note {{in call to}} \
105+
// ref-error {{constant expression}} \
106+
// ref-note {{one-past-the-end}}
107+
}
108+
43109
namespace nan {
44110
constexpr double NaN1 = __builtin_nan("");
45111

0 commit comments

Comments
 (0)