Skip to content

Commit bc4d48c

Browse files
committed
[Wasm] Extend strncmp() functions by flag to indicate reversed iteration.
1 parent bbd7c89 commit bc4d48c

File tree

3 files changed

+52
-19
lines changed

3 files changed

+52
-19
lines changed

src/backend/WasmDSL.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5514,6 +5514,14 @@ struct Variable<T, Kind, CanBeNull, L>
55145514
#endif
55155515

55165516
public:
5517+
friend void swap(Variable &first, Variable &second) {
5518+
using std::swap;
5519+
swap(first.storage_, second.storage_);
5520+
#ifdef M_ENABLE_SANITY_FIELDS
5521+
swap(first.used_, second.used_);
5522+
#endif
5523+
}
5524+
55175525
/** Default-constructs a new `Variable`. */
55185526
Variable() = default;
55195527

src/backend/WasmUtil.cpp

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,7 +3091,7 @@ template struct m::wasm::buffer_swap_proxy_t<true>;
30913091
* string comparison
30923092
*====================================================================================================================*/
30933093

3094-
_I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
3094+
_I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len, bool reverse)
30953095
{
30963096
static thread_local struct {} _; // unique caller handle
30973097
struct data_t : GarbageCollectedData
@@ -3105,7 +3105,7 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
31053105
};
31063106
auto &d = Module::Get().add_garbage_collected_data<data_t>(&_); // garbage collect the `data_t` instance
31073107

3108-
auto strncmp_non_null = [&d, &_left, &_right](Ptr<Charx1> left, Ptr<Charx1> right, U32x1 len) -> I32x1 {
3108+
auto strncmp_non_null = [&d, &_left, &_right, &reverse](Ptr<Charx1> left, Ptr<Charx1> right, U32x1 len) -> I32x1 {
31093109
Wasm_insist(left.clone().not_null(), "left operand must not be NULL");
31103110
Wasm_insist(right.clone().not_null(), "right operand must not be NULL");
31113111
Wasm_insist(len.clone() != 0U, "length to compare must not be 0");
@@ -3116,7 +3116,7 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
31163116
auto left_gt_right = *left.clone() > *right.clone();
31173117
return left_gt_right.to<int32_t>() - (*left < *right).to<int32_t>();
31183118
} else {
3119-
if (_left.guarantees_terminating_nul() and _right.guarantees_terminating_nul()) {
3119+
if (_left.guarantees_terminating_nul() and _right.guarantees_terminating_nul() and not reverse) { // reverse needs in-bounds checks
31203120
if (not d.strncmp_terminating_nul) {
31213121
/*----- Create function to compute the result for non-nullptr arguments character-wise. -----*/
31223122
FUNCTION(strncmp_terminating_nul, data_t::fn_t)
@@ -3170,16 +3170,41 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
31703170

31713171
const auto len_ty_left = PARAMETER(0);
31723172
const auto len_ty_right = PARAMETER(1);
3173-
auto left = PARAMETER(2);
3174-
auto right = PARAMETER(3);
3173+
Var<Ptr<Charx1>> left(PARAMETER(2));
3174+
Var<Ptr<Charx1>> right(PARAMETER(3));
31753175
const auto len = PARAMETER(4);
31763176

31773177
Var<I32x1> result; // always set here
31783178

31793179
I32x1 len_left = Select(len < len_ty_left, len, len_ty_left) .make_signed();
31803180
I32x1 len_right = Select(len < len_ty_right, len, len_ty_right).make_signed();
3181-
Var<Ptr<Charx1>> end_left (left + len_left);
3182-
Var<Ptr<Charx1>> end_right(right + len_right);
3181+
Var<Ptr<Charx1>> end_left, end_right;
3182+
3183+
if (not reverse) {
3184+
/* Set end variables according to theoretical length. */
3185+
end_left = left + len_left;
3186+
end_right = right + len_right;
3187+
} else {
3188+
/* Set end variables to first found NUL byte without exceeding the theoretical length. */
3189+
end_left = left;
3190+
WHILE(*end_left != 0 and end_left != left + len_left) {
3191+
end_left += 1;
3192+
}
3193+
end_right = right;
3194+
WHILE(*end_right != 0 and end_right != right + len_right) {
3195+
end_right += 1;
3196+
}
3197+
3198+
/* Swap variable for current position with the one for end position to iterate reversed. */
3199+
swap(left, end_left);
3200+
swap(right, end_right);
3201+
3202+
/* Resolve off-by-one errors created by swapping variables. */
3203+
left -= 1;
3204+
right -= 1;
3205+
end_left -= 1;
3206+
end_right -= 1;
3207+
}
31833208

31843209
LOOP() {
31853210
/* Check whether one side is shorter than the other. Load next character with in-bounds
@@ -3202,8 +3227,8 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
32023227
BREAK(val_left == 0); // reached end of identical strings
32033228

32043229
/* Advance to next character. */
3205-
left += 1;
3206-
right += 1;
3230+
left += reverse ? -1 : 1;
3231+
right += reverse ? -1 : 1;
32073232
CONTINUE();
32083233
}
32093234

@@ -3234,17 +3259,17 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
32343259
}
32353260
}
32363261

3237-
_I32x1 m::wasm::strcmp(NChar left, NChar right)
3262+
_I32x1 m::wasm::strcmp(NChar left, NChar right, bool reverse)
32383263
{
32393264
/* Delegate to `strncmp` with length set to minimum of both string lengths **plus** 1 since we need to check if
32403265
* one string is a prefix of the other, i.e. all of its characters are equal but it is shorter than the other. */
32413266
U32x1 len(std::min<uint32_t>(left.length(), right.length()) + 1U);
3242-
return strncmp(left, right, len);
3267+
return strncmp(left, right, len, reverse);
32433268
}
32443269

3245-
_Boolx1 m::wasm::strncmp(NChar left, NChar right, U32x1 len, cmp_op op)
3270+
_Boolx1 m::wasm::strncmp(NChar left, NChar right, U32x1 len, cmp_op op, bool reverse)
32463271
{
3247-
_I32x1 res = strncmp(left, right, len);
3272+
_I32x1 res = strncmp(left, right, len, reverse);
32483273

32493274
switch (op) {
32503275
case EQ: return res == 0;
@@ -3256,9 +3281,9 @@ _Boolx1 m::wasm::strncmp(NChar left, NChar right, U32x1 len, cmp_op op)
32563281
}
32573282
}
32583283

3259-
_Boolx1 m::wasm::strcmp(NChar left, NChar right, cmp_op op)
3284+
_Boolx1 m::wasm::strcmp(NChar left, NChar right, cmp_op op, bool reverse)
32603285
{
3261-
_I32x1 res = strcmp(left, right);
3286+
_I32x1 res = strcmp(left, right, reverse);
32623287

32633288
switch (op) {
32643289
case EQ: return res == 0;

src/backend/WasmUtil.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,13 +1326,13 @@ enum cmp_op
13261326
};
13271327

13281328
/** Compares two strings \p left and \p right. Has similar semantics to `strncmp` of libc. */
1329-
_I32x1 strncmp(NChar left, NChar right, U32x1 len);
1329+
_I32x1 strncmp(NChar left, NChar right, U32x1 len, bool reverse = false);
13301330
/** Compares two strings \p left and \p right. Has similar semantics to `strcmp` of libc. */
1331-
_I32x1 strcmp(NChar left, NChar right);
1331+
_I32x1 strcmp(NChar left, NChar right, bool reverse = false);
13321332
/** Compares two strings \p left and \p right. Has similar semantics to `strncmp` of libc. */
1333-
_Boolx1 strncmp(NChar left, NChar right, U32x1 len, cmp_op op);
1333+
_Boolx1 strncmp(NChar left, NChar right, U32x1 len, cmp_op op, bool reverse = false);
13341334
/** Compares two strings \p left and \p right. Has similar semantics to `strcmp` of libc. */
1335-
_Boolx1 strcmp(NChar left, NChar right, cmp_op op);
1335+
_Boolx1 strcmp(NChar left, NChar right, cmp_op op, bool reverse = false);
13361336

13371337

13381338
/*======================================================================================================================

0 commit comments

Comments
 (0)