]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
bpf: pseudo-c assembly dialect support
authorCupertino Miranda <cupertino.miranda@oracle.com>
Mon, 17 Jul 2023 16:42:42 +0000 (17:42 +0100)
committerCupertino Miranda <cupertino.miranda@oracle.com>
Fri, 21 Jul 2023 18:56:36 +0000 (19:56 +0100)
New pseudo-c BPF assembly dialect already supported by clang and widely
used in the linux kernel.

gcc/ChangeLog:

PR target/110770
* config/bpf/bpf.opt: Added option -masm=<dialect>.
* config/bpf/bpf-opts.h (enum bpf_asm_dialect): New type.
* config/bpf/bpf.cc (bpf_print_register): New function.
(bpf_print_register): Support pseudo-c syntax for registers.
(bpf_print_operand_address): Likewise.
* config/bpf/bpf.h (ASM_SPEC): handle -msasm.
(ASSEMBLER_DIALECT): Define.
* config/bpf/bpf.md: Added pseudo-c templates.
* doc/invoke.texi (-masm=): New eBPF option item.

gcc/config/bpf/bpf-opts.h
gcc/config/bpf/bpf.cc
gcc/config/bpf/bpf.h
gcc/config/bpf/bpf.md
gcc/config/bpf/bpf.opt
gcc/doc/invoke.texi

index 8282351cf045496f137d0d8c83bd00981eb9f4a9..92db01ec4d54d283e574f072b44f96f69131989b 100644 (file)
@@ -60,4 +60,10 @@ enum bpf_isa_version
   ISA_V3,
 };
 
+enum bpf_asm_dialect
+{
+  ASM_NORMAL,
+  ASM_PSEUDOC
+};
+
 #endif /* ! BPF_OPTS_H */
index e0324e1e0e08846e247c294b0f1cc8477502ef52..1d3936871d60b69d1efa47a95ef6a90e994587c4 100644 (file)
@@ -873,16 +873,47 @@ bpf_output_call (rtx target)
   return "";
 }
 
+/* Print register name according to assembly dialect.
+   In normal syntax registers are printed like %rN where N is the
+   register number.
+   In pseudoc syntax, the register names do not feature a '%' prefix.
+   Additionally, the code 'w' denotes that the register should be printed
+   as wN instead of rN, where N is the register number, but only when the
+   value stored in the operand OP is 32-bit wide.  */
+static void
+bpf_print_register (FILE *file, rtx op, int code)
+{
+  if(asm_dialect == ASM_NORMAL)
+    fprintf (file, "%s", reg_names[REGNO (op)]);
+  else
+    {
+      if (code == 'w' && GET_MODE (op) == SImode)
+       {
+         if (REGNO (op) == BPF_FP)
+           fprintf (file, "w10");
+         else
+           fprintf (file, "w%s", reg_names[REGNO (op)]+2);
+       }
+      else
+       {
+         if (REGNO (op) == BPF_FP)
+           fprintf (file, "r10");
+         else
+           fprintf (file, "%s", reg_names[REGNO (op)]+1);
+       }
+    }
+}
+
 /* Print an instruction operand.  This function is called in the macro
    PRINT_OPERAND defined in bpf.h */
 
 void
-bpf_print_operand (FILE *file, rtx op, int code ATTRIBUTE_UNUSED)
+bpf_print_operand (FILE *file, rtx op, int code)
 {
   switch (GET_CODE (op))
     {
     case REG:
-      fprintf (file, "%s", reg_names[REGNO (op)]);
+      bpf_print_register (file, op, code);
       break;
     case MEM:
       output_address (GET_MODE (op), XEXP (op, 0));
@@ -936,7 +967,9 @@ bpf_print_operand_address (FILE *file, rtx addr)
   switch (GET_CODE (addr))
     {
     case REG:
-      fprintf (file, "[%s+0]", reg_names[REGNO (addr)]);
+      fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
+      bpf_print_register (file, addr, 0);
+      fprintf (file, asm_dialect == ASM_NORMAL ? "+0]" : "+0)");
       break;
     case PLUS:
       {
@@ -945,9 +978,11 @@ bpf_print_operand_address (FILE *file, rtx addr)
 
        if (GET_CODE (op0) == REG && GET_CODE (op1) == CONST_INT)
          {
-           fprintf (file, "[%s+", reg_names[REGNO (op0)]);
+           fprintf (file, asm_dialect == ASM_NORMAL ? "[" : "(");
+           bpf_print_register (file, op0, 0);
+           fprintf (file, "+");
            output_addr_const (file, op1);
-           fputs ("]", file);
+           fprintf (file, asm_dialect == ASM_NORMAL ? "]" : ")");
          }
        else
          fatal_insn ("invalid address in operand", addr);
@@ -1816,7 +1851,6 @@ handle_attr_preserve (function *fn)
     }
 }
 
-
 /* This pass finds accesses to structures marked with the BPF target attribute
    __attribute__((preserve_access_index)). For every such access, a CO-RE
    relocation record is generated, to be output in the .BTF.ext section.  */
index 344aca02d1bb4dddac6a22b83426d5294c774f42..9561bf59b800324f99a978bcaf7372be63d5ec2d 100644 (file)
@@ -22,7 +22,8 @@
 
 /**** Controlling the Compilation Driver.  */
 
-#define ASM_SPEC "%{mbig-endian:-EB} %{!mbig-endian:-EL} %{mxbpf:-mxbpf}"
+#define ASM_SPEC "%{mbig-endian:-EB} %{!mbig-endian:-EL} %{mxbpf:-mxbpf} " \
+  "%{masm=pseudoc:-mdialect=pseudoc}"
 #define LINK_SPEC "%{mbig-endian:-EB} %{!mbig-endian:-EL}"
 #define LIB_SPEC ""
 #define STARTFILE_SPEC ""
@@ -503,4 +504,6 @@ enum reg_class
 #define DO_GLOBAL_DTORS_BODY                   \
   do { } while (0)
 
+#define ASSEMBLER_DIALECT ((int) asm_dialect)
+
 #endif /* ! GCC_BPF_H */
index adf11e151df12cdabb6f2b5429d530a656c3c9bf..80220f2ef37aaf2af0ff785fce7ac802607a83bc 100644 (file)
@@ -88,6 +88,8 @@
 
 (define_mode_attr mop [(QI "b") (HI "h") (SI "w") (DI "dw")
                        (SF "w") (DF "dw")])
+(define_mode_attr smop [(QI "u8") (HI "u16") (SI "u32") (DI "u64")
+                       (SF "u32") (DF "u64")])
 (define_mode_attr mtype [(SI "alu32") (DI "alu")])
 (define_mode_attr msuffix [(SI "32") (DI "")])
 
         (plus:AM (match_operand:AM 1 "register_operand"   " 0,0")
                  (match_operand:AM 2 "reg_or_imm_operand" " r,I")))]
   "1"
-  "add<msuffix>\t%0,%2"
+  "{add<msuffix>\t%0,%2|%w0 += %w1}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Subtraction
         (minus:AM (match_operand:AM 1 "register_operand" " 0")
                   (match_operand:AM 2 "register_operand" " r")))]
   ""
-  "sub<msuffix>\t%0,%2"
+  "{sub<msuffix>\t%0,%2|%w0 -= %w1}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Negation
 (define_insn "neg<AM:mode>2"
-  [(set (match_operand:AM         0 "register_operand" "=r,r")
-        (neg:AM (match_operand:AM 1 "register_operand" " r,I")))]
+  [(set (match_operand:AM         0 "register_operand"   "=r,r")
+        (neg:AM (match_operand:AM 1 "reg_or_imm_operand" " r,I")))]
   ""
-  "neg<msuffix>\t%0,%1"
+  "{neg<msuffix>\t%0,%1|%w0 = -%w1}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Multiplication
         (mult:AM (match_operand:AM 1 "register_operand"   " 0,0")
                  (match_operand:AM 2 "reg_or_imm_operand" " r,I")))]
   ""
-  "mul<msuffix>\t%0,%2"
+  "{mul<msuffix>\t%0,%2|%w0 *= %w2}"
   [(set_attr "type" "<mtype>")])
 
 (define_insn "*mulsidi3_zeroextend"
          (mult:SI (match_operand:SI 1 "register_operand" "0,0")
                   (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))]
   ""
-  "mul32\t%0,%2"
+  "{mul32\t%0,%2|%w0 *= %w2}"
   [(set_attr "type" "alu32")])
 
 ;;; Division
         (udiv:AM (match_operand:AM 1 "register_operand" " 0,0")
                  (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   ""
-  "div<msuffix>\t%0,%2"
+  "{div<msuffix>\t%0,%2|%w0 /= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;; However, xBPF does provide a signed division operator, sdiv.
         (div:AM (match_operand:AM 1 "register_operand" " 0,0")
                 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   "TARGET_XBPF"
-  "sdiv<msuffix>\t%0,%2"
+  "{sdiv<msuffix>\t%0,%2|%w0 s/= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Modulus
         (umod:AM (match_operand:AM 1 "register_operand" " 0,0")
                  (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   ""
-  "mod<msuffix>\t%0,%2"
+  "{mod<msuffix>\t%0,%2|%w0 %%= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;; Again, xBPF provides a signed version, smod.
         (mod:AM (match_operand:AM 1 "register_operand" " 0,0")
                 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   "TARGET_XBPF"
-  "smod<msuffix>\t%0,%2"
+  "{smod<msuffix>\t%0,%2|%w0 s%%= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Logical AND
         (and:AM (match_operand:AM 1 "register_operand" " 0,0")
                 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   ""
-  "and<msuffix>\t%0,%2"
+  "{and<msuffix>\t%0,%2|%w0 &= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Logical inclusive-OR
         (ior:AM (match_operand:AM 1 "register_operand" " 0,0")
                 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   ""
-  "or<msuffix>\t%0,%2"
+  "{or<msuffix>\t%0,%2|%w0 %|= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;; Logical exclusive-OR
         (xor:AM (match_operand:AM 1 "register_operand" " 0,0")
                 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
   ""
-  "xor<msuffix>\t%0,%2"
+  "{xor<msuffix>\t%0,%2|%w0 ^= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;;; Conversions
        (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "0,r,q")))]
   ""
   "@
-   and\t%0,0xffff
-   mov\t%0,%1\;and\t%0,0xffff
-   ldxh\t%0,%1"
+   {and\t%0,0xffff|%0 &= 0xffff}
+   {mov\t%0,%1\;and\t%0,0xffff|%0 = %1;%0 &= 0xffff}
+   {ldxh\t%0,%1|%0 = *(u16 *) %1}"
   [(set_attr "type" "alu,alu,ldx")])
 
 (define_insn "zero_extendqidi2"
        (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "0,r,q")))]
   ""
   "@
-   and\t%0,0xff
-   mov\t%0,%1\;and\t%0,0xff
-   ldxb\t%0,%1"
+   {and\t%0,0xff|%0 &= 0xff}
+   {mov\t%0,%1\;and\t%0,0xff|%0 = %1;%0 &= 0xff}
+   {ldxh\t%0,%1|%0 = *(u8 *) %1}"
   [(set_attr "type" "alu,alu,ldx")])
 
 (define_insn "zero_extendsidi2"
          (match_operand:SI 1 "nonimmediate_operand" "r,q")))]
   ""
   "@
-   * return bpf_has_alu32 ? \"mov32\t%0,%1\" : \"mov\t%0,%1\;and\t%0,0xffffffff\";
-   ldxw\t%0,%1"
+   * return bpf_has_alu32 ? \"{mov32\t%0,%1|%0 = %1}\" : \"{mov\t%0,%1\;and\t%0,0xffffffff|%0 = %1;%0 &= 0xffffffff}\";
+   {ldxw\t%0,%1|%0 = *(u32 *) %1}"
   [(set_attr "type" "alu,ldx")])
 
 ;;; Sign-extension
         (match_operand:MM 1 "mov_src_operand"      " q,rI,B,r,I"))]
   ""
   "@
-   ldx<mop>\t%0,%1
-   mov\t%0,%1
-   lddw\t%0,%1
-   stx<mop>\t%0,%1
-   st<mop>\t%0,%1"
+   {ldx<mop>\t%0,%1|%0 = *(<smop> *) %1}
+   {mov\t%0,%1|%0 = %1}
+   {lddw\t%0,%1|%0 = %1 ll}
+   {stx<mop>\t%0,%1|*(<smop> *) %0 = %1}
+   {st<mop>\t%0,%1|*(<smop> *) %0 = %1}"
 [(set_attr "type" "ldx,alu,alu,stx,st")])
 
 ;;;; Shifts
         (ashiftrt:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
                       (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
   ""
-  "arsh<msuffix>\t%0,%2"
+  "{arsh<msuffix>\t%0,%2|%w0 s>>= %w2}"
   [(set_attr "type" "<mtype>")])
 
 (define_insn "ashl<SIM:mode>3"
         (ashift:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
                     (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
   ""
-  "lsh<msuffix>\t%0,%2"
+  "{lsh<msuffix>\t%0,%2|%w0 <<= %w2}"
   [(set_attr "type" "<mtype>")])
 
 (define_insn "lshr<SIM:mode>3"
         (lshiftrt:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
                       (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
   ""
-  "rsh<msuffix>\t%0,%2"
+  "{rsh<msuffix>\t%0,%2|%w0 >>= %w2}"
   [(set_attr "type" "<mtype>")])
 
 ;;;; Endianness conversion
   ""
 {
   if (TARGET_BIG_ENDIAN)
-    return "endle\t%0, <endmode>";
+    return "{endle\t%0, <endmode>|%0 = le<endmode> %0}";
   else
-    return "endbe\t%0, <endmode>";
+    return "{endbe\t%0, <endmode>|%0 = be<endmode> %0}";
 }
   [(set_attr "type" "end")])
 
 
   switch (code)
   {
-  case EQ: return "jeq<msuffix>\t%0,%1,%2"; break;
-  case NE: return "jne<msuffix>\t%0,%1,%2"; break;
-  case LT: return "jslt<msuffix>\t%0,%1,%2"; break;
-  case LE: return "jsle<msuffix>\t%0,%1,%2"; break;
-  case GT: return "jsgt<msuffix>\t%0,%1,%2"; break;
-  case GE: return "jsge<msuffix>\t%0,%1,%2"; break;
-  case LTU: return "jlt<msuffix>\t%0,%1,%2"; break;
-  case LEU: return "jle<msuffix>\t%0,%1,%2"; break;
-  case GTU: return "jgt<msuffix>\t%0,%1,%2"; break;
-  case GEU: return "jge<msuffix>\t%0,%1,%2"; break;
+  case EQ: return  "{jeq<msuffix>\t%0,%1,%2|if %w0 == %w1 goto %2}"; break;
+  case NE: return  "{jne<msuffix>\t%0,%1,%2|if %w0 != %w1 goto %2}"; break;
+  case LT: return  "{jslt<msuffix>\t%0,%1,%2|if %w0 s< %w1 goto %2}"; break;
+  case LE: return  "{jsle<msuffix>\t%0,%1,%2|if %w0 s<= %w1 goto %2}"; break;
+  case GT: return  "{jsgt<msuffix>\t%0,%1,%2|if %w0 s> %w1 goto %2}"; break;
+  case GE: return  "{jsge<msuffix>\t%0,%1,%2|if %w0 s>= %w1 goto %2}"; break;
+  case LTU: return "{jlt<msuffix>\t%0,%1,%2|if %w0 < %w1 goto %2}"; break;
+  case LEU: return "{jle<msuffix>\t%0,%1,%2|if %w0 <= %w1 goto %2}"; break;
+  case GTU: return "{jgt<msuffix>\t%0,%1,%2|if %w0 > %w1 goto %2}"; break;
+  case GEU: return "{jge<msuffix>\t%0,%1,%2|if %w0 >= %w1 goto %2}"; break;
   default:
     gcc_unreachable ();
     return "";
   [(set (pc)
         (label_ref (match_operand 0 "" "")))]
   ""
-  "ja\t%0"
+  "{ja\t%0|goto %0}"
 [(set_attr "type" "jmp")])
 
 ;;;; Function prologue/epilogue
   ;; operands[2] is next_arg_register
   ;; operands[3] is struct_value_size_rtx.
   ""
-  "ja\t%0"
+  "{ja\t%0|goto %0}"
   [(set_attr "type" "jmp")])
 
 ;;;; Non-generic load instructions
 
 (define_mode_iterator LDM [QI HI SI DI])
 (define_mode_attr ldop [(QI "b") (HI "h") (SI "w") (DI "dw")])
+(define_mode_attr pldop [(QI "u8") (HI "u16") (SI "u32") (DI "u64")])
 
 (define_insn "ldind<ldop>"
   [(set (reg:LDM R0_REGNUM)
    (clobber (reg:DI R3_REGNUM))
    (clobber (reg:DI R4_REGNUM))]
   ""
-  "ldind<ldop>\t%0,%1"
+  "{ldind<ldop>\t%0,%1|r0 = *(<pldop> *) skb[%0 + %1]}"
   [(set_attr "type" "ld")])
 
 (define_insn "ldabs<ldop>"
    (clobber (reg:DI R3_REGNUM))
    (clobber (reg:DI R4_REGNUM))]
   ""
-  "ldabs<ldop>\t%0"
+  "{ldabs<ldop>\t%0|r0 = *(<pldop> *) skb[%0]}"
   [(set_attr "type" "ld")])
 
 ;;;; Atomic increments
           (match_operand:SI 2 "const_int_operand")] ;; Memory model.
          UNSPEC_XADD))]
   ""
-  "xadd<mop>\t%0,%1"
+  "{xadd<mop>\t%0,%1|*(<smop> *) %0 += %1}"
   [(set_attr "type" "xadd")])
index fe3ad355e4bd749c63e8227631b7474748f07367..ff805f9e083cd0da6eaba9e7d6f60db97bac6695 100644 (file)
@@ -160,3 +160,17 @@ Enum(bpf_isa) String(v2) Value(ISA_V2)
 
 EnumValue
 Enum(bpf_isa) String(v3) Value(ISA_V3)
+
+masm=
+Target RejectNegative Joined Var(asm_dialect) Enum(asm_dialect) Init(ASM_NORMAL)
+Use given assembler dialect.
+
+Enum
+Name(asm_dialect) Type(enum bpf_asm_dialect)
+Known assembler dialects (for use with the -masm= option)
+
+EnumValue
+Enum(asm_dialect) String(normal) Value(ASM_NORMAL)
+
+EnumValue
+Enum(asm_dialect) String(pseudoc) Value(ASM_PSEUDOC)
index 5628c08214d3bad69324bfa55825803f1a28de0f..efd356e7ef69dcae96bd84a1690b0609aa711531 100644 (file)
@@ -946,8 +946,8 @@ Objective-C and Objective-C++ Dialects}.
 
 @emph{eBPF Options}
 @gccoptlist{-mbig-endian -mlittle-endian -mkernel=@var{version}
--mframe-limit=@var{bytes} -mxbpf -mco-re -mno-co-re
--mjmpext -mjmp32 -malu32 -mcpu=@var{version}}
+-mframe-limit=@var{bytes} -mxbpf -mco-re -mno-co-re -mjmpext
+-mjmp32 -malu32 -mcpu=@var{version} -masm=@var{dialect}}
 
 @emph{FR30 Options}
 @gccoptlist{-msmall-model  -mno-lsim}
@@ -24748,6 +24748,23 @@ the restrictions imposed by the BPF architecture:
 @item Save and restore callee-saved registers at function entry and
 exit, respectively.
 @end itemize
+
+@opindex masm=@var{dialect}
+@item -masm=@var{dialect}
+Outputs assembly instructions using eBPF selected @var{dialect}.  The default
+is @samp{normal}.
+
+Supported values for @var{dialect} are:
+
+@table @samp
+@item normal
+Outputs normal assembly dialect.
+
+@item pseudoc
+Outputs pseudo-c assembly dialect.
+
+@end table
+
 @end table
 
 @node FR30 Options