Hi Richard.
> +(define_insn "mulsidi3" > + [(set (match_operand:DI 0 "register_operand" "=r,r") > + (sign_extend:DI > + (mult:SI (match_operand:SI 1 "register_operand" "0,0") > + (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))] > + "" > + "mul32\t%0,%2" > + [(set_attr "type" "alu32")]) Sorry, Segher was right and I was wrong: mulsidi3 is instead: [(set (match_operand:DI 0 "register_operand" "=r,r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0")) (sign_extend:DI (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))] i.e. extend the operands rather than the result. So the define_insn shouldn't be called mulsidi3 after all. Are you sure this is a sign extension though? From a quick look at the kernel sources, I got the impression it was a zero extension instead. You are right. This is from linux/kernel/bpf/core.c: #define ALU(OPCODE, OP) \ ALU64_##OPCODE##_X: \ DST = DST OP SRC; \ CONT; \ ALU_##OPCODE##_X: \ DST = (u32) DST OP (u32) SRC; \ CONT; \ ALU64_##OPCODE##_K: \ DST = DST OP IMM; \ CONT; \ ALU_##OPCODE##_K: \ DST = (u32) DST OP (u32) IMM; \ CONT; [...] ALU(MUL, *) So, mul32 zero-extends arguments and then multiplies, leaving the result in the 64-bit register. This is an unsigned widening multiplication, that according to the internal manuals should be handled with a pattern like: (define_insn "umulsidi3" [(set (match_operand:DI 0 "register_operand" "=r,r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "0,0")) (zero_extend:DI (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))] "" "mul32\t%0,%2" [(set_attr "type" "alu32")])