1//===- ARCInstrInfo.td - Target Description for ARC --------*- tablegen -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file describes the ARC instructions in TableGen format. 10// 11//===----------------------------------------------------------------------===// 12 13include "ARCInstrFormats.td" 14 15// --------------------------------------------------------------------------- 16// Selection DAG Nodes. 17// --------------------------------------------------------------------------- 18 19// Selection DAG types. 20def SDT_ARCcmptst : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; 21def SDT_ARCcmov : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>]>; 22def SDT_ARCmov : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>]>; 23def SDT_ARCbrcc : SDTypeProfile<0, 4, []>; 24def SDT_ARCBranchLink : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; 25def SDT_ARCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>, 26 SDTCisVT<1, i32> ]>; 27def SDT_ARCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, 28 SDTCisVT<1, i32> ]>; 29 30 31// Global Address. 32def ARCGAWrapper : SDNode<"ARCISD::GAWRAPPER", SDT_ARCmov, []>; 33 34// Comparison 35def ARCcmp : SDNode<"ARCISD::CMP", SDT_ARCcmptst, [SDNPOutGlue]>; 36 37// Conditional mov 38def ARCcmov : SDNode<"ARCISD::CMOV", SDT_ARCcmov, [SDNPInGlue]>; 39 40// Conditional Branch 41def ARCbrcc : SDNode<"ARCISD::BRcc", SDT_ARCbrcc, 42 [SDNPHasChain, SDNPInGlue, SDNPOutGlue]>; 43 44// Direct Call 45def ARCBranchLink : SDNode<"ARCISD::BL",SDT_ARCBranchLink, 46 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, 47 SDNPVariadic]>; 48 49// Indirect Call 50def ARCJumpLink : SDNode<"ARCISD::JL",SDT_ARCBranchLink, 51 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, 52 SDNPVariadic]>; 53// Call return 54def ret : SDNode<"ARCISD::RET", SDTNone, 55 [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; 56 57// Call sequencing nodes. 58// These are target-independent nodes, but have target-specific formats. 59def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_ARCCallSeqStart, 60 [SDNPHasChain, SDNPOutGlue]>; 61def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_ARCCallSeqEnd, 62 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; 63 64//===----------------------------------------------------------------------===// 65// Instruction Pattern Stuff 66//===----------------------------------------------------------------------===// 67 68def imm32 : ImmLeaf<i32, [{ 69 return (Imm & 0xFFFFFFFF) == Imm; 70}]>; 71 72// Addressing modes 73def FrameADDR_ri : ComplexPattern<i32, 2, "SelectFrameADDR_ri", 74 [add, frameindex], []>; 75def AddrModeS9 : ComplexPattern<i32, 2, "SelectAddrModeS9", []>; 76def AddrModeImm : ComplexPattern<i32, 2, "SelectAddrModeImm", []>; 77def AddrModeFar : ComplexPattern<i32, 2, "SelectAddrModeFar", []>; 78 79//===----------------------------------------------------------------------===// 80// Instruction Class Templates 81//===----------------------------------------------------------------------===// 82 83//===----------------------------------------------------------------------===// 84// Pseudo Instructions 85//===----------------------------------------------------------------------===// 86 87let Defs = [SP], Uses = [SP] in { 88def ADJCALLSTACKDOWN : PseudoInstARC<(outs), (ins i32imm:$amt, i32imm:$amt2), 89 "# ADJCALLSTACKDOWN $amt, $amt2", 90 [(callseq_start timm:$amt, timm:$amt2)]>; 91def ADJCALLSTACKUP : PseudoInstARC<(outs), (ins i32imm:$amt1, i32imm:$amt2), 92 "# ADJCALLSTACKUP $amt1", 93 [(callseq_end timm:$amt1, timm:$amt2)]>; 94} 95 96def GETFI : PseudoInstARC<(outs GPR32:$dst), (ins MEMii:$addr), 97 "pldfi $dst, $addr", 98 [(set GPR32:$dst, FrameADDR_ri:$addr)]>; 99 100 101def ST_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr), 102 "ST_FAR $dst, $addr", 103 [(store GPR32:$dst, AddrModeFar:$addr)]>; 104 105def STH_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr), 106 "STH_FAR $dst, $addr", 107 [(truncstorei16 GPR32:$dst, AddrModeFar:$addr)]>; 108 109def STB_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr), 110 "STB_FAR $dst, $addr", 111 [(truncstorei8 GPR32:$dst, AddrModeFar:$addr)]>; 112 113//===----------------------------------------------------------------------===// 114// Instruction Generation multiclasses. 115// Generate many variants of a single instruction with a single defining 116// multiclass. These classes do not contain Selection DAG patterns. 117//===----------------------------------------------------------------------===// 118 119// Generic 3 operand binary instructions (i.e., add r0, r1, r2). 120multiclass ArcBinaryInst<bits<5> major, bits<6> mincode, 121 string opasm> { 122 // 3 register variant. 123 def _rrr : F32_DOP_RR<major, mincode, 0, (outs GPR32:$A), 124 (ins GPR32:$B, GPR32:$C), 125 !strconcat(opasm, "\t$A, $B, $C"), 126 []>; 127 def _f_rrr : F32_DOP_RR<major, mincode, 1, (outs GPR32:$A), 128 (ins GPR32:$B, GPR32:$C), 129 !strconcat(opasm, ".f\t$A, $B, $C"), 130 []> 131 { let Defs = [STATUS32]; } 132 133 // 2 register with unsigned 6-bit immediate variant. 134 def _rru6 : F32_DOP_RU6<major, mincode, 0, (outs GPR32:$A), 135 (ins GPR32:$B, immU6:$U6), 136 !strconcat(opasm, "\t$A, $B, $U6"), 137 []>; 138 def _f_rru6 : F32_DOP_RU6<major, mincode, 1, (outs GPR32:$A), 139 (ins GPR32:$B, immU6:$U6), 140 !strconcat(opasm, ".f\t$A, $B, $U6"), 141 []> 142 { let Defs = [STATUS32]; } 143 144 // 2 register with 32-bit immediate variant. 145 def _rrlimm : F32_DOP_RLIMM<major, mincode, 0, 146 (outs GPR32:$A), 147 (ins GPR32:$B, i32imm:$LImm), 148 !strconcat(opasm, "\t$A, $B, $LImm"), 149 []>; 150 def _f_rrlimm : F32_DOP_RLIMM<major, mincode, 1, 151 (outs GPR32:$A), 152 (ins GPR32:$B, i32imm:$LImm), 153 !strconcat(opasm, ".f\t$A, $B, $LImm"), 154 []> 155 { let Defs = [STATUS32]; } 156 157 // 2 matched-register with signed 12-bit immediate variant (add r0, r0, -1). 158 def _rrs12 : F32_DOP_RS12<major, mincode, 0, 159 (outs GPR32:$B), 160 (ins GPR32:$in, immS<12>:$S12), 161 !strconcat(opasm, "\t$B, $in, $S12"), 162 []> 163 { let Constraints = "$B = $in"; } 164 def _f_rrs12 : F32_DOP_RS12<major, mincode, 1, 165 (outs GPR32:$B), 166 (ins GPR32:$in, immS<12>:$S12), 167 !strconcat(opasm, ".f\t$B, $in, $S12"), 168 []> 169 { let Constraints = "$B = $in"; let Defs = [STATUS32]; } 170} 171 172// Special multivariant GEN4 DOP format instruction that take 2 registers. 173// This is the class that is used for various comparison instructions. 174multiclass ArcSpecialDOPInst<bits<6> subop, string opasm, bit F> { 175 def _rr : F32_DOP_RR<0b00100, subop, F, (outs), (ins GPR32:$B, GPR32:$C), 176 !strconcat(opasm, "\t$B, $C"), 177 []>; 178 179 def _ru6 : F32_DOP_RU6<0b00100, subop, F, (outs), (ins GPR32:$B, i32imm:$U6), 180 !strconcat(opasm, "\t$B, $U6"), 181 []>; 182 183 def _rlimm : F32_DOP_RLIMM<0b00100, subop, F, (outs), 184 (ins GPR32:$B, i32imm:$LImm), 185 !strconcat(opasm, "\t$B, $LImm"), 186 []>; 187} 188 189// Generic 2-operand unary instructions. 190multiclass ArcUnaryInst<bits<5> major, bits<6> subop, 191 string opasm> { 192 def _rr : F32_SOP_RR<major, subop, 0, (outs GPR32:$B), (ins GPR32:$C), 193 !strconcat(opasm, "\t$B, $C"), []>; 194 195 def _f_rr : F32_SOP_RR<major, subop, 1, (outs GPR32:$B), (ins GPR32:$C), 196 !strconcat(opasm, ".f\t$B, $C"), []> 197 { let Defs = [STATUS32]; } 198} 199 200 201multiclass ArcBinaryGEN4Inst<bits<6> mincode, string opasm> : 202 ArcBinaryInst<0b00100, mincode, opasm>; 203multiclass ArcBinaryEXT5Inst<bits<6> mincode, string opasm> : 204 ArcBinaryInst<0b00101, mincode, opasm>; 205 206multiclass ArcUnaryGEN4Inst<bits<6> mincode, string opasm> : 207 ArcUnaryInst<0b00100, mincode, opasm>; 208 209// Pattern generation for different instruction variants. 210multiclass MultiPat<SDPatternOperator InFrag, 211 Instruction RRR, Instruction RRU6, Instruction RRLImm> { 212 def _rrr : Pat<(InFrag i32:$B, i32:$C), (RRR i32:$B, i32:$C)>; 213 def _rru6 : Pat<(InFrag i32:$B, immU6:$U6), (RRU6 i32:$B, immU6:$U6)>; 214 def _rrlimm : Pat<(InFrag i32:$B, imm32:$LImm), (RRLImm i32:$B, imm32:$LImm)>; 215} 216 217// --------------------------------------------------------------------------- 218// Instruction definitions and patterns for 3 operand binary instructions. 219// --------------------------------------------------------------------------- 220 221// Definitions for 3 operand binary instructions. 222defm ADD : ArcBinaryGEN4Inst<0b000000, "add">; 223defm SUB : ArcBinaryGEN4Inst<0b000010, "sub">; 224defm SUB1 : ArcBinaryGEN4Inst<0b010111, "sub1">; 225defm SUB2 : ArcBinaryGEN4Inst<0b011000, "sub2">; 226defm SUB3 : ArcBinaryGEN4Inst<0b011001, "sub3">; 227defm OR : ArcBinaryGEN4Inst<0b000101, "or">; 228defm AND : ArcBinaryGEN4Inst<0b000100, "and">; 229defm XOR : ArcBinaryGEN4Inst<0b000111, "xor">; 230defm MAX : ArcBinaryGEN4Inst<0b001000, "max">; 231defm MIN : ArcBinaryGEN4Inst<0b001001, "min">; 232defm ASL : ArcBinaryEXT5Inst<0b000000, "asl">; 233defm LSR : ArcBinaryEXT5Inst<0b000001, "lsr">; 234defm ASR : ArcBinaryEXT5Inst<0b000010, "asr">; 235defm ROR : ArcBinaryEXT5Inst<0b000011, "ror">; 236defm MPY : ArcBinaryGEN4Inst<0b011010, "mpy">; 237defm MPYM : ArcBinaryGEN4Inst<0b011011, "mpym">; 238defm MPYMU : ArcBinaryGEN4Inst<0b011100, "mpymu">; 239defm SETEQ : ArcBinaryGEN4Inst<0b111000, "seteq">; 240 241// Patterns for 3 operand binary instructions. 242defm : MultiPat<add, ADD_rrr, ADD_rru6, ADD_rrlimm>; 243defm : MultiPat<sub, SUB_rrr, SUB_rru6, SUB_rrlimm>; 244defm : MultiPat<or, OR_rrr, OR_rru6, OR_rrlimm>; 245defm : MultiPat<and, AND_rrr, AND_rru6, AND_rrlimm>; 246defm : MultiPat<xor, XOR_rrr, XOR_rru6, XOR_rrlimm>; 247defm : MultiPat<smax, MAX_rrr, MAX_rru6, MAX_rrlimm>; 248defm : MultiPat<smin, MIN_rrr, MIN_rru6, MIN_rrlimm>; 249defm : MultiPat<shl, ASL_rrr, ASL_rru6, ASL_rrlimm>; 250defm : MultiPat<srl, LSR_rrr, LSR_rru6, LSR_rrlimm>; 251defm : MultiPat<sra, ASR_rrr, ASR_rru6, ASR_rrlimm>; 252defm : MultiPat<rotr, ROR_rrr, ROR_rru6, ROR_rrlimm>; 253defm : MultiPat<mul, MPY_rrr, MPY_rru6, MPY_rrlimm>; 254defm : MultiPat<mulhs, MPYM_rrr, MPYM_rru6, MPYM_rrlimm>; 255defm : MultiPat<mulhu, MPYMU_rrr, MPYMU_rru6, MPYMU_rrlimm>; 256 257// --------------------------------------------------------------------------- 258// Unary Instruction definitions. 259// --------------------------------------------------------------------------- 260// General unary instruction definitions. 261defm SEXB : ArcUnaryGEN4Inst<0b000101, "sexb">; 262defm SEXH : ArcUnaryGEN4Inst<0b000110, "sexh">; 263 264// General Unary Instruction fragments. 265def : Pat<(sext_inreg i32:$a, i8), (SEXB_rr i32:$a)>; 266def : Pat<(sext_inreg i32:$a, i16), (SEXH_rr i32:$a)>; 267 268// Comparison instruction definition 269let isCompare = 1, Defs = [STATUS32] in { 270defm CMP : ArcSpecialDOPInst<0b001100, "cmp", 1>; 271} 272 273def cmp : PatFrag<(ops node:$op1, node:$op2), (ARCcmp $op1, $op2)>; 274defm : MultiPat<cmp, CMP_rr, CMP_ru6, CMP_rlimm>; 275 276// --------------------------------------------------------------------------- 277// MOV instruction and variants (conditional mov). 278// --------------------------------------------------------------------------- 279let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { 280def MOV_rs12 : F32_DOP_RS12<0b00100, 0b001010, 0, 281 (outs GPR32:$B), (ins immS<12>:$S12), 282 "mov\t$B, $S12", 283 [(set GPR32:$B, immS<12>:$S12)]>; 284} 285 286def MOV_rr : F32_DOP_RR<0b00100, 0b001010, 0, 287 (outs GPR32:$B), (ins GPR32:$C), 288 "mov\t$B, $C", []>; 289 290def MOV_rlimm : F32_DOP_RLIMM<0b00100, 0b001010, 0, 291 (outs GPR32:$B), (ins i32imm:$LImm), 292 "mov\t$B, $LImm", []>; 293 294def MOV_ru6 : F32_DOP_RU6<0b00100, 0b001010, 0, 295 (outs GPR32:$B), (ins immU6:$U6), 296 "mov\t$B, $U6", []>; 297 298def cmov : PatFrag<(ops node:$op1, node:$op2, node:$cc), 299 (ARCcmov $op1, $op2, $cc)>; 300let Uses = [STATUS32] in { 301def MOVcc : F32_DOP_CC_RR<0b00100, 0b001010, 0, 302 (outs GPR32:$B), 303 (ins GPR32:$C, GPR32:$fval, cmovpred:$cc), 304 !strconcat("mov.", "$cc\t$B, $C"), 305 [(set GPR32:$B, (cmov i32:$C, i32:$fval, cmovpred:$cc))]> { 306 let Constraints = "$B = $fval"; 307} 308} 309def : Pat<(ARCGAWrapper tglobaladdr:$addr), 310 (MOV_rlimm tglobaladdr:$addr)>; 311 312def : Pat<(ARCGAWrapper tjumptable:$addr), 313 (MOV_rlimm tjumptable:$addr)>; 314 315 316// --------------------------------------------------------------------------- 317// Control flow instructions (branch, return, calls, etc). 318// --------------------------------------------------------------------------- 319 320// Branch instructions 321let isBranch = 1, isTerminator = 1 in { 322 323 // Unconditional branch. 324 let isBarrier = 1 in 325 def BR : F32_BR0_UCOND_FAR<(outs), (ins btargetS25:$S25), 326 "b\t$S25", [(br bb:$S25)]>; 327 328 let Uses=[STATUS32] in 329 // Conditional branch. 330 def Bcc : F32_BR0_COND<(outs), (ins btargetS21:$S21, ccond:$cc), 331 "b$cc\t$S21", []>; 332 333 // Compare and branch (limited range). 334 def BRcc_rr : F32_BR1_BCC<(outs), 335 (ins btargetS9:$S9, GPR32:$B, GPR32:$C, brccond:$cc), 336 "br$cc\t$B, $C, $S9", 0, []>; 337 def BRcc_ru6 : F32_BR1_BCC<(outs), 338 (ins btargetS9:$S9, GPR32:$B, immU6:$C, brccond:$cc), 339 "br$cc\t$B, $C, $S9", 1, []>; 340 341 // Pseudo compare and branch. 342 // After register allocation, this can expand into either a limited range 343 // Compare and branch (BRcc), or into CMP + Bcc. 344 // At worst, this expands into 2 4-byte instructions. 345 def BRcc_rr_p : PseudoInstARC<(outs), 346 (ins btarget:$T, GPR32:$B, GPR32:$C, ccond:$cc), 347 "pbr$cc\t$B, $C, $T", 348 [(ARCbrcc bb:$T, i32:$B, i32:$C, imm32:$cc)]> 349 { let Size = 8; } 350 351 def BRcc_ru6_p : PseudoInstARC<(outs), 352 (ins btarget:$T, GPR32:$B, i32imm:$C, ccond:$cc), 353 "pbr$cc\t$B, $C, $T", 354 [(ARCbrcc bb:$T, i32:$B, immU6:$C, imm32:$cc)]> 355 { let Size = 8; } 356} // let isBranch, isTerminator 357 358// Unconditional Jump. 359let isBranch = 1, isTerminator = 1, isBarrier = 1 in { 360 // Indirect. 361 let isIndirectBranch = 1 in 362 def J : F32_DOP_RR<0b00100, 0b100000, 0, 363 (outs), (ins GPR32:$C), 364 "j\t[$C]", [(brind i32:$C)]>; 365 366 // Direct. 367 def J_LImm : F32_DOP_RLIMM<0b00100, 0b100000, 0, 368 (outs), (ins i32imm:$LImm), 369 "j\t$LImm", []>; 370} 371 372// Call instructions. 373let isCall = 1, isBarrier = 1, Defs = [BLINK], Uses = [SP] in { 374 // Direct unconditional call. 375 def BL : F32_BR1_BL_UCOND_FAR<(outs), (ins calltargetS25:$S25), 376 "bl\t$S25", [(ARCBranchLink tglobaladdr:$S25)]>; 377 378 // Indirect unconditional call. 379 let isIndirectBranch = 1 in 380 def JL : F32_DOP_RR<0b00100, 0b100010, 0, (outs), (ins GPR32:$C), 381 "jl\t[$C]", [(ARCJumpLink i32:$C)]>; 382 383 // Direct unconditional call. 384 def JL_LImm : F32_DOP_RLIMM<0b00100, 0b100010, 0, (outs), (ins i32imm:$LImm), 385 "jl\t$LImm", []>; 386} // let isCall, isBarrier, Defs, Uses 387 388// Pattern to generate BL instruction. 389def : Pat<(ARCBranchLink texternalsym:$dst), (BL texternalsym:$dst)>; 390 391// Return from call. 392let isReturn = 1, isTerminator = 1, isBarrier = 1 in 393// This is a specialized 2-byte instruction that doesn't generalize 394// to any larger 2-byte class, so go ahead and define it here. 395def J_S_BLINK : InstARC<2, (outs), (ins), "j_s\t[%blink]", [(ret)]> { 396 let Inst{15-0} = 0b0111111011100000; 397} 398 399//---------------------------------------------------------------------------- 400// Compact stack-based operations. 401//---------------------------------------------------------------------------- 402 403// 2-byte push/pop blink instructions commonly used for prolog/epilog 404// generation. These 2 instructions are actually specialized 2-byte 405// format instructions that aren't generalized to a larger 2-byte 406// class, so we might as well have them here. 407let Uses = [BLINK], Defs = [SP] in 408def PUSH_S_BLINK : F16_SP_OPS_buconst<0b111, "push_s">; 409 410let Defs = [BLINK, SP] in 411def POP_S_BLINK : F16_SP_OPS_buconst<0b110, "pop_s">; 412 413def PUSH_S_r : F16_SP_OPS_uconst<0b110, 414 (outs), (ins GPR32Reduced:$b3), "push_s">; 415def POP_S_r : F16_SP_OPS_uconst<0b111, 416 (outs GPR32Reduced:$b3), (ins), "pop_s">; 417 418def SP_SUB_SP_S : F16_SP_OPS_bconst<0b001, "sub_s">; 419def SP_ADD_SP_S : F16_SP_OPS_bconst<0b000, "add_s">; 420def SP_ADD_S : F16_SP_OPS_u7_aligned<0b100, 421 (outs GPR32Reduced:$b3), (ins immU<7>:$u7), 422 "add_s\t$b3, %sp, $u7">; 423 424def SP_LD_S : F16_SP_LD<0b000, "ld_s">; 425def SP_LDB_S : F16_SP_LD<0b001, "ldb_s">; 426def SP_ST_S : F16_SP_ST<0b010, "st_s">; 427def SP_STB_S : F16_SP_ST<0b011, "stb_s">; 428 429def LEAVE_S : F16_SP_OPS<0b110, 430 (outs), (ins immU<7>:$u7), "leave_s\t$u7"> { 431 432 bits<7> u7; 433 434 let fieldB = u7{6-4}; 435 let fieldU{4-1} = u7{3-0}; 436 let fieldU{0} = 0b0; 437} 438 439def ENTER_S : F16_SP_OPS<0b111, 440 (outs), (ins immU<6>:$u6), "enter_s\t$u6"> { 441 442 bits<6> u6; 443 444 let fieldB{2} = 0; 445 let fieldB{1-0} = u6{5-4}; 446 let fieldU{4-1} = u6{3-0}; 447 let fieldU{0} = 0b0; 448} 449 450//---------------------------------------------------------------------------- 451// Compact Move/Load instructions. 452//---------------------------------------------------------------------------- 453class COMPACT_MOV_S : 454 F16_COMPACT<0b0, (outs GPR32:$g), (ins GPR32:$h), 455 "mov_s\t$g, $h"> { 456 let DecoderMethod = "DecodeMoveHRegInstruction"; 457} 458 459def COMPACT_MOV_S_limm : COMPACT_MOV_S { 460 bits<32> LImm; 461 let Inst{47-16} = LImm; 462 463 bits<5> LImmReg = 0b11110; 464 let Inst{7-5} = LImmReg{2-0}; 465 let Inst{1-0} = LImmReg{4-3}; 466 467 let Size = 6; 468} 469 470def COMPACT_MOV_S_hreg : COMPACT_MOV_S; 471 472def COMPACT_LD_S : 473 F16_COMPACT<0b1, (outs GPR32:$r), (ins GPR32:$h, immU<5>:$u5), 474 "ld_s\t$r, [$h, $u5]"> { 475 bits<5> u5; 476 bits<2> r; 477 478 let Inst{10} = u5{4}; 479 let Inst{9-8} = r; 480 let Inst{4-3} = u5{3-2}; 481 let u5{1-0} = 0b00; 482} 483 484//---------------------------------------------------------------------------- 485// Compact Load/Add/Sub. 486//---------------------------------------------------------------------------- 487def LD_S_AS_rrr : F16_LD_SUB<0b0, "ld_s.as\t$a, [$b, $c]">; 488def SUB_S_rrr : F16_LD_SUB<0b1, "sub_s\t$a, $b, $c">; 489def ADD_S_rru6 : F16_ADD; 490 491//---------------------------------------------------------------------------- 492// Compact Load/Store. 493//---------------------------------------------------------------------------- 494def LD_S_s11 : F16_LD_ST_s11<0b0, "ld_s\t%r1, [%gp, $s11]">; 495def ST_S_s11 : F16_LD_ST_s11<0b1, "st_s\t%r0, [%gp, $s11]">; 496def LDI_S_u7 : F16_LDI_u7; 497 498//---------------------------------------------------------------------------- 499// Indexed Jump or Execute. 500//---------------------------------------------------------------------------- 501def JLI_S : F16_JLI_EI<0, "jli_s">; 502def EI_S : F16_JLI_EI<1, "ei_s">; 503 504//---------------------------------------------------------------------------- 505// Load/Add Register-Register. 506//---------------------------------------------------------------------------- 507def LD_S_rrr : F16_LD_ADD_RR<0b00, "ld_s\t$a, [$b, $c]">; 508def LDB_S_rrr : F16_LD_ADD_RR<0b01, "ldb_s\t$a, [$b, $c]">; 509def LDH_S_rrr : F16_LD_ADD_RR<0b10, "ldh_s\t$a, [$b, $c]">; 510def ADD_S_rrr : F16_LD_ADD_RR<0b11, "add_s\t$a, $b, $c">; 511 512//---------------------------------------------------------------------------- 513// Load/Add GP-Relative. 514//---------------------------------------------------------------------------- 515def GP_LD_S : F16_GP_LD_ADD<0b00, (ins immS<11>:$s), 516 "ld_s\t%r0, [%gp, $s]"> { 517 518 bits<11> s; 519 let Inst{8-0} = s{10-2}; 520 let s{1-0} = 0b00; 521} 522 523def GP_LDB_S : F16_GP_LD_ADD<0b01, (ins immS<9>:$s), 524 "ldb_s\t%r0, [%gp, $s]"> { 525 526 bits<9> s; 527 let Inst{8-0} = s{8-0}; 528} 529 530def GP_LDH_S : F16_GP_LD_ADD<0b10, (ins immS<10>:$s), 531 "ldh_s\t%r0, [%gp, $s]"> { 532 533 bits<10> s; 534 let Inst{8-0} = s{9-1}; 535 let s{0} = 0b0; 536} 537 538def GP_ADD_S : F16_GP_LD_ADD<0b11, (ins immS<11>:$s), 539 "add_s\t%r0, %gp, $s"> { 540 541 bits<11> s; 542 let Inst{8-0} = s{10-2}; 543 let s{1-0} = 0b00; 544} 545 546//---------------------------------------------------------------------------- 547// Load PCL-Relative. 548//---------------------------------------------------------------------------- 549def PCL_LD : InstARC<2, (outs GPR32:$b), (ins immU<10>:$u10), 550 "ld_s\t$b, [%pcl, $u10]", []> { 551 552 bits<3> b; 553 bits<10> u10; 554 555 let Inst{15-11} = 0b11010; 556 let Inst{10-8} = b; 557 let Inst{7-0} = u10{9-2}; 558 let u10{1-0} = 0b00; 559} 560 561let isBranch = 1 in { 562 //---------------------------------------------------------------------------- 563 // Branch on Compare Register with Zero. 564 //---------------------------------------------------------------------------- 565 def BREQ_S : F16_BCC_REG<0b0, "breq_s">; 566 def BRNE_S : F16_BCC_REG<0b1, "brne_s">; 567 568 //---------------------------------------------------------------------------- 569 // Branch Conditionally. 570 //---------------------------------------------------------------------------- 571 let isBarrier = 1 in 572 def B_S : F16_BCC_s10<0b00, "b_s">; 573 574 def BEQ_S : F16_BCC_s10<0b01, "beq_s">; 575 def BNE_S : F16_BCC_s10<0b10, "bne_s">; 576 def BGT_S : F16_BCC_s7<0b000, "bgt_s">; 577 def BGE_S : F16_BCC_s7<0b001, "bge_s">; 578 def BLT_S : F16_BCC_s7<0b010, "blt_s">; 579 def BLE_S : F16_BCC_s7<0b011, "ble_s">; 580 def BHI_S : F16_BCC_s7<0b100, "bhi_s">; 581 def BHS_S : F16_BCC_s7<0b101, "bhs_s">; 582 def BLO_S : F16_BCC_s7<0b110, "blo_s">; 583 def BLS_S : F16_BCC_s7<0b111, "bls_s">; 584} // let isBranch 585 586def BL_S : 587 InstARC<2, (outs), (ins btargetS13:$s13), "bl_s\t$s13", []> { 588 589 let Inst{15-11} = 0b11111; 590 591 bits<13> s13; 592 let Inst{10-0} = s13{12-2}; 593 let s13{1-0} = 0b00; 594 595 let isCall = 1; 596 let isBarrier = 1; 597} 598 599//---------------------------------------------------------------------------- 600// Add/Sub/Shift Register-Immediate. 601//---------------------------------------------------------------------------- 602def ADD_S_ru3 : F16_ADD_IMM<0b00,"add_s">; 603def SUB_S_ru3 : F16_ADD_IMM<0b01,"sub_s">; 604def ASL_S_ru3 : F16_ADD_IMM<0b10,"asl_s">; 605def ASR_S_ru3 : F16_ADD_IMM<0b11,"asr_s">; 606 607//---------------------------------------------------------------------------- 608// Shift/Subtract/Bit Immediate. 609//---------------------------------------------------------------------------- 610def ASL_S_ru5 : F16_SH_SUB_BIT_DST<0b000,"asl_s">; 611def LSR_S_ru5 : F16_SH_SUB_BIT_DST<0b001,"lsr_s">; 612def ASR_S_ru5 : F16_SH_SUB_BIT_DST<0b010,"asr_s">; 613def SUB_S_ru5 : F16_SH_SUB_BIT_DST<0b011,"sub_s">; 614def BSET_S_ru5 : F16_SH_SUB_BIT_DST<0b100,"bset_s">; 615def BCLR_S_ru5 : F16_SH_SUB_BIT_DST<0b101,"bclr_s">; 616def BMSK_S_ru5 : F16_SH_SUB_BIT_DST<0b110,"bmsk_s">; 617def BTST_S_ru5 : F16_SH_SUB_BIT<0b111, "btst_s\t$b, $u5">; 618 619//---------------------------------------------------------------------------- 620// Dual Register Operations. 621//---------------------------------------------------------------------------- 622def ADD_S_rlimm : 623 F16_OP_HREG_LIMM<0b000, (outs GPR32:$b_s3), (ins i32imm:$LImm), 624 !strconcat("add_s", "\t$b_s3, $b_s3, $LImm")>; 625 626def ADD_S_rr : 627 F16_OP_HREG<0b000, (outs GPR32:$b_s3), (ins GPR32:$h), 628 !strconcat("add_s", "\t$b_s3, $b_s3, $h")>; 629 630def ADD_S_rs3 : 631 F16_OP_HREG<0b001, (outs GPR32:$h), (ins immC<3>:$b_s3), 632 !strconcat("add_s", "\t$h, $h, $b_s3")>; 633 634def ADD_S_limms3 : 635 F16_OP_HREG_LIMM<0b001, (outs), (ins immC<3>:$b_s3, i32imm:$LImm), 636 !strconcat("add_s", "\t0, $LImm, $b_s3")>; 637 638def MOV_S_NE_rlimm : 639 F16_OP_HREG_LIMM<0b111, (outs GPR32:$b_s3), (ins i32imm:$LImm), 640 !strconcat("mov_s.ne", "\t$b_s3, $LImm")>; 641 642def MOV_S_NE_rr : 643 F16_OP_HREG<0b111,(outs GPR32:$b_s3), (ins GPR32:$h), 644 !strconcat("mov_s.ne", "\t$b_s3, $h")>; 645 646def MOV_S_rs3 : 647 F16_OP_HREG<0b011, (outs GPR32:$h), (ins immC<3>:$b_s3), 648 !strconcat("mov_s", "\t$h, $b_s3")>; 649 650def MOV_S_s3 : 651 F16_OP_HREG30<0b011, (outs), (ins immC<3>:$b_s3), 652 !strconcat("mov_s", "\t0, $b_s3")>; 653 654def CMP_S_rlimm : 655 F16_OP_HREG_LIMM<0b100, (outs GPR32:$b_s3), (ins i32imm:$LImm), 656 !strconcat("cmp_s", "\t$b_s3, $LImm")>; 657 658def CMP_S_rr : 659 F16_OP_HREG<0b100, (outs GPR32:$b_s3), (ins GPR32:$h), 660 !strconcat("cmp_s", "\t$b_s3, $h")>; 661 662def CMP_S_rs3 : 663 F16_OP_HREG<0b101, (outs GPR32:$h), (ins immC<3>:$b_s3), 664 !strconcat("cmp_s", "\t$h, $b_s3")>; 665 666def CMP_S_limms3 : 667 F16_OP_HREG_LIMM<0b101, (outs), (ins immC<3>:$b_s3, i32imm:$LImm), 668 !strconcat("cmp_s", "\t$LImm, $b_s3")>; 669 670//---------------------------------------------------------------------------- 671// Compact MOV/ADD/CMP Immediate instructions. 672//---------------------------------------------------------------------------- 673def MOV_S_u8 : 674 F16_OP_IMM<0b11011, (outs GPR32:$b), (ins immU<8>:$u8), 675 !strconcat("mov_s", "\t$b, $u8")> { 676 bits<8> u8; 677 let Inst{7-0} = u8; 678} 679 680def ADD_S_u7 : 681 F16_OP_U7<0b0, !strconcat("add_s", "\t$b, $b, $u7")>; 682 683def CMP_S_u7 : 684 F16_OP_U7<0b1, !strconcat("cmp_s", "\t$b, $u7")>; 685 686//---------------------------------------------------------------------------- 687// Compact Load/Store instructions with offset. 688//---------------------------------------------------------------------------- 689def LD_S_OFF : 690 F16_LD_ST_WORD_OFF<0x10, (outs GPR32:$c), (ins GPR32:$b, immU<7>:$off), 691 "ld_s">; 692 693def LDB_S_OFF : 694 F16_LD_ST_BYTE_OFF<0x11, (outs GPR32:$c), (ins GPR32:$b, immU<5>:$off), 695 "ldb_s">; 696 697class F16_LDH_OFF<bits<5> opc, string asmstr> : 698 F16_LD_ST_HALF_OFF<opc, (outs GPR32:$c), (ins GPR32:$b, immU<6>:$off), 699 asmstr>; 700 701def LDH_S_OFF : F16_LDH_OFF<0x12, "ldh_s">; 702def LDH_S_X_OFF : F16_LDH_OFF<0x13, "ldh_s.x">; 703 704def ST_S_OFF : 705 F16_LD_ST_WORD_OFF<0x14, (outs), (ins GPR32:$c, GPR32:$b, immU<7>:$off), 706 "st_s">; 707 708def STB_S_OFF : 709 F16_LD_ST_BYTE_OFF<0x15, (outs), (ins GPR32:$c, GPR32:$b, immU<5>:$off), 710 "stb_s">; 711 712def STH_S_OFF : 713 F16_LD_ST_HALF_OFF<0x16, (outs), (ins GPR32:$c, GPR32:$b, immU<6>:$off), 714 "sth_s">; 715 716//---------------------------------------------------------------------------- 717// General compact instructions. 718//---------------------------------------------------------------------------- 719def GEN_SUB_S : F16_GEN_DOP<0x02, "sub_s">; 720def GEN_AND_S : F16_GEN_DOP<0x04, "and_s">; 721def GEN_OR_S : F16_GEN_DOP<0x05, "or_s">; 722def GEN_BIC_S : F16_GEN_DOP<0x06, "bic_s">; 723def GEN_XOR_S : F16_GEN_DOP<0x07, "xor_s">; 724def GEN_MPYW_S : F16_GEN_DOP<0x09, "mpyw_s">; 725def GEN_MPYUW_S : F16_GEN_DOP<0x0a, "mpyuw_s">; 726def GEN_TST_S : F16_GEN_DOP_NODST<0x0b, "tst_s">; 727def GEN_MPY_S : F16_GEN_DOP<0x0c, "mpy_s">; 728def GEN_SEXB_S : F16_GEN_DOP_SINGLESRC<0x0d, "sexb_s">; 729def GEN_SEXH_S : F16_GEN_DOP_SINGLESRC<0x0e, "sexh_s">; 730def GEN_EXTB_S : F16_GEN_DOP_SINGLESRC<0x0f, "extb_s">; 731def GEN_EXTH_S : F16_GEN_DOP_SINGLESRC<0x10, "exth_s">; 732def GEN_ABS_S : F16_GEN_DOP_SINGLESRC<0x11, "abs_s">; 733def GEN_NOT_S : F16_GEN_DOP_SINGLESRC<0x12, "not_s">; 734def GEN_NEG_S : F16_GEN_DOP_SINGLESRC<0x13, "neg_s">; 735def GEN_ADD1_S : F16_GEN_DOP<0x14, "add1_s">; 736def GEN_ADD2_S : F16_GEN_DOP<0x15, "add2_s">; 737def GEN_ADD3_S : F16_GEN_DOP<0x16, "add3_s">; 738def GEN_ASL_S : F16_GEN_DOP<0x18, "asl_s">; 739def GEN_LSR_S : F16_GEN_DOP<0x19, "lsr_s">; 740def GEN_ASR_S : F16_GEN_DOP<0x1a, "asr_s">; 741def GEN_AS1L_S : F16_GEN_DOP_SINGLESRC<0x1b, "asl_s">; 742def GEN_AS1R_S : F16_GEN_DOP_SINGLESRC<0x1c, "asr_s">; 743def GEN_LS1R_S : F16_GEN_DOP_SINGLESRC<0x1d, "lsr_s">; 744def GEN_TRAP_S : F16_GEN_DOP_BASE<0x1e, (outs), (ins immU6:$u6), 745 "trap_s\t$u6"> { 746 747 bits<6> u6; 748 let b = u6{5-3}; 749 let c = u6{2-0}; 750} 751 752def GEN_BRK_S : F16_GEN_DOP_BASE<0x1f, (outs), (ins), 753 "brk_s"> { 754 755 let b = 0b111; 756 let c = 0b111; 757} 758 759let isBarrier = 1 in { 760 let isBranch = 1 in { 761 def GEN_J_S : F16_GEN_SOP<0x0, "j_s\t[$b]">; 762 def GEN_J_S_D : F16_GEN_SOP<0x1, "j_s.d\t[$b]">; 763 } // let isBranch 764 765 let isCall = 1 in { 766 def GEN_JL_S : F16_GEN_SOP<0x2, "jl_s\t[$b]">; 767 def GEN_JL_S_D : F16_GEN_SOP<0x3, "jl_s.d\t[$b]">; 768 } // let isCall 769} // let isBarrier 770 771def GEN_SUB_S_NE : F16_GEN_SOP<0x6, "sub_s.ne\t$b, $b, $b">; 772 773def GEN_NOP_S : F16_GEN_ZOP<0x0, "nop_s">; 774def GEN_UNIMP_S : F16_GEN_ZOP<0x1, "unimp_s">; 775def GEN_SWI_S : F16_GEN_ZOP<0x2, "swi_s">; 776 777let isReturn = 1, isTerminator = 1 in { 778 def GEN_JEQ_S : F16_GEN_ZOP<0x4, "jeq_s\t[%blink]">; 779 def GEN_JNE_S : F16_GEN_ZOP<0x5, "jne_s\t[%blink]">; 780 let isBarrier = 1 in { 781 //def GEN_J_S_BLINK : F16_GEN_ZOP<0x6, "j_s\t[%blink]">; 782 def GEN_J_S_D_BLINK : F16_GEN_ZOP<0x7, "j_s.d\t[%blink]">; 783 } // let isBarrier 784} // let isReturn, isTerminator 785 786//---------------------------------------------------------------------------- 787// Load/Store instructions. 788//---------------------------------------------------------------------------- 789 790// Filter class for load/store mappings 791class ArcLdStRel; 792 793// Load instruction variants: 794// Control bits: x, aa, di, zz 795// x - sign extend. 796// aa - incrementing mode. (N/A for LIMM). 797// di - uncached. 798// zz - data size. 799multiclass ArcLdInst<DataSizeMode zz, ExtMode x, CacheMode di, string asmop> { 800 let mayLoad = 1, ZZ = zz, X = x, DI = di in { 801 def _rs9: F32_LD_ADDR<x.Value, NoAM.Value, di.Value, zz.Value, 802 (outs GPR32:$A), (ins MEMrs9:$addr), 803 !strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel; 804 805 def _limm: F32_LD_LIMM<x.Value, di.Value, zz.Value, 806 (outs GPR32:$A), (ins MEMii:$addr), 807 !strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel; 808 809 def _rlimm: F32_LD_RLIMM<x.Value, NoAM.Value, di.Value, zz.Value, 810 (outs GPR32:$A), (ins MEMrlimm:$addr), 811 !strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel; 812 813 foreach aa = [PreIncAM, PostIncAM] in { 814 def aa.InstSuffix#_rs9: F32_LD_RS9<x.Value, aa.Value, di.Value, zz.Value, 815 (outs GPR32:$A, GPR32:$addrout), 816 (ins GPR32:$B, immS<9>:$S9), 817 asmop#aa.AsmSuffix#"\t$A, [$B,$S9]", []>, ArcLdStRel 818 { let Constraints = "$addrout = $B"; let AA = aa; } 819 } 820 } 821} 822 823foreach di = [NoCC, UncachedCC] in { 824 defm LD#di.InstSuffix : ArcLdInst<WordSM, NoEM, di, "ld"#di.AsmSuffix>; 825 foreach zz = [ByteSM, HalfSM] in { 826 foreach x = [NoEM, SignedEM] in { 827 defm LD#zz.InstSuffix#x.InstSuffix#di.InstSuffix : ArcLdInst<zz, x, di, "ld"#zz.AsmSuffix#x.AsmSuffix#di.AsmSuffix>; 828 } 829 } 830} 831 832// Load instruction patterns. 833// 32-bit loads. 834def : Pat<(load AddrModeS9:$addr), (LD_rs9 AddrModeS9:$addr)>; 835def : Pat<(load AddrModeImm:$addr), (LD_limm AddrModeImm:$addr)>; 836def : Pat<(load AddrModeFar:$addr), (LD_rs9 AddrModeFar:$addr)>; 837 838// 16-bit loads 839def : Pat<(zextloadi16 AddrModeS9:$addr), (LDH_rs9 AddrModeS9:$addr)>; 840def : Pat<(extloadi16 AddrModeS9:$addr), (LDH_rs9 AddrModeS9:$addr)>; 841def : Pat<(zextloadi16 AddrModeImm:$addr), (LDH_limm AddrModeImm:$addr)>; 842def : Pat<(extloadi16 AddrModeImm:$addr), (LDH_limm AddrModeImm:$addr)>; 843def : Pat<(zextloadi16 AddrModeFar:$addr), (LDH_rlimm AddrModeFar:$addr)>; 844def : Pat<(extloadi16 AddrModeFar:$addr), (LDH_rlimm AddrModeFar:$addr)>; 845def : Pat<(sextloadi16 AddrModeImm:$addr),(LDH_X_limm AddrModeImm:$addr)>; 846def : Pat<(sextloadi16 AddrModeFar:$addr),(LDH_X_rlimm AddrModeFar:$addr)>; 847def : Pat<(sextloadi16 AddrModeS9:$addr),(LDH_X_rs9 AddrModeS9:$addr)>; 848 849// 8-bit loads. 850def : Pat<(zextloadi8 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>; 851def : Pat<(extloadi8 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>; 852def : Pat<(zextloadi8 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>; 853def : Pat<(extloadi8 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>; 854def : Pat<(zextloadi8 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>; 855def : Pat<(extloadi8 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>; 856def : Pat<(zextloadi1 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>; 857def : Pat<(extloadi1 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>; 858def : Pat<(zextloadi1 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>; 859def : Pat<(extloadi1 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>; 860def : Pat<(zextloadi1 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>; 861def : Pat<(extloadi1 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>; 862def : Pat<(sextloadi8 AddrModeImm:$addr),(LDB_X_limm AddrModeImm:$addr)>; 863def : Pat<(sextloadi8 AddrModeFar:$addr),(LDB_X_rlimm AddrModeFar:$addr)>; 864def : Pat<(sextloadi8 AddrModeS9:$addr),(LDB_X_rs9 AddrModeS9:$addr)>; 865 866 867// Store instruction variants: 868// Control bits: aa, di, zz 869// aa - incrementing mode. (N/A for LIMM). 870// di - uncached. 871// zz - data size. 872multiclass ArcStInst<DataSizeMode zz, CacheMode di, string asmop> { 873 let mayStore = 1, ZZ = zz, DI = di in { 874 def _rs9: F32_ST_ADDR<NoAM.Value, di.Value, zz.Value, 875 (outs), (ins GPR32:$C, MEMrs9:$addr), 876 !strconcat(asmop, "\t$C, [$addr]"), []>, ArcLdStRel; 877 878 def _limm: F32_ST_LIMM<di.Value, zz.Value, 879 (outs), (ins GPR32:$C, MEMii:$addr), 880 !strconcat(asmop, "\t$C, [$addr]"), []>, ArcLdStRel; 881 882 883 foreach aa = [PreIncAM, PostIncAM] in { 884 def aa.InstSuffix#_rs9: F32_ST_RS9<aa.Value, di.Value, zz.Value, 885 (outs GPR32:$addrout), 886 (ins GPR32:$C, GPR32:$B, immS<9>:$S9), 887 asmop#aa.AsmSuffix#"\t$C, [$B,$S9]", []>, ArcLdStRel 888 { let Constraints = "$addrout = $B"; let AA = aa; } 889 } 890 } 891} 892 893foreach di = [NoCC, UncachedCC] in { 894 foreach zz = [ByteSM, HalfSM, WordSM] in { 895 defm ST#zz.InstSuffix#di.InstSuffix : ArcStInst<zz, di, "st"#zz.AsmSuffix#di.AsmSuffix>; 896 } 897} 898 899// Store instruction patterns. 900// 32-bit stores 901def : Pat<(store i32:$C, AddrModeS9:$addr), 902 (ST_rs9 i32:$C, AddrModeS9:$addr)>; 903def : Pat<(store i32:$C, AddrModeImm:$addr), 904 (ST_limm i32:$C, AddrModeImm:$addr)>; 905 906// 16-bit stores 907def : Pat<(truncstorei16 i32:$C, AddrModeS9:$addr), 908 (STH_rs9 i32:$C, AddrModeS9:$addr)>; 909def : Pat<(truncstorei16 i32:$C, AddrModeImm:$addr), 910 (STH_limm i32:$C, AddrModeImm:$addr)>; 911 912// 8-bit stores 913def : Pat<(truncstorei8 i32:$C, AddrModeS9:$addr), 914 (STB_rs9 i32:$C, AddrModeS9:$addr)>; 915def : Pat<(truncstorei8 i32:$C, AddrModeImm:$addr), 916 (STB_limm i32:$C, AddrModeImm:$addr)>; 917 918def getPostIncOpcode : InstrMapping { 919 let FilterClass = "ArcLdStRel"; 920 let RowFields = [ "BaseOpcode", "ZZ", "DI", "X"]; 921 let ColFields = [ "AA" ]; 922 let KeyCol = [ "NoAM" ]; 923 let ValueCols = [["PostIncAM"]]; 924} 925