Merge pull request #2187 from akirilov-arm/ALUOp3

AArch64: Introduce an enum for ternary integer operations
This commit is contained in:
Chris Fallin
2020-09-08 12:57:59 -07:00
committed by GitHub
4 changed files with 47 additions and 66 deletions

View File

@@ -502,16 +502,8 @@ impl MachInstEmit for Inst {
ALUOp::UDiv64 => 0b10011010_110, ALUOp::UDiv64 => 0b10011010_110,
ALUOp::RotR32 | ALUOp::Lsr32 | ALUOp::Asr32 | ALUOp::Lsl32 => 0b00011010_110, ALUOp::RotR32 | ALUOp::Lsr32 | ALUOp::Asr32 | ALUOp::Lsl32 => 0b00011010_110,
ALUOp::RotR64 | ALUOp::Lsr64 | ALUOp::Asr64 | ALUOp::Lsl64 => 0b10011010_110, ALUOp::RotR64 | ALUOp::Lsr64 | ALUOp::Asr64 | ALUOp::Lsl64 => 0b10011010_110,
ALUOp::SMulH => 0b10011011_010,
ALUOp::MAdd32 ALUOp::UMulH => 0b10011011_110,
| ALUOp::MAdd64
| ALUOp::MSub32
| ALUOp::MSub64
| ALUOp::SMulH
| ALUOp::UMulH => {
//// RRRR ops.
panic!("Bad ALUOp {:?} in RRR form!", alu_op);
}
}; };
let bit15_10 = match alu_op { let bit15_10 = match alu_op {
ALUOp::SDiv64 => 0b000011, ALUOp::SDiv64 => 0b000011,
@@ -521,6 +513,7 @@ impl MachInstEmit for Inst {
ALUOp::Asr32 | ALUOp::Asr64 => 0b001010, ALUOp::Asr32 | ALUOp::Asr64 => 0b001010,
ALUOp::Lsl32 | ALUOp::Lsl64 => 0b001000, ALUOp::Lsl32 | ALUOp::Lsl64 => 0b001000,
ALUOp::SubS64XR => 0b011000, ALUOp::SubS64XR => 0b011000,
ALUOp::SMulH | ALUOp::UMulH => 0b011111,
_ => 0b000000, _ => 0b000000,
}; };
debug_assert_ne!(writable_stack_reg(), rd); debug_assert_ne!(writable_stack_reg(), rd);
@@ -541,13 +534,10 @@ impl MachInstEmit for Inst {
ra, ra,
} => { } => {
let (top11, bit15) = match alu_op { let (top11, bit15) = match alu_op {
ALUOp::MAdd32 => (0b0_00_11011_000, 0), ALUOp3::MAdd32 => (0b0_00_11011_000, 0),
ALUOp::MSub32 => (0b0_00_11011_000, 1), ALUOp3::MSub32 => (0b0_00_11011_000, 1),
ALUOp::MAdd64 => (0b1_00_11011_000, 0), ALUOp3::MAdd64 => (0b1_00_11011_000, 0),
ALUOp::MSub64 => (0b1_00_11011_000, 1), ALUOp3::MSub64 => (0b1_00_11011_000, 1),
ALUOp::SMulH => (0b1_00_11011_010, 0),
ALUOp::UMulH => (0b1_00_11011_110, 0),
_ => unimplemented!("{:?}", alu_op),
}; };
sink.put4(enc_arith_rrrr(top11, rm, bit15, ra, rn, rd)); sink.put4(enc_arith_rrrr(top11, rm, bit15, ra, rn, rd));
} }
@@ -1005,7 +995,7 @@ impl MachInstEmit for Inst {
} }
} }
} }
&Inst::Mov { rd, rm } => { &Inst::Mov64 { rd, rm } => {
assert!(rd.to_reg().get_class() == rm.get_class()); assert!(rd.to_reg().get_class() == rm.get_class());
assert!(rm.get_class() == RegClass::I64); assert!(rm.get_class() == RegClass::I64);

View File

@@ -789,7 +789,7 @@ fn test_aarch64_binemit() {
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRRR {
alu_op: ALUOp::MAdd32, alu_op: ALUOp3::MAdd32,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
@@ -800,7 +800,7 @@ fn test_aarch64_binemit() {
)); ));
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRRR {
alu_op: ALUOp::MAdd64, alu_op: ALUOp3::MAdd64,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
@@ -811,7 +811,7 @@ fn test_aarch64_binemit() {
)); ));
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRRR {
alu_op: ALUOp::MSub32, alu_op: ALUOp3::MSub32,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
@@ -822,7 +822,7 @@ fn test_aarch64_binemit() {
)); ));
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRRR {
alu_op: ALUOp::MSub64, alu_op: ALUOp3::MSub64,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
@@ -832,23 +832,21 @@ fn test_aarch64_binemit() {
"msub x1, x2, x3, x4", "msub x1, x2, x3, x4",
)); ));
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRR {
alu_op: ALUOp::SMulH, alu_op: ALUOp::SMulH,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
ra: zero_reg(),
}, },
"417C439B", "417C439B",
"smulh x1, x2, x3", "smulh x1, x2, x3",
)); ));
insns.push(( insns.push((
Inst::AluRRRR { Inst::AluRRR {
alu_op: ALUOp::UMulH, alu_op: ALUOp::UMulH,
rd: writable_xreg(1), rd: writable_xreg(1),
rn: xreg(2), rn: xreg(2),
rm: xreg(3), rm: xreg(3),
ra: zero_reg(),
}, },
"417CC39B", "417CC39B",
"umulh x1, x2, x3", "umulh x1, x2, x3",
@@ -1654,7 +1652,7 @@ fn test_aarch64_binemit() {
)); ));
insns.push(( insns.push((
Inst::Mov { Inst::Mov64 {
rd: writable_xreg(8), rd: writable_xreg(8),
rm: xreg(9), rm: xreg(9),
}, },

View File

@@ -73,14 +73,6 @@ pub enum ALUOp {
SubS64, SubS64,
/// Sub, setting flags, using extended registers /// Sub, setting flags, using extended registers
SubS64XR, SubS64XR,
/// Multiply-add
MAdd32,
/// Multiply-add
MAdd64,
/// Multiply-sub
MSub32,
/// Multiply-sub
MSub64,
/// Signed multiply, high-word result /// Signed multiply, high-word result
SMulH, SMulH,
/// Unsigned multiply, high-word result /// Unsigned multiply, high-word result
@@ -97,6 +89,19 @@ pub enum ALUOp {
Lsl64, Lsl64,
} }
/// An ALU operation with three arguments.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ALUOp3 {
/// Multiply-add
MAdd32,
/// Multiply-add
MAdd64,
/// Multiply-sub
MSub32,
/// Multiply-sub
MSub64,
}
/// A floating-point unit (FPU) operation with one arg. /// A floating-point unit (FPU) operation with one arg.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum FPUOp1 { pub enum FPUOp1 {
@@ -433,7 +438,7 @@ pub enum Inst {
}, },
/// An ALU operation with three register sources and a register destination. /// An ALU operation with three register sources and a register destination.
AluRRRR { AluRRRR {
alu_op: ALUOp, alu_op: ALUOp3,
rd: Writable<Reg>, rd: Writable<Reg>,
rn: Reg, rn: Reg,
rm: Reg, rm: Reg,
@@ -571,7 +576,7 @@ pub enum Inst {
/// A MOV instruction. These are encoded as ORR's (AluRRR form) but we /// A MOV instruction. These are encoded as ORR's (AluRRR form) but we
/// keep them separate at the `Inst` level for better pretty-printing /// keep them separate at the `Inst` level for better pretty-printing
/// and faster `is_move()` logic. /// and faster `is_move()` logic.
Mov { Mov64 {
rd: Writable<Reg>, rd: Writable<Reg>,
rm: Reg, rm: Reg,
}, },
@@ -1149,7 +1154,7 @@ impl Inst {
pub fn mov(to_reg: Writable<Reg>, from_reg: Reg) -> Inst { pub fn mov(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
assert!(to_reg.to_reg().get_class() == from_reg.get_class()); assert!(to_reg.to_reg().get_class() == from_reg.get_class());
if from_reg.get_class() == RegClass::I64 { if from_reg.get_class() == RegClass::I64 {
Inst::Mov { Inst::Mov64 {
rd: to_reg, rd: to_reg,
rm: from_reg, rm: from_reg,
} }
@@ -1458,7 +1463,7 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
collector.add_def(rt2); collector.add_def(rt2);
pairmemarg_regs(mem, collector); pairmemarg_regs(mem, collector);
} }
&Inst::Mov { rd, rm } => { &Inst::Mov64 { rd, rm } => {
collector.add_def(rd); collector.add_def(rd);
collector.add_use(rm); collector.add_use(rm);
} }
@@ -1991,7 +1996,7 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
map_def(mapper, rt2); map_def(mapper, rt2);
map_pairmem(mapper, mem); map_pairmem(mapper, mem);
} }
&mut Inst::Mov { &mut Inst::Mov64 {
ref mut rd, ref mut rd,
ref mut rm, ref mut rm,
} => { } => {
@@ -2456,7 +2461,7 @@ impl MachInst for Inst {
fn is_move(&self) -> Option<(Writable<Reg>, Reg)> { fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
match self { match self {
&Inst::Mov { rd, rm } => Some((rd, rm)), &Inst::Mov64 { rd, rm } => Some((rd, rm)),
&Inst::FpuMove64 { rd, rn } => Some((rd, rn)), &Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
&Inst::FpuMove128 { rd, rn } => Some((rd, rn)), &Inst::FpuMove128 { rd, rn } => Some((rd, rn)),
_ => None, _ => None,
@@ -2628,10 +2633,6 @@ impl Inst {
ALUOp::SubS32 => ("subs", OperandSize::Size32), ALUOp::SubS32 => ("subs", OperandSize::Size32),
ALUOp::SubS64 => ("subs", OperandSize::Size64), ALUOp::SubS64 => ("subs", OperandSize::Size64),
ALUOp::SubS64XR => ("subs", OperandSize::Size64), ALUOp::SubS64XR => ("subs", OperandSize::Size64),
ALUOp::MAdd32 => ("madd", OperandSize::Size32),
ALUOp::MAdd64 => ("madd", OperandSize::Size64),
ALUOp::MSub32 => ("msub", OperandSize::Size32),
ALUOp::MSub64 => ("msub", OperandSize::Size64),
ALUOp::SMulH => ("smulh", OperandSize::Size64), ALUOp::SMulH => ("smulh", OperandSize::Size64),
ALUOp::UMulH => ("umulh", OperandSize::Size64), ALUOp::UMulH => ("umulh", OperandSize::Size64),
ALUOp::SDiv64 => ("sdiv", OperandSize::Size64), ALUOp::SDiv64 => ("sdiv", OperandSize::Size64),
@@ -2670,19 +2671,18 @@ impl Inst {
rm, rm,
ra, ra,
} => { } => {
let (op, size) = op_name_size(alu_op); let (op, size) = match alu_op {
let four_args = alu_op != ALUOp::SMulH && alu_op != ALUOp::UMulH; ALUOp3::MAdd32 => ("madd", OperandSize::Size32),
ALUOp3::MAdd64 => ("madd", OperandSize::Size64),
ALUOp3::MSub32 => ("msub", OperandSize::Size32),
ALUOp3::MSub64 => ("msub", OperandSize::Size64),
};
let rd = show_ireg_sized(rd.to_reg(), mb_rru, size); let rd = show_ireg_sized(rd.to_reg(), mb_rru, size);
let rn = show_ireg_sized(rn, mb_rru, size); let rn = show_ireg_sized(rn, mb_rru, size);
let rm = show_ireg_sized(rm, mb_rru, size); let rm = show_ireg_sized(rm, mb_rru, size);
let ra = show_ireg_sized(ra, mb_rru, size); let ra = show_ireg_sized(ra, mb_rru, size);
if four_args {
format!("{} {}, {}, {}, {}", op, rd, rn, rm, ra) format!("{} {}, {}, {}, {}", op, rd, rn, rm, ra)
} else {
// smulh and umulh have Ra "hard-wired" to the zero register
// and the canonical assembly form has only three regs.
format!("{} {}, {}, {}", op, rd, rn, rm)
}
} }
&Inst::AluRRImm12 { &Inst::AluRRImm12 {
alu_op, alu_op,
@@ -2878,7 +2878,7 @@ impl Inst {
let mem = mem.show_rru_sized(mb_rru, /* size = */ 8); let mem = mem.show_rru_sized(mb_rru, /* size = */ 8);
format!("ldp {}, {}, {}", rt, rt2, mem) format!("ldp {}, {}, {}", rt, rt2, mem)
} }
&Inst::Mov { rd, rm } => { &Inst::Mov64 { rd, rm } => {
let rd = rd.to_reg().show_rru(mb_rru); let rd = rd.to_reg().show_rru(mb_rru);
let rm = rm.show_rru(mb_rru); let rm = rm.show_rru(mb_rru);
format!("mov {}, {}", rd, rm) format!("mov {}, {}", rd, rm)

View File

@@ -212,7 +212,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let ty = ty.unwrap(); let ty = ty.unwrap();
if !ty.is_vector() { if !ty.is_vector() {
let alu_op = choose_32_64(ty, ALUOp::MAdd32, ALUOp::MAdd64); let alu_op = choose_32_64(ty, ALUOp3::MAdd32, ALUOp3::MAdd64);
ctx.emit(Inst::AluRRRR { ctx.emit(Inst::AluRRRR {
alu_op, alu_op,
rd, rd,
@@ -349,19 +349,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
I64 => { I64 => {
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None); let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None); let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
let ra = zero_reg();
let alu_op = if is_signed { let alu_op = if is_signed {
ALUOp::SMulH ALUOp::SMulH
} else { } else {
ALUOp::UMulH ALUOp::UMulH
}; };
ctx.emit(Inst::AluRRRR { ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm });
alu_op,
rd,
rn,
rm,
ra,
});
} }
I32 | I16 | I8 => { I32 | I16 | I8 => {
let narrow_mode = if is_signed { let narrow_mode = if is_signed {
@@ -373,7 +366,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let rm = put_input_in_reg(ctx, inputs[1], narrow_mode); let rm = put_input_in_reg(ctx, inputs[1], narrow_mode);
let ra = zero_reg(); let ra = zero_reg();
ctx.emit(Inst::AluRRRR { ctx.emit(Inst::AluRRRR {
alu_op: ALUOp::MAdd64, alu_op: ALUOp3::MAdd64,
rd, rd,
rn, rn,
rm, rm,
@@ -462,7 +455,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}); });
ctx.emit(Inst::AluRRRR { ctx.emit(Inst::AluRRRR {
alu_op: ALUOp::MSub64, alu_op: ALUOp3::MSub64,
rd: rd, rd: rd,
rn: rd.to_reg(), rn: rd.to_reg(),
rm: rm, rm: rm,