1// Auto-generated file. Do not edit! 2// Template: src/qs8-gemm/4x8-aarch32-neon-mlal-lane-cortex-a53.S.in 3// Generator: tools/xngen 4// 5// Copyright 2021 Google LLC 6// 7// This source code is licensed under the BSD-style license found in the 8// LICENSE file in the root directory of this source tree. 9 10 11#include <xnnpack/assembly.h> 12 13.syntax unified 14 15// void xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a53( 16// size_t mr, r0 17// size_t nc, r1 18// size_t kc, (r2) -> sp + 56 -> r5 19// const uint8_t*restrict a, r3 20// size_t a_stride, sp + 96 -> (r7) 21// const void*restrict w, sp + 100 -> r9 22// uint8_t*restrict c, sp + 104 -> r11 23// size_t cm_stride, sp + 108 -> (r6) 24// size_t cn_stride, sp + 112 -> r7 25// xnn_qs8_conv_minmax_params params) sp + 116 -> (r5) 26 27// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 28 29// Register usage 30// A0 r3 d0-d1 q0 31// A1 r12 d2-d3 q1 32// A2 r10 d4-d5 q2 33// A3 r0 d6-d7 q3 34 35// B r9 d8-d9 q4 q5 36 37// C0 r11 d16-d17 q8 d18-d19 q9 38// C1 r4 d20-d21 q10 d22-d23 q11 39// C2 r8 d24-d25 q12 d26-d27 q13 40// C3 r6 d28-d29 q14 d30-d31 q15 41 42// r2,r14 A53 gpr temporary loads 43// Unused d15 44 45# params structure is 20 bytes 46# struct { 47# uint8_t kernel_zero_point[4]; d14 48# int32_t right_pre_shift; d12[0] 49# int32_t multiplier; d12[1] 50# int32_t right_post_shift; d13[0] 51# int16_t output_zero_point; d13[2] 52# uint8_t output_min; d13[6] 53# uint8_t output_max; d13[7] 54# } rndnu_neon; 55 56BEGIN_FUNCTION xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a53 57 # Push 96 bytes 58 PUSH {r2, r4, r5, r6, r7, r8, r9, r10, r11, lr} // 40 59 VPUSH {d8-d14} // +56 = 96 60 61 LDR r7, [sp, 96] // a_stride 62 LDR r11, [sp, 104] // c 63 LDR r6, [sp, 108] // cm_stride 64 LDR r9, [sp, 100] // w 65 LDR r5, [sp, 116] // params 66 67 # Clamp A and C pointers 68 CMP r0, 2 // if mr >= 2 69 ADD r12, r3, r7 // a1 = a0 + a_stride 70 ADD r4, r11, r6 // c1 = c0 + cm_stride 71 MOVLO r12, r3 // a1 72 MOVLO r4, r11 // c1 73 // if mr > 2 74 ADD r10, r12, r7 // a2 = a1 + a_stride 75 ADD r8, r4, r6 // c2 = c1 + cm_stride 76 MOVLS r10, r12 // a2 77 MOVLS r8, r4 // c2 78 79 CMP r0, 4 // if mr >=4 80 ADD r0, r10, r7 // a3 = a2 + a_stride 81 ADD r6, r8, r6 // c3 = c2 + cm_stride 82 MOVLO r0, r10 // a3 83 MOVLO r6, r8 // c3 84 85 # Load params values 86 VLD1.32 {d14[]}, [r5]! // QU8 kernel_zero_point 87 VLDM r5, {d12-d13} // RNDNU params 88 LDR r7, [sp, 112] // cn_stride 89 90 91 .p2align 3 920: 93 # Load initial bias from w into accumulators 94 VLDM r9!, {d16-d19} // Bias 95 SUBS r5, r2, 8 // k = kc - 8 96 97 VMOV q10, q8 98 VMOV q11, q9 99 VMOV q12, q8 100 VMOV q13, q9 101 VMOV q14, q8 102 VMOV q15, q9 103 BLO 4f // less than 8 channels? 104 105 // Prologue - load 4A's and B0 106 VLD1.8 {d0}, [r3]! // A0 107 VLD1.8 {d2}, [r12]! // A1 108 VLD1.8 {d4}, [r10]! // A2 109 VLD1.8 {d6}, [r0]! // A3 110 VLD1.8 {d8}, [r9]! // B0 111 112 SUBS r5, r5, 8 // k = k - 8 113 BLO 2f // less than 8 channels? 114 115 // Main loop - 8 bytes 116 // 64 bytes for weights. 117 // 5 VMOVL = 4 A and 1 B = 5 cycles 118 // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles 119 // 1 blocks with VLD B, VMLA = 9 cycles 120 // total = 84 cycles 121 .p2align 3 1221: 123 // Extend - 5 cycles 124 VMOVL.U8 q0, d0 125 VSUBL.U8 q4, d8, d14 126 VMOVL.U8 q1, d2 127 VMOVL.U8 q2, d4 128 VMOVL.U8 q3, d6 129 130 // BLOCK 0 - 10 cycles 131 VLD1.8 {d10}, [r9]! // B1 132 VMLAL.S16 q8, d8, d0[0] 133 VMLAL.S16 q9, d9, d0[0] 134 VMLAL.S16 q10, d8, d2[0] 135 VMLAL.S16 q11, d9, d2[0] 136 VSUBL.U8 q5, d10, d14 137 VMLAL.S16 q12, d8, d4[0] 138 VMLAL.S16 q13, d9, d4[0] 139 VMLAL.S16 q14, d8, d6[0] 140 VMLAL.S16 q15, d9, d6[0] 141 142 // BLOCK 1 - 10 cycles 143 VLD1.8 {d8}, [r9]! // B2 144 VMLAL.S16 q8, d10, d0[1] 145 VMLAL.S16 q9, d11, d0[1] 146 VMLAL.S16 q10, d10, d2[1] 147 VMLAL.S16 q11, d11, d2[1] 148 VSUBL.U8 q4, d8, d14 149 VMLAL.S16 q12, d10, d4[1] 150 VMLAL.S16 q13, d11, d4[1] 151 VMLAL.S16 q14, d10, d6[1] 152 VMLAL.S16 q15, d11, d6[1] 153 154 // BLOCK 2 - 10 cycles 155 VLD1.8 {d10}, [r9]! // B3 156 VMLAL.S16 q8, d8, d0[2] 157 VMLAL.S16 q9, d9, d0[2] 158 VMLAL.S16 q10, d8, d2[2] 159 VMLAL.S16 q11, d9, d2[2] 160 VSUBL.U8 q5, d10, d14 161 VMLAL.S16 q12, d8, d4[2] 162 VMLAL.S16 q13, d9, d4[2] 163 VMLAL.S16 q14, d8, d6[2] 164 VMLAL.S16 q15, d9, d6[2] 165 166 // BLOCK 3 - 10 cycles 167 VLD1.8 {d8}, [r9]! // B4 168 VMLAL.S16 q8, d10, d0[3] 169 VMLAL.S16 q9, d11, d0[3] 170 VMLAL.S16 q10, d10, d2[3] 171 VMLAL.S16 q11, d11, d2[3] 172 VSUBL.U8 q4, d8, d14 173 VMLAL.S16 q12, d10, d4[3] 174 LDR r2, [r3] // A0 low 175 VMLAL.S16 q13, d11, d4[3] 176 LDR r14, [r3, 4] // A0 high 177 VMLAL.S16 q14, d10, d6[3] 178 ADD r3, r3, 8 179 VMLAL.S16 q15, d11, d6[3] 180 181 // BLOCK 4 - 10 cycles 182 VLD1.8 {d10}, [r9]! // B5 183 VMOV d0, r2, r14 // A0 VMOV 184 VMLAL.S16 q8, d8, d1[0] 185 VMLAL.S16 q9, d9, d1[0] 186 VMLAL.S16 q10, d8, d3[0] 187 VMLAL.S16 q11, d9, d3[0] 188 VSUBL.U8 q5, d10, d14 189 VMLAL.S16 q12, d8, d5[0] 190 LDR r2, [r12] // A1 low 191 VMLAL.S16 q13, d9, d5[0] 192 LDR r14, [r12, 4] // A1 high 193 VMLAL.S16 q14, d8, d7[0] 194 ADD r12, r12, 8 195 VMLAL.S16 q15, d9, d7[0] 196 197 // BLOCK 5 - 10 cycles 198 VLD1.8 {d8}, [r9]! // B6 199 VMOV d2, r2, r14 // A1 VMOV 200 VMLAL.S16 q8, d10, d1[1] 201 VMLAL.S16 q9, d11, d1[1] 202 VMLAL.S16 q10, d10, d3[1] 203 VMLAL.S16 q11, d11, d3[1] 204 VSUBL.U8 q4, d8, d14 205 VMLAL.S16 q12, d10, d5[1] 206 LDR r2, [r10] // A2 low 207 VMLAL.S16 q13, d11, d5[1] 208 LDR r14, [r10, 4] // A2 high 209 VMLAL.S16 q14, d10, d7[1] 210 ADD r10, r10, 8 211 VMLAL.S16 q15, d11, d7[1] 212 213 // BLOCK 6 - 10 cycles 214 VLD1.8 {d10}, [r9]! // B7 215 VMOV d4, r2, r14 // A2 VMOV 216 VMLAL.S16 q8, d8, d1[2] 217 VMLAL.S16 q9, d9, d1[2] 218 VMLAL.S16 q10, d8, d3[2] 219 VMLAL.S16 q11, d9, d3[2] 220 VSUBL.U8 q5, d10, d14 221 VMLAL.S16 q12, d8, d5[2] 222 LDR r2, [r0] // A3 low 223 VMLAL.S16 q13, d9, d5[2] 224 LDR r14, [r0, 4] // A3 high 225 VMLAL.S16 q14, d8, d7[2] 226 ADD r0, r0, 8 227 VMLAL.S16 q15, d9, d7[2] 228 229 // BLOCK 7 - 9 cycles 230 VLD1.8 {d8}, [r9]! // B0 231 VMOV d6, r2, r14 // A3 VMOV 232 VMLAL.S16 q8, d10, d1[3] 233 VMLAL.S16 q9, d11, d1[3] 234 VMLAL.S16 q10, d10, d3[3] 235 VMLAL.S16 q11, d11, d3[3] 236 VMLAL.S16 q12, d10, d5[3] 237 VMLAL.S16 q13, d11, d5[3] 238 SUBS r5, r5, 8 239 VMLAL.S16 q14, d10, d7[3] 240 VMLAL.S16 q15, d11, d7[3] 241 BHS 1b 242 243 // Epilogue 244 245 .p2align 3 2462: 247 VMOVL.U8 q0, d0 248 VSUBL.U8 q4, d8, d14 249 VMOVL.U8 q1, d2 250 VMOVL.U8 q2, d4 251 VMOVL.U8 q3, d6 252 253 VLD1.8 {d10}, [r9]! // B1 254 VMLAL.S16 q8, d8, d0[0] 255 VMLAL.S16 q9, d9, d0[0] 256 VMLAL.S16 q10, d8, d2[0] 257 VMLAL.S16 q11, d9, d2[0] 258 VSUBL.U8 q5, d10, d14 259 VMLAL.S16 q12, d8, d4[0] 260 VMLAL.S16 q13, d9, d4[0] 261 VMLAL.S16 q14, d8, d6[0] 262 VMLAL.S16 q15, d9, d6[0] 263 264 VLD1.8 {d8}, [r9]! // B2 265 VMLAL.S16 q8, d10, d0[1] 266 VMLAL.S16 q9, d11, d0[1] 267 VMLAL.S16 q10, d10, d2[1] 268 VMLAL.S16 q11, d11, d2[1] 269 VSUBL.U8 q4, d8, d14 270 VMLAL.S16 q12, d10, d4[1] 271 VMLAL.S16 q13, d11, d4[1] 272 VMLAL.S16 q14, d10, d6[1] 273 VMLAL.S16 q15, d11, d6[1] 274 275 VLD1.8 {d10}, [r9]! // B3 276 VMLAL.S16 q8, d8, d0[2] 277 VMLAL.S16 q9, d9, d0[2] 278 VMLAL.S16 q10, d8, d2[2] 279 VMLAL.S16 q11, d9, d2[2] 280 VSUBL.U8 q5, d10, d14 281 VMLAL.S16 q12, d8, d4[2] 282 VMLAL.S16 q13, d9, d4[2] 283 VMLAL.S16 q14, d8, d6[2] 284 VMLAL.S16 q15, d9, d6[2] 285 286 VLD1.8 {d8}, [r9]! // B4 287 VMLAL.S16 q8, d10, d0[3] 288 VMLAL.S16 q9, d11, d0[3] 289 VMLAL.S16 q10, d10, d2[3] 290 VMLAL.S16 q11, d11, d2[3] 291 VSUBL.U8 q4, d8, d14 292 VMLAL.S16 q12, d10, d4[3] 293 VMLAL.S16 q13, d11, d4[3] 294 VMLAL.S16 q14, d10, d6[3] 295 VMLAL.S16 q15, d11, d6[3] 296 297 VLD1.8 {d10}, [r9]! // B5 298 VMLAL.S16 q8, d8, d1[0] 299 VMLAL.S16 q9, d9, d1[0] 300 VMLAL.S16 q10, d8, d3[0] 301 VMLAL.S16 q11, d9, d3[0] 302 VSUBL.U8 q5, d10, d14 303 VMLAL.S16 q12, d8, d5[0] 304 VMLAL.S16 q13, d9, d5[0] 305 VMLAL.S16 q14, d8, d7[0] 306 VMLAL.S16 q15, d9, d7[0] 307 308 VLD1.8 {d8}, [r9]! // B6 309 VMLAL.S16 q8, d10, d1[1] 310 VMLAL.S16 q9, d11, d1[1] 311 VMLAL.S16 q10, d10, d3[1] 312 VMLAL.S16 q11, d11, d3[1] 313 VSUBL.U8 q4, d8, d14 314 VMLAL.S16 q12, d10, d5[1] 315 VMLAL.S16 q13, d11, d5[1] 316 VMLAL.S16 q14, d10, d7[1] 317 VMLAL.S16 q15, d11, d7[1] 318 319 VLD1.8 {d10}, [r9]! // B7 320 VMLAL.S16 q8, d8, d1[2] 321 VMLAL.S16 q9, d9, d1[2] 322 VMLAL.S16 q10, d8, d3[2] 323 VMLAL.S16 q11, d9, d3[2] 324 VSUBL.U8 q5, d10, d14 325 VMLAL.S16 q12, d8, d5[2] 326 VMLAL.S16 q13, d9, d5[2] 327 VMLAL.S16 q14, d8, d7[2] 328 VMLAL.S16 q15, d9, d7[2] 329 330 VMLAL.S16 q8, d10, d1[3] 331 VMLAL.S16 q9, d11, d1[3] 332 VMLAL.S16 q10, d10, d3[3] 333 VMLAL.S16 q11, d11, d3[3] 334 VMLAL.S16 q12, d10, d5[3] 335 VMLAL.S16 q13, d11, d5[3] 336 ADDS r5, r5, 8 337 VMLAL.S16 q14, d10, d7[3] 338 VMLAL.S16 q15, d11, d7[3] 339 340 # Is there a remainder?- 1-7 bytes of A 341 BNE 4f 342 3433: 344 # RNDNU quantization 345 VDUP.32 q0, d12[0] // right_pre_shift 346 347 VQSHL.S32 q8, q8, q0 348 VQSHL.S32 q9, q9, q0 349 VQSHL.S32 q10, q10, q0 350 VQSHL.S32 q11, q11, q0 351 VQSHL.S32 q12, q12, q0 352 VQSHL.S32 q13, q13, q0 353 VQSHL.S32 q14, q14, q0 354 VQSHL.S32 q15, q15, q0 355 356 VDUP.32 q2, d13[0] // right_post_shift 357 358 VQDMULH.S32 q8, q8, d12[1] // multiplier 359 VQDMULH.S32 q9, q9, d12[1] 360 VQDMULH.S32 q10, q10, d12[1] 361 VQDMULH.S32 q11, q11, d12[1] 362 VQDMULH.S32 q12, q12, d12[1] 363 VQDMULH.S32 q13, q13, d12[1] 364 VQDMULH.S32 q14, q14, d12[1] 365 VQDMULH.S32 q15, q15, d12[1] 366 367 VRSHL.S32 q8, q8, q2 368 VRSHL.S32 q9, q9, q2 369 VRSHL.S32 q10, q10, q2 370 VRSHL.S32 q11, q11, q2 371 VRSHL.S32 q12, q12, q2 372 VRSHL.S32 q13, q13, q2 373 VRSHL.S32 q14, q14, q2 374 VRSHL.S32 q15, q15, q2 375 376 VDUP.16 q0, d13[2] // output_zero_point 377 378 VQMOVN.S32 d16, q8 379 VQMOVN.S32 d17, q9 380 VQMOVN.S32 d18, q10 381 VQMOVN.S32 d19, q11 382 VQMOVN.S32 d20, q12 383 VQMOVN.S32 d21, q13 384 VQMOVN.S32 d22, q14 385 VQMOVN.S32 d23, q15 386 387 VQADD.S16 q8, q8, q0 388 VQADD.S16 q9, q9, q0 389 VQADD.S16 q10, q10, q0 390 VQADD.S16 q11, q11, q0 391 392 VDUP.8 q12, d13[6] // output_min 393 394 VQMOVUN.S16 d0, q8 395 VQMOVUN.S16 d1, q9 396 VQMOVUN.S16 d2, q10 397 VQMOVUN.S16 d3, q11 398 399 VDUP.8 q13, d13[7] // output_max 400 401 VMAX.U8 q0, q0, q12 402 VMAX.U8 q1, q1, q12 403 404 LDR r2, [sp, 56] // kc 405 SUBS r1, r1, 8 406 407 VMIN.U8 q0, q0, q13 408 VMIN.U8 q1, q1, q13 409 410 # Store full 4 x 8 411 BLO 5f 412 VST1.8 {d0}, [r11], r7 413 SUB r3, r3, r2 414 VST1.8 {d1}, [r4], r7 415 SUB r12, r12, r2 416 VST1.8 {d2}, [r8], r7 417 SUB r10, r10, r2 418 VST1.8 {d3}, [r6], r7 419 SUB r0, r0, r2 420 BHI 0b 421 422 VPOP {d8-d14} 423 ADD sp, sp, 4 // skip r2 424 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 425 426 # Remainder- 1 to 7 bytes of A 427 .p2align 3 4284: 429 AND r5, r5, 7 // kc remainder 1 to 7 430 431 VLD1.8 {d0}, [r3], r5 432 VLD1.8 {d8}, [r9]! 433 VLD1.8 {d2}, [r12], r5 434 VLD1.8 {d4}, [r10], r5 435 VLD1.8 {d6}, [r0], r5 436 437 VMOVL.U8 q0, d0 438 VSUBL.U8 q4, d8, d14 439 VMOVL.U8 q1, d2 440 VMOVL.U8 q2, d4 441 VMOVL.U8 q3, d6 442 VMLAL.S16 q8, d8, d0[0] 443 VMLAL.S16 q9, d9, d0[0] 444 VMLAL.S16 q10, d8, d2[0] 445 VMLAL.S16 q11, d9, d2[0] 446 VMLAL.S16 q12, d8, d4[0] 447 VMLAL.S16 q13, d9, d4[0] 448 VMLAL.S16 q14, d8, d6[0] 449 VMLAL.S16 q15, d9, d6[0] 450 CMP r5, 2 451 BLO 3b 452 453 VLD1.8 {d8}, [r9]! 454 VSUBL.U8 q4, d8, d14 455 VMLAL.S16 q8, d8, d0[1] 456 VMLAL.S16 q9, d9, d0[1] 457 VMLAL.S16 q10, d8, d2[1] 458 VMLAL.S16 q11, d9, d2[1] 459 VMLAL.S16 q12, d8, d4[1] 460 VMLAL.S16 q13, d9, d4[1] 461 VMLAL.S16 q14, d8, d6[1] 462 VMLAL.S16 q15, d9, d6[1] 463 BEQ 3b 464 465 VLD1.8 {d8}, [r9]! 466 VSUBL.U8 q4, d8, d14 467 VMLAL.S16 q8, d8, d0[2] 468 VMLAL.S16 q9, d9, d0[2] 469 VMLAL.S16 q10, d8, d2[2] 470 VMLAL.S16 q11, d9, d2[2] 471 VMLAL.S16 q12, d8, d4[2] 472 VMLAL.S16 q13, d9, d4[2] 473 VMLAL.S16 q14, d8, d6[2] 474 VMLAL.S16 q15, d9, d6[2] 475 CMP r5, 4 476 BLO 3b 477 478 VLD1.8 {d8}, [r9]! 479 VSUBL.U8 q4, d8, d14 480 VMLAL.S16 q8, d8, d0[3] 481 VMLAL.S16 q9, d9, d0[3] 482 VMLAL.S16 q10, d8, d2[3] 483 VMLAL.S16 q11, d9, d2[3] 484 VMLAL.S16 q12, d8, d4[3] 485 VMLAL.S16 q13, d9, d4[3] 486 VMLAL.S16 q14, d8, d6[3] 487 VMLAL.S16 q15, d9, d6[3] 488 BEQ 3b 489 490 VLD1.8 {d8}, [r9]! 491 VSUBL.U8 q4, d8, d14 492 VMLAL.S16 q8, d8, d1[0] 493 VMLAL.S16 q9, d9, d1[0] 494 VMLAL.S16 q10, d8, d3[0] 495 VMLAL.S16 q11, d9, d3[0] 496 VMLAL.S16 q12, d8, d5[0] 497 VMLAL.S16 q13, d9, d5[0] 498 VMLAL.S16 q14, d8, d7[0] 499 VMLAL.S16 q15, d9, d7[0] 500 CMP r5, 6 501 BLO 3b 502 503 VLD1.8 {d8}, [r9]! 504 VSUBL.U8 q4, d8, d14 505 VMLAL.S16 q8, d8, d1[1] 506 VMLAL.S16 q9, d9, d1[1] 507 VMLAL.S16 q10, d8, d3[1] 508 VMLAL.S16 q11, d9, d3[1] 509 VMLAL.S16 q12, d8, d5[1] 510 VMLAL.S16 q13, d9, d5[1] 511 VMLAL.S16 q14, d8, d7[1] 512 VMLAL.S16 q15, d9, d7[1] 513 BEQ 3b 514 515 VLD1.8 {d8}, [r9]! 516 VSUBL.U8 q4, d8, d14 517 VMLAL.S16 q8, d8, d1[2] 518 VMLAL.S16 q9, d9, d1[2] 519 VMLAL.S16 q10, d8, d3[2] 520 VMLAL.S16 q11, d9, d3[2] 521 VMLAL.S16 q12, d8, d5[2] 522 VMLAL.S16 q13, d9, d5[2] 523 VMLAL.S16 q14, d8, d7[2] 524 VMLAL.S16 q15, d9, d7[2] 525 B 3b 526 527 # Store odd width 528 .p2align 3 5295: 530 TST r1, 4 531 BEQ 6f 532 VST1.32 {d0[0]}, [r11]! 533 VST1.32 {d1[0]}, [r4]! 534 VST1.32 {d2[0]}, [r8]! 535 VST1.32 {d3[0]}, [r6]! 536 VEXT.8 q0, q0, q0, 4 537 VEXT.8 q1, q1, q1, 4 5386: 539 TST r1, 2 540 BEQ 7f 541 VST1.16 {d0[0]}, [r11]! 542 VST1.16 {d1[0]}, [r4]! 543 VST1.16 {d2[0]}, [r8]! 544 VST1.16 {d3[0]}, [r6]! 545 VEXT.8 q0, q0, q0, 2 546 VEXT.8 q1, q1, q1, 2 547 5487: 549 TST r1, 1 550 BEQ 8f 551 VST1.8 {d0[0]}, [r11] 552 VST1.8 {d1[0]}, [r4] 553 VST1.8 {d2[0]}, [r8] 554 VST1.8 {d3[0]}, [r6] 555 5568: 557 VPOP {d8-d14} 558 ADD sp, sp, 4 // skip r2 559 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 560 561 562END_FUNCTION xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a53 563 564#ifdef __ELF__ 565.section ".note.GNU-stack","",%progbits 566#endif 567 568