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
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.
;; 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"
(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")])
;;;; 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")
;; 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)))]
""
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 "";