@@ -64,6 +64,7 @@ def SBFCallxSrc : Predicate<"Subtarget->getCallXRegSrc()">, AssemblerPredicate<(
6464def SBFNoCallxSrc : Predicate<"!Subtarget->getCallXRegSrc()">;
6565def SBFPqrInstr : Predicate<"Subtarget->getHasPqrClass()">;
6666def SBFNoPqrInstr : Predicate<"!Subtarget->getHasPqrClass()">;
67+ def SBFHasStoreImm : Predicate<"Subtarget->getHasStoreImm()">;
6768
6869def brtarget : Operand<OtherVT> {
6970 let PrintMethod = "printBrTargetOperand";
@@ -74,10 +75,18 @@ def u64imm : Operand<i64> {
7475 let PrintMethod = "printImm64Operand";
7576}
7677
78+ def gpr_or_imm : Operand<i64>;
79+
7780def i64immSExt32 : PatLeaf<(i64 imm),
7881 [{return isInt<32>(N->getSExtValue()); }]>;
7982def i32immSExt32 : PatLeaf<(i32 imm),
8083 [{return isInt<32>(N->getSExtValue()); }]>;
84+ def i64immZExt32 : PatLeaf<(i64 imm),
85+ [{return isUInt<32>(N->getZExtValue()); }]>;
86+
87+ def imm_to_i64 : SDNodeXForm<timm, [{
88+ return CurDAG->getTargetConstant(N->getZExtValue(), SDLoc(N), MVT::i64);
89+ }]>;
8190
8291// Fetch the upper 32-bits of a 64-bit integer.
8392def Upper32 : SDNodeXForm<imm, [{
@@ -469,7 +478,7 @@ class STORE<SBFWidthModifer SizeOp, string Mnemonic, list<dag> Pattern>
469478}
470479
471480class STOREi64<SBFWidthModifer Opc, string Mnemonic, PatFrag OpNode>
472- : STORE<Opc, Mnemonic, [(OpNode i64 :$src, ADDRri:$addr)]>;
481+ : STORE<Opc, Mnemonic, [(OpNode GPR :$src, ADDRri:$addr)]>;
473482
474483let Predicates = [SBFNoALU32] in {
475484 def STW : STOREi64<SBF_W, "stxw", truncstorei32>;
@@ -478,6 +487,49 @@ let Predicates = [SBFNoALU32] in {
478487}
479488def STD : STOREi64<SBF_DW, "stxdw", store>;
480489
490+ class STORE_imm<SBFWidthModifer SizeOp,
491+ string Mnemonic, dag Pattern>
492+ : TYPE_LD_ST<SBF_MEM.Value, SizeOp.Value,
493+ (outs),
494+ (ins i64imm:$imm, MEMri:$addr),
495+ Mnemonic # " [$addr], $imm",
496+ [Pattern]> {
497+ bits<20> addr;
498+ bits<32> imm;
499+ let Inst{51-48} = addr{19-16}; // base reg
500+ let Inst{47-32} = addr{15-0}; // offset
501+ let Inst{31-0} = imm;
502+ let SBFClass = SBF_ST;
503+ }
504+
505+ // Opcode (SBF_ST | SBF_MEM | SBF_DW) implies sign extension for
506+ // value stored to memory:
507+ // - it is fine to generate such write when immediate is -1
508+ // - it is incorrect to generate such write when immediate is
509+ // +0xffff_ffff.
510+ //
511+ // In the latter case two instructions would be generated instead of
512+ // one BPF_ST:
513+ // lddw rA, 0xffffffff
514+ // stx [rb], rA
515+ //
516+ // For SBF_{B,H,W} the size of value stored matches size of the immediate.
517+ let Predicates = [SBFHasStoreImm] in {
518+ def STD_imm : STORE_imm<SBF_DW, "stdw", (store (i64 i64immSExt32:$imm), ADDRri:$addr)>;
519+ def STW_imm : STORE_imm<SBF_W, "stw", (truncstorei32 (i64 i64immZExt32:$imm), ADDRri:$addr)>;
520+ def STH_imm : STORE_imm<SBF_H, "sth", (truncstorei16 (i64 i64immZExt32:$imm), ADDRri:$addr)>;
521+ def STB_imm : STORE_imm<SBF_B, "stb", (truncstorei8 (i64 i64immZExt32:$imm), ADDRri:$addr)>;
522+ }
523+
524+ let Predicates = [SBFHasALU32, SBFHasStoreImm] in {
525+ def : Pat<(store (i32 imm:$src), ADDRri:$dst),
526+ (STW_imm (imm_to_i64 $src), ADDRri:$dst)>;
527+ def : Pat<(truncstorei16 (i32 imm:$src), ADDRri:$dst),
528+ (STH_imm (imm_to_i64 imm:$src), ADDRri:$dst)>;
529+ def : Pat<(truncstorei8 (i32 imm:$src), ADDRri:$dst),
530+ (STB_imm (imm_to_i64 imm:$src), ADDRri:$dst)>;
531+ }
532+
481533// LOAD instructions
482534class LOAD<SBFWidthModifer SizeOp, string Mnemonic, list<dag> Pattern>
483535 : TYPE_LD_ST<SBF_MEM.Value, SizeOp.Value,
@@ -498,16 +550,21 @@ class LOADi64<SBFWidthModifer SizeOp, string Mnemonic, PatFrag OpNode>
498550 : LOAD<SizeOp, Mnemonic, [(set i64:$dst, (OpNode ADDRri:$addr))]>;
499551
500552let isCodeGenOnly = 1 in {
501- def CORE_MEM : TYPE_LD_ST<SBF_MEM.Value, SBF_W.Value,
502- (outs GPR:$dst),
553+ class CORE_LD<RegisterClass RegClass, string Sz>
554+ : TYPE_LD_ST<SBF_MEM.Value, SBF_W.Value,
555+ (outs RegClass:$dst),
503556 (ins u64imm:$opcode, GPR:$src, u64imm:$offset),
504- "$dst = core_mem ($opcode, $src, $offset)",
557+ "$dst = core_ld"#Sz#" ($opcode, $src, $offset)",
505558 []>;
506- def CORE_ALU32_MEM : TYPE_LD_ST<SBF_MEM.Value, SBF_W.Value,
507- (outs GPR32:$dst),
508- (ins u64imm:$opcode, GPR:$src, u64imm:$offset),
509- "$dst = core_alu32_mem($opcode, $src, $offset)",
510- []>;
559+
560+ def CORE_LD64 : CORE_LD<GPR, "64">;
561+ def CORE_LD32 : CORE_LD<GPR32, "32">;
562+
563+ def CORE_ST : TYPE_LD_ST<SBF_MEM.Value, SBF_W.Value,
564+ (outs),
565+ (ins gpr_or_imm:$src, u64imm:$opcode, GPR:$ptr, u64imm:$offset),
566+ "core_st($src, $opcode, $ptr, $offset)",
567+ []>;
511568 let Constraints = "$dst = $src" in {
512569 def CORE_SHIFT : MATH_RR<SBF_ALU64, SBF_LSH,
513570 (outs GPR:$dst),
@@ -996,7 +1053,7 @@ class STORE32<SBFWidthModifer SizeOp, string Mnemonic, list<dag> Pattern>
9961053}
9971054
9981055class STOREi32<SBFWidthModifer Opc, string Mnemonic, PatFrag OpNode>
999- : STORE32<Opc, Mnemonic, [(OpNode i32 :$src, ADDRri:$addr)]>;
1056+ : STORE32<Opc, Mnemonic, [(OpNode GPR32 :$src, ADDRri:$addr)]>;
10001057
10011058let Predicates = [SBFHasALU32], DecoderNamespace = "SBFALU32" in {
10021059 def STW32 : STOREi32<SBF_W, "stxw", store>;
0 commit comments