@@ -3091,7 +3091,7 @@ template struct m::wasm::buffer_swap_proxy_t<true>;
3091
3091
* string comparison
3092
3092
*====================================================================================================================*/
3093
3093
3094
- _I32x1 m::wasm::strncmp (NChar _left, NChar _right, U32x1 len)
3094
+ _I32x1 m::wasm::strncmp (NChar _left, NChar _right, U32x1 len, bool reverse )
3095
3095
{
3096
3096
static thread_local struct {} _; // unique caller handle
3097
3097
struct data_t : GarbageCollectedData
@@ -3105,7 +3105,7 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
3105
3105
};
3106
3106
auto &d = Module::Get ().add_garbage_collected_data <data_t >(&_); // garbage collect the `data_t` instance
3107
3107
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 {
3109
3109
Wasm_insist (left.clone ().not_null (), " left operand must not be NULL" );
3110
3110
Wasm_insist (right.clone ().not_null (), " right operand must not be NULL" );
3111
3111
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)
3116
3116
auto left_gt_right = *left.clone () > *right.clone ();
3117
3117
return left_gt_right.to <int32_t >() - (*left < *right).to <int32_t >();
3118
3118
} 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
3120
3120
if (not d.strncmp_terminating_nul ) {
3121
3121
/* ----- Create function to compute the result for non-nullptr arguments character-wise. -----*/
3122
3122
FUNCTION (strncmp_terminating_nul, data_t ::fn_t )
@@ -3170,16 +3170,41 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
3170
3170
3171
3171
const auto len_ty_left = PARAMETER (0 );
3172
3172
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 ) );
3175
3175
const auto len = PARAMETER (4 );
3176
3176
3177
3177
Var<I32x1> result; // always set here
3178
3178
3179
3179
I32x1 len_left = Select (len < len_ty_left, len, len_ty_left) .make_signed ();
3180
3180
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
+ }
3183
3208
3184
3209
LOOP () {
3185
3210
/* 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)
3202
3227
BREAK (val_left == 0 ); // reached end of identical strings
3203
3228
3204
3229
/* Advance to next character. */
3205
- left += 1 ;
3206
- right += 1 ;
3230
+ left += reverse ? - 1 : 1 ;
3231
+ right += reverse ? - 1 : 1 ;
3207
3232
CONTINUE ();
3208
3233
}
3209
3234
@@ -3234,17 +3259,17 @@ _I32x1 m::wasm::strncmp(NChar _left, NChar _right, U32x1 len)
3234
3259
}
3235
3260
}
3236
3261
3237
- _I32x1 m::wasm::strcmp (NChar left, NChar right)
3262
+ _I32x1 m::wasm::strcmp (NChar left, NChar right, bool reverse )
3238
3263
{
3239
3264
/* Delegate to `strncmp` with length set to minimum of both string lengths **plus** 1 since we need to check if
3240
3265
* one string is a prefix of the other, i.e. all of its characters are equal but it is shorter than the other. */
3241
3266
U32x1 len (std::min<uint32_t >(left.length (), right.length ()) + 1U );
3242
- return strncmp (left, right, len);
3267
+ return strncmp (left, right, len, reverse );
3243
3268
}
3244
3269
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 )
3246
3271
{
3247
- _I32x1 res = strncmp (left, right, len);
3272
+ _I32x1 res = strncmp (left, right, len, reverse );
3248
3273
3249
3274
switch (op) {
3250
3275
case EQ: return res == 0 ;
@@ -3256,9 +3281,9 @@ _Boolx1 m::wasm::strncmp(NChar left, NChar right, U32x1 len, cmp_op op)
3256
3281
}
3257
3282
}
3258
3283
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 )
3260
3285
{
3261
- _I32x1 res = strcmp (left, right);
3286
+ _I32x1 res = strcmp (left, right, reverse );
3262
3287
3263
3288
switch (op) {
3264
3289
case EQ: return res == 0 ;
0 commit comments