@@ -53,4 +53,11 @@ enum bpf_kernel_version
LINUX_NATIVE,
};
+enum bpf_isa_version
+{
+ ISA_V1,
+ ISA_V2,
+ ISA_V3,
+};
+
#endif /* ! BPF_OPTS_H */
@@ -29,6 +29,7 @@ extern void bpf_print_operand (FILE *, rtx, int);
extern void bpf_print_operand_address (FILE *, rtx);
extern void bpf_expand_prologue (void);
extern void bpf_expand_epilogue (void);
+extern void bpf_expand_cbranch (machine_mode, rtx *);
rtl_opt_pass * make_pass_bpf_core_attr (gcc::context *);
@@ -242,6 +242,17 @@ bpf_option_override (void)
target_flags |= MASK_BPF_CORE;
write_symbols |= BTF_WITH_CORE_DEBUG;
}
+
+ /* Determine available features from ISA setting (-mcpu=). */
+ if (bpf_has_jmpext == -1)
+ bpf_has_jmpext = (bpf_isa >= ISA_V2);
+
+ if (bpf_has_alu32 == -1)
+ bpf_has_alu32 = (bpf_isa >= ISA_V3);
+
+ if (bpf_has_jmp32 == -1)
+ bpf_has_jmp32 = (bpf_isa >= ISA_V3);
+
}
#undef TARGET_OPTION_OVERRIDE
@@ -540,6 +551,36 @@ bpf_expand_epilogue (void)
emit_jump_insn (gen_exit ());
}
+/* Expand to the instructions for a conditional branch. This function
+ is called when expanding the 'cbranch<mode>4' pattern in bpf.md. */
+
+void
+bpf_expand_cbranch (machine_mode mode, rtx *operands)
+{
+ /* If all jump instructions are available, nothing special to do here. */
+ if (bpf_has_jmpext)
+ return;
+
+ enum rtx_code code = GET_CODE (operands[0]);
+
+ /* Without the conditional branch instructions jslt, jsle, jlt, jle, we need
+ to convert conditional branches that would use them to an available
+ operation instead by reversing the comparison. */
+ if ((code == LT || code == LE || code == LTU || code == LEU))
+ {
+ /* Reverse the condition. */
+ PUT_CODE (operands[0], reverse_condition (code));
+
+ /* Swap the operands, and ensure that the first is a register. */
+ if (!register_operand (operands[2], mode))
+ operands[2] = force_reg (mode, operands[2]);
+
+ rtx tmp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = tmp;
+ }
+}
+
/* Return the initial difference between the specified pair of
registers. The registers that can figure in FROM, and TO, are
specified by ELIMINABLE_REGS in bpf.h.
@@ -100,9 +100,9 @@
;; insns, with the proper modes.
;;
;; 32-bit arithmetic (for SI modes) is implemented using the alu32
-;; instructions.
+;; instructions, if available.
-(define_mode_iterator AM [SI DI])
+(define_mode_iterator AM [(SI "bpf_has_alu32") DI])
;;; Addition
(define_insn "add<AM:mode>3"
@@ -264,7 +264,7 @@
(match_operand:SI 1 "nonimmediate_operand" "r,m")))]
""
"@
- mov32\t%0,%1
+ * return bpf_has_alu32 ? \"mov32\t%0,%1\" : \"mov\t%0,%1\;and\t%0,0xffffffff\";
ldxw\t%0,%1"
[(set_attr "type" "alu,ldx")])
@@ -313,7 +313,7 @@
;;;; Shifts
-(define_mode_iterator SIM [SI DI])
+(define_mode_iterator SIM [(SI "bpf_has_alu32") DI])
(define_insn "ashr<SIM:mode>3"
[(set (match_operand:SIM 0 "register_operand" "=r,r")
@@ -344,24 +344,28 @@
;; The eBPF jump instructions use 64-bit arithmetic when evaluating
;; the jump conditions. Therefore we use DI modes below.
-(define_expand "cbranchdi4"
+(define_mode_iterator JM [(SI "bpf_has_jmp32") DI])
+
+(define_expand "cbranch<JM:mode>4"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
- [(match_operand:DI 1 "register_operand")
- (match_operand:DI 2 "reg_or_imm_operand")])
+ [(match_operand:JM 1 "register_operand")
+ (match_operand:JM 2 "reg_or_imm_operand")])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
{
if (!ordered_comparison_operator (operands[0], VOIDmode))
FAIL;
+
+ bpf_expand_cbranch (<JM:MODE>mode, operands);
})
-(define_insn "*branch_on_di"
+(define_insn "*branch_on_<JM:mode>"
[(set (pc)
(if_then_else (match_operator 3 "ordered_comparison_operator"
- [(match_operand:DI 0 "register_operand" "r")
- (match_operand:DI 1 "reg_or_imm_operand" "rI")])
+ [(match_operand:JM 0 "register_operand" "r")
+ (match_operand:JM 1 "reg_or_imm_operand" "rI")])
(label_ref (match_operand 2 "" ""))
(pc)))]
""
@@ -370,16 +374,16 @@
switch (code)
{
- case EQ: return "jeq\t%0,%1,%2"; break;
- case NE: return "jne\t%0,%1,%2"; break;
- case LT: return "jslt\t%0,%1,%2"; break;
- case LE: return "jsle\t%0,%1,%2"; break;
- case GT: return "jsgt\t%0,%1,%2"; break;
- case GE: return "jsge\t%0,%1,%2"; break;
- case LTU: return "jlt\t%0,%1,%2"; break;
- case LEU: return "jle\t%0,%1,%2"; break;
- case GTU: return "jgt\t%0,%1,%2"; break;
- case GEU: return "jge\t%0,%1,%2"; break;
+ 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;
default:
gcc_unreachable ();
return "";
@@ -131,3 +131,32 @@ Set a hard limit for the size of each stack frame, in bytes.
mco-re
Target Mask(BPF_CORE)
Generate all necessary information for BPF Compile Once - Run Everywhere.
+
+; Selecting BPF ISA features and versions
+
+mjmpext
+Target Var(bpf_has_jmpext) Init(-1)
+Enable extra conditional-branch instructions j(s)lt and j(s)le.
+
+malu32
+Target Var(bpf_has_alu32) Init(-1)
+Enable 32-bit ALU instructions.
+
+mjmp32
+Target Var(bpf_has_jmp32) Init(-1)
+Enable 32-bit jump instructions.
+
+mcpu=
+Target RejectNegative Joined Var(bpf_isa) Enum(bpf_isa) Init(ISA_V3)
+
+Enum
+Name(bpf_isa) Type(enum bpf_isa_version)
+
+EnumValue
+Enum(bpf_isa) String(v1) Value(ISA_V1)
+
+EnumValue
+Enum(bpf_isa) String(v2) Value(ISA_V2)
+
+EnumValue
+Enum(bpf_isa) String(v3) Value(ISA_V3)