Why should I know this?

[AArch64] STR (STRroX, STRXui) 본문

LLVM-STUDY/MIR

[AArch64] STR (STRroX, STRXui)

die4taoam 2024. 6. 20. 09:19

Store IR 원형

store [volatile] <ty> <value>, ptr <pointer>
[, align <alignment>][, !nontemporal !<nontemp_node>][, !invariant.group !<empty_node>]; yields void
store atomic [volatile] <ty> <value>, ptr <pointer> [syncscope("<target-scope>")] <ordering>, align <alignment> 
[, !invariant.group !<empty_node>] ; yields void
!<nontemp_node> = !{ i32 1 }
!<empty_node> = !{}

STRroX, STRroW

STR(register)

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 x 1 1 1 0 0 0 0 0 1 Rm option S 1 0 Rn Rt
size       opc              

 

STRroX, STRroW 예시

str x0, [x9, x8, lsl #3]

storeop Ty regtype:$Rt ro_Windexed64 GPR64sp:$Rn GPR32:$Rm ro_Wextend64:$extend
str x2 x0 w1  lsl #3
  regtype:$Rt GPR64sp:$Rn GPR32:$Rm ro_Wextend64:$extend

 

 

defm STRX  : Store64RO<0b11, 0, 0b00, GPR64, "str",  i64, store>;

 

multiclass Store64RO<bits<2> sz, bit V, bits<2> opc, DAGOperand regtype,
                     string asm, ValueType Ty, SDPatternOperator storeop> {
  let AddedComplexity = 10, mayLoad = 0, mayStore = 1, hasSideEffects = 0 in
  def roW : LoadStore64RO<sz, V, opc, asm, (outs),
                (ins regtype:$Rt, GPR64sp:$Rn, GPR32:$Rm, ro_Wextend64:$extend),
                [(storeop (Ty regtype:$Rt),
                          (ro_Windexed64 GPR64sp:$Rn, GPR32:$Rm,
                                         ro_Wextend64:$extend))]>,
            Sched<[WriteSTIdx, ReadST, ReadAdrBase]> {
    let Inst{13} = 0b0;
  }

  let AddedComplexity = 10, mayLoad = 0, mayStore = 1, hasSideEffects = 0 in
  def roX : LoadStore64RO<sz, V, opc, asm, (outs),
                (ins regtype:$Rt, GPR64sp:$Rn, GPR64:$Rm, ro_Xextend64:$extend),
                [(storeop (Ty regtype:$Rt),
                          (ro_Xindexed64 GPR64sp:$Rn, GPR64:$Rm,
                                         ro_Xextend64:$extend))]>,
            Sched<[WriteSTIdx, ReadST, ReadAdrBase]> {
    let Inst{13} = 0b1;
  }

  def : ROInstAlias<asm, regtype, !cast<Instruction>(NAME # "roX")>;
}

 

class LoadStore64RO<bits<2> sz, bit V, bits<2> opc, string asm, dag ins,
                    dag outslist<dag> pat>
    : I<insouts, asm, "\t$Rt, [$Rn, $Rm, $extend]", "", pat> {
  bits<5> Rt;
  bits<5> Rn;
  bits<5> Rm;
  bits<2> extend;
  let Inst{31-30} = sz;
  let Inst{29-27} = 0b111;
  let Inst{26}    = V;
  let Inst{25-24} = 0b00;
  let Inst{23-22} = opc;
  let Inst{21}    = 1;
  let Inst{20-16} = Rm;

option<extend>
010 UXTW
011 LSL
110 SXTW
111 SXTX

  (아래 옵션 FLAG를 Setting하는 의미, {15} 는 Signed여부, Inst{14}는 32bit이상이기 때문에 항상 1 )

  let Inst{15}    = extend{1}; // sign extend Rm?
  let Inst{14}    = 1;

 

(inst{13} 은 이전에 설정했다.  let Inst{13} = 0b1; 32bit 는 0 64bit는 1)

(Inst{12) : extend가 LSL 이 아닌 경우 shift amount 정의 32bit (0:#0 1:#2->4의 배수) 64bit (0:#0, 1:#3->8의 배수)

  let Inst{12}    = extend{0}; // do shift?

  let Inst{11-10} = 0b10;
  let Inst{9-5}   = Rn;
  let Inst{4-0}   = Rt;
}

 

// Normal instructions
class I<dag oops, dag iops, string asm, string operands, string cstr,
        list<dag> pattern>
    : EncodedI<cstr, pattern> {
  dag OutOperandList = oops;
  dag InOperandList  = iops;
  let AsmString      = !strconcat(asm, operands);
}

 

oops (outs)
iops (ins regtype:$Rt, GPR64sp:$Rn, GPR64:$Rm, ro_Xextend64:$extend)
Pattern :  [(storeop 
        (Ty regtype:$Rt),

        (ro_Xindexed64 GPR64sp:$Rn, GPR64:$Rm, ro_Xextend64:$extend))]

 


STRXui STRWui

STR (immediate)

Unsigned offset

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 x 1 1 1 0 0 1 0 0 imm12 Rn Rt
size   VR   opc  

 

STRXui 예시

STRXui killed renamable $x8, killed renamable $x0, 31

  GPR64:$val GPR64sp:$Rn uimm12s8:$offset
STRXui killed renamable $x8 killed renamable $x0 31
  GPR64:$val am_indexed64 GPR64sp:$Rn uimm12s8:$offset

 

 

 

// An atomic store operation that doesn't actually need to be atomic on AArch64.
class relaxed_store<PatFrag base>
  : PatFrag<(ops node:$ptr, node:$val), (base node:$val, node:$ptr)> {
  let IsAtomic = 1;
  let IsAtomicOrderingReleaseOrStronger = 0;
}

 

def : Pat<(relaxed_store<atomic_store_64>
              (am_indexed64 GPR64sp:$Rn, uimm12s8:$offset), GPR64:$val),
          (STRXui GPR64:$val, GPR64sp:$Rn, uimm12s8:$offset)>;

 

 

ARM Develeoper manual에 기재된 offset 계산법.

boolean wback = FALSE;
boolean postindex = FALSE;
integer scale = UInt(size);
bits(64) offset = LSL(ZeroExtend(imm12, 64), scale);

 

여기서 size 는 3이므로 scale=3이다. (위 MIR 참고)

imm12 에 설정 가능한 최대값 4095 이고, 이를 기준으로 64비트라면 << 3 된 #32760 이 지정가능한 최대오프셋이 된다.

왜 scale 을 하는지는 ARM 계열의 주소지정모드의 특징을 알아보면 된다.

 

만약 이 범위를 벗어난 값을 MIR 에 설정하면 clang은 다음과 같은 에러를 낸다.

error: index must be an integer in range [-256, 255]

 

원인은 다음처럼 operand mismatch가 되기 때문...

Trying to match opcode STRXui
  Matching formal operand class MCK_GPR64 against actual operand at index 1 (<register 244>): match success using generic matcher
  Matching formal operand class MCK__91_ against actual operand at index 2 ('['): match success using generic matcher
  Matching formal operand class MCK_GPR64sp against actual operand at index 3 (<register 236>): match success using generic matcher
  Matching formal operand class MCK_UImm12Offset8 against actual operand at index 4 (32768): Opcode result: multiple operand mismatches, ignoring this opcode

 

Matching 을 찾다가 마지막에 찾지 못한 경우로 에러를 내기 때문에 위와 같은 에러가 난다.

STRXui는 12bit Unsigned Offset 을 가질 수 있으므로 최대 12bit까지 값을 허용할 수 있다.

; STRXui killed %1:gpr64, killed %0:gpr64common, 4095
0000000000000000 <ltmp0>:
       0: d28acf08     	mov	x8, #22136
       4: f2a24688     	movk	x8, #4660, lsl #16
       8: aa088108     	orr	x8, x8, x8, lsl #32
       c: f93ffc08     	str	x8, [x0, #32760]
      10: d65f03c0     	ret

 

 

PatFag

llvm/utils/TableGen/Common/GlobalISel/Patterns.h

class PatFrag {
public:
  static constexpr StringLiteral ClassName = "GICombinePatFrag";

'LLVM-STUDY > MIR' 카테고리의 다른 글

LESSONS IN TABLEGEN  (0) 2024.06.21
[AArch64] LDR (LDRroX, LDRXui)  (0) 2024.04.16
[AArch64] STPX  (0) 2024.03.18
Comments