1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=indvars -S | FileCheck %s 3; This is a collection of tests specifically for LFTR of multiple exit loops. 4; The actual LFTR performed is trivial so as to focus on the loop structure 5; aspects. 6 7; Provide legal integer types. 8target datalayout = "n8:16:32:64" 9 10@A = external global i32 11 12define void @analyzeable_early_exit(i32 %n) { 13; CHECK-LABEL: @analyzeable_early_exit( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: br label [[LOOP:%.*]] 16; CHECK: loop: 17; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 18; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 19; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 20; CHECK: latch: 21; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 22; CHECK-NEXT: store i32 [[IV]], ptr @A, align 4 23; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 24; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] 25; CHECK: exit: 26; CHECK-NEXT: ret void 27; 28entry: 29 br label %loop 30 31loop: 32 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 33 %earlycnd = icmp ult i32 %iv, %n 34 br i1 %earlycnd, label %latch, label %exit 35 36latch: 37 %iv.next = add i32 %iv, 1 38 store i32 %iv, ptr @A 39 %c = icmp ult i32 %iv.next, 1000 40 br i1 %c, label %loop, label %exit 41 42exit: 43 ret void 44} 45 46define void @unanalyzeable_early_exit() { 47; CHECK-LABEL: @unanalyzeable_early_exit( 48; CHECK-NEXT: entry: 49; CHECK-NEXT: br label [[LOOP:%.*]] 50; CHECK: loop: 51; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 52; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, ptr @A, align 4 53; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0 54; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]] 55; CHECK: latch: 56; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 57; CHECK-NEXT: store i32 [[IV]], ptr @A, align 4 58; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 59; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT]] 60; CHECK: exit: 61; CHECK-NEXT: ret void 62; 63entry: 64 br label %loop 65 66loop: 67 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 68 %vol = load volatile i32, ptr @A 69 %earlycnd = icmp ne i32 %vol, 0 70 br i1 %earlycnd, label %latch, label %exit 71 72latch: 73 %iv.next = add i32 %iv, 1 74 store i32 %iv, ptr @A 75 %c = icmp ult i32 %iv.next, 1000 76 br i1 %c, label %loop, label %exit 77 78exit: 79 ret void 80} 81 82 83define void @multiple_early_exits(i32 %n, i32 %m) { 84; CHECK-LABEL: @multiple_early_exits( 85; CHECK-NEXT: entry: 86; CHECK-NEXT: br label [[LOOP:%.*]] 87; CHECK: loop: 88; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 89; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 90; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] 91; CHECK: continue: 92; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 93; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]] 94; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]] 95; CHECK: latch: 96; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 97; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 98; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 99; CHECK-NEXT: br i1 [[EXITCOND2]], label [[LOOP]], label [[EXIT]] 100; CHECK: exit: 101; CHECK-NEXT: ret void 102; 103entry: 104 br label %loop 105 106loop: 107 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 108 %earlycnd = icmp ult i32 %iv, %n 109 br i1 %earlycnd, label %continue, label %exit 110 111continue: 112 store volatile i32 %iv, ptr @A 113 %earlycnd2 = icmp ult i32 %iv, %m 114 br i1 %earlycnd2, label %latch, label %exit 115 116latch: 117 %iv.next = add i32 %iv, 1 118 store volatile i32 %iv, ptr @A 119 %c = icmp ult i32 %iv.next, 1000 120 br i1 %c, label %loop, label %exit 121 122exit: 123 ret void 124} 125 126; Note: This slightly odd form is what indvars itself produces for multiple 127; exits without a side effect between them. 128define void @compound_early_exit(i32 %n, i32 %m) { 129; CHECK-LABEL: @compound_early_exit( 130; CHECK-NEXT: entry: 131; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[M:%.*]], i32 [[N:%.*]]) 132; CHECK-NEXT: br label [[LOOP:%.*]] 133; CHECK: loop: 134; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 135; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[UMIN]] 136; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 137; CHECK: latch: 138; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 139; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 140; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 141; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] 142; CHECK: exit: 143; CHECK-NEXT: ret void 144; 145entry: 146 br label %loop 147 148loop: 149 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 150 %earlycnd = icmp ult i32 %iv, %n 151 %earlycnd2 = icmp ult i32 %iv, %m 152 %and = and i1 %earlycnd, %earlycnd2 153 br i1 %and, label %latch, label %exit 154 155latch: 156 %iv.next = add i32 %iv, 1 157 store volatile i32 %iv, ptr @A 158 %c = icmp ult i32 %iv.next, 1000 159 br i1 %c, label %loop, label %exit 160 161exit: 162 ret void 163} 164 165 166define void @unanalyzeable_latch(i32 %n) { 167; CHECK-LABEL: @unanalyzeable_latch( 168; CHECK-NEXT: entry: 169; CHECK-NEXT: br label [[LOOP:%.*]] 170; CHECK: loop: 171; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 172; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 173; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 174; CHECK: latch: 175; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 176; CHECK-NEXT: store i32 [[IV]], ptr @A, align 4 177; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, ptr @A, align 4 178; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[VOL]], 1000 179; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] 180; CHECK: exit: 181; CHECK-NEXT: ret void 182; 183entry: 184 br label %loop 185 186loop: 187 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 188 %earlycnd = icmp ult i32 %iv, %n 189 br i1 %earlycnd, label %latch, label %exit 190 191latch: 192 %iv.next = add i32 %iv, 1 193 store i32 %iv, ptr @A 194 %vol = load volatile i32, ptr @A 195 %c = icmp ult i32 %vol, 1000 196 br i1 %c, label %loop, label %exit 197 198exit: 199 ret void 200} 201 202define void @single_exit_no_latch(i32 %n) { 203; CHECK-LABEL: @single_exit_no_latch( 204; CHECK-NEXT: entry: 205; CHECK-NEXT: br label [[LOOP:%.*]] 206; CHECK: loop: 207; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 208; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 209; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 210; CHECK: latch: 211; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 212; CHECK-NEXT: store i32 [[IV]], ptr @A, align 4 213; CHECK-NEXT: br label [[LOOP]] 214; CHECK: exit: 215; CHECK-NEXT: ret void 216; 217entry: 218 br label %loop 219 220loop: 221 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 222 %earlycnd = icmp ult i32 %iv, %n 223 br i1 %earlycnd, label %latch, label %exit 224 225latch: 226 %iv.next = add i32 %iv, 1 227 store i32 %iv, ptr @A 228 br label %loop 229 230exit: 231 ret void 232} 233 234; Multiple exits which could be LFTRed, but the latch itself is not an 235; exiting block. 236define void @no_latch_exit(i32 %n, i32 %m) { 237; CHECK-LABEL: @no_latch_exit( 238; CHECK-NEXT: entry: 239; CHECK-NEXT: br label [[LOOP:%.*]] 240; CHECK: loop: 241; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 242; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 243; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] 244; CHECK: continue: 245; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 246; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]] 247; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]] 248; CHECK: latch: 249; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 250; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 251; CHECK-NEXT: br label [[LOOP]] 252; CHECK: exit: 253; CHECK-NEXT: ret void 254; 255entry: 256 br label %loop 257 258loop: 259 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 260 %earlycnd = icmp ult i32 %iv, %n 261 br i1 %earlycnd, label %continue, label %exit 262 263continue: 264 store volatile i32 %iv, ptr @A 265 %earlycnd2 = icmp ult i32 %iv, %m 266 br i1 %earlycnd2, label %latch, label %exit 267 268latch: 269 store volatile i32 %iv, ptr @A 270 %iv.next = add i32 %iv, 1 271 br label %loop 272 273exit: 274 ret void 275} 276 277;; Show the value of multiple exit LFTR (being able to eliminate all but 278;; one IV when exit tests involve multiple IVs). 279define void @combine_ivs(i32 %n) { 280; CHECK-LABEL: @combine_ivs( 281; CHECK-NEXT: entry: 282; CHECK-NEXT: br label [[LOOP:%.*]] 283; CHECK: loop: 284; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 285; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 286; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 287; CHECK: latch: 288; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 289; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 290; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 999 291; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] 292; CHECK: exit: 293; CHECK-NEXT: ret void 294; 295entry: 296 br label %loop 297 298loop: 299 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 300 %iv2 = phi i32 [ 1, %entry], [ %iv2.next, %latch] 301 %earlycnd = icmp ult i32 %iv, %n 302 br i1 %earlycnd, label %latch, label %exit 303 304latch: 305 %iv.next = add i32 %iv, 1 306 %iv2.next = add i32 %iv2, 1 307 store volatile i32 %iv, ptr @A 308 %c = icmp ult i32 %iv2.next, 1000 309 br i1 %c, label %loop, label %exit 310 311exit: 312 ret void 313} 314 315; We can remove the decrementing IV entirely 316define void @combine_ivs2(i32 %n) { 317; CHECK-LABEL: @combine_ivs2( 318; CHECK-NEXT: entry: 319; CHECK-NEXT: br label [[LOOP:%.*]] 320; CHECK: loop: 321; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 322; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 323; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 324; CHECK: latch: 325; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 326; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 327; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 328; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] 329; CHECK: exit: 330; CHECK-NEXT: ret void 331; 332entry: 333 br label %loop 334 335loop: 336 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 337 %iv2 = phi i32 [ 1000, %entry], [ %iv2.next, %latch] 338 %earlycnd = icmp ult i32 %iv, %n 339 br i1 %earlycnd, label %latch, label %exit 340 341latch: 342 %iv.next = add i32 %iv, 1 343 %iv2.next = sub i32 %iv2, 1 344 store volatile i32 %iv, ptr @A 345 %c = icmp ugt i32 %iv2.next, 0 346 br i1 %c, label %loop, label %exit 347 348exit: 349 ret void 350} 351 352; An example where we can eliminate an f(i) computation entirely 353; from a multiple exit loop with LFTR. 354define void @simplify_exit_test(i32 %n) { 355; CHECK-LABEL: @simplify_exit_test( 356; CHECK-NEXT: entry: 357; CHECK-NEXT: br label [[LOOP:%.*]] 358; CHECK: loop: 359; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 360; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] 361; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] 362; CHECK: latch: 363; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 364; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 365; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 65 366; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] 367; CHECK: exit: 368; CHECK-NEXT: ret void 369; 370entry: 371 br label %loop 372 373loop: 374 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 375 %earlycnd = icmp ult i32 %iv, %n 376 br i1 %earlycnd, label %latch, label %exit 377 378latch: 379 %iv.next = add i32 %iv, 1 380 %fx = shl i32 %iv, 4 381 store volatile i32 %iv, ptr @A 382 %c = icmp ult i32 %fx, 1024 383 br i1 %c, label %loop, label %exit 384 385exit: 386 ret void 387} 388 389 390; Another example where we can remove an f(i) type computation, but this 391; time in a loop w/o a statically computable exit count. 392define void @simplify_exit_test2(i32 %n) { 393; CHECK-LABEL: @simplify_exit_test2( 394; CHECK-NEXT: entry: 395; CHECK-NEXT: br label [[LOOP:%.*]] 396; CHECK: loop: 397; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] 398; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, ptr @A, align 4 399; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0 400; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]] 401; CHECK: latch: 402; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 403; CHECK-NEXT: [[FX:%.*]] = udiv i32 [[IV]], 4 404; CHECK-NEXT: store volatile i32 [[IV]], ptr @A, align 4 405; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[FX]], 1024 406; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] 407; CHECK: exit: 408; CHECK-NEXT: ret void 409; 410entry: 411 br label %loop 412 413loop: 414 %iv = phi i32 [ 0, %entry], [ %iv.next, %latch] 415 %vol = load volatile i32, ptr @A 416 %earlycnd = icmp ne i32 %vol, 0 417 br i1 %earlycnd, label %latch, label %exit 418 419latch: 420 %iv.next = add i32 %iv, 1 421 %fx = udiv i32 %iv, 4 422 store volatile i32 %iv, ptr @A 423 %c = icmp ult i32 %fx, 1024 424 br i1 %c, label %loop, label %exit 425 426exit: 427 ret void 428} 429 430; Demonstrate a case where two nested loops share a single exiting block. 431; The key point is that the exit count is *different* for the two loops, and 432; thus we can't rewrite the exit for the outer one. There are three sub-cases 433; which can happen here: a) the outer loop has a backedge taken count of zero 434; (for the case where we know the inner exit is known taken), b) the exit is 435; known never taken (but may have an exit count outside the range of the IV) 436; or c) the outer loop has an unanalyzable exit count (where we can't tell). 437define void @nested(i32 %n) { 438; CHECK-LABEL: @nested( 439; CHECK-NEXT: entry: 440; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1 441; CHECK-NEXT: br label [[OUTER:%.*]] 442; CHECK: outer: 443; CHECK-NEXT: [[IV1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV1_NEXT:%.*]], [[OUTER_LATCH:%.*]] ] 444; CHECK-NEXT: store volatile i32 [[IV1]], ptr @A, align 4 445; CHECK-NEXT: [[IV1_NEXT]] = add nuw nsw i32 [[IV1]], 1 446; CHECK-NEXT: br label [[INNER:%.*]] 447; CHECK: inner: 448; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[OUTER]] ], [ [[IV2_NEXT:%.*]], [[INNER_LATCH:%.*]] ] 449; CHECK-NEXT: store volatile i32 [[IV2]], ptr @A, align 4 450; CHECK-NEXT: [[IV2_NEXT]] = add nuw nsw i32 [[IV2]], 1 451; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], 20 452; CHECK-NEXT: br i1 [[EXITCOND]], label [[INNER_LATCH]], label [[EXIT_LOOPEXIT:%.*]] 453; CHECK: inner_latch: 454; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV2_NEXT]], [[TMP0]] 455; CHECK-NEXT: br i1 [[EXITCOND2]], label [[INNER]], label [[OUTER_LATCH]] 456; CHECK: outer_latch: 457; CHECK-NEXT: [[EXITCOND3:%.*]] = icmp ne i32 [[IV1_NEXT]], 21 458; CHECK-NEXT: br i1 [[EXITCOND3]], label [[OUTER]], label [[EXIT_LOOPEXIT1:%.*]] 459; CHECK: exit.loopexit: 460; CHECK-NEXT: br label [[EXIT:%.*]] 461; CHECK: exit.loopexit1: 462; CHECK-NEXT: br label [[EXIT]] 463; CHECK: exit: 464; CHECK-NEXT: ret void 465; 466entry: 467 br label %outer 468 469outer: 470 %iv1 = phi i32 [ 0, %entry ], [ %iv1.next, %outer_latch ] 471 store volatile i32 %iv1, ptr @A 472 %iv1.next = add i32 %iv1, 1 473 br label %inner 474 475inner: 476 %iv2 = phi i32 [ 0, %outer ], [ %iv2.next, %inner_latch ] 477 store volatile i32 %iv2, ptr @A 478 %iv2.next = add i32 %iv2, 1 479 %innertest = icmp ult i32 %iv2, 20 480 br i1 %innertest, label %inner_latch, label %exit 481 482inner_latch: 483 %innertestb = icmp ult i32 %iv2, %n 484 br i1 %innertestb, label %inner, label %outer_latch 485 486outer_latch: 487 %outertest = icmp ult i32 %iv1, 20 488 br i1 %outertest, label %outer, label %exit 489 490exit: 491 ret void 492} 493