Merge pull request #2414 from jgouly/extend-refactor
arm64: Refactor Inst::Extend handling
This commit is contained in:
@@ -258,10 +258,6 @@ fn enc_ldst_vec(q: u32, size: u32, rn: Reg, rt: Writable<Reg>) -> u32 {
|
|||||||
| machreg_to_vec(rt.to_reg())
|
| machreg_to_vec(rt.to_reg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enc_extend(top22: u32, rd: Writable<Reg>, rn: Reg) -> u32 {
|
|
||||||
(top22 << 10) | (machreg_to_gpr(rn) << 5) | machreg_to_gpr(rd.to_reg())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enc_vec_rrr(top11: u32, rm: Reg, bit15_10: u32, rn: Reg, rd: Writable<Reg>) -> u32 {
|
fn enc_vec_rrr(top11: u32, rm: Reg, bit15_10: u32, rn: Reg, rd: Writable<Reg>) -> u32 {
|
||||||
(top11 << 21)
|
(top11 << 21)
|
||||||
| (machreg_to_vec(rm) << 16)
|
| (machreg_to_vec(rm) << 16)
|
||||||
@@ -313,6 +309,12 @@ fn enc_cset(rd: Writable<Reg>, cond: Cond) -> u32 {
|
|||||||
| (cond.invert().bits() << 12)
|
| (cond.invert().bits() << 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enc_csetm(rd: Writable<Reg>, cond: Cond) -> u32 {
|
||||||
|
0b110_11010100_11111_0000_00_11111_00000
|
||||||
|
| machreg_to_gpr(rd.to_reg())
|
||||||
|
| (cond.invert().bits() << 12)
|
||||||
|
}
|
||||||
|
|
||||||
fn enc_ccmp_imm(size: OperandSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) -> u32 {
|
fn enc_ccmp_imm(size: OperandSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) -> u32 {
|
||||||
0b0_1_1_11010010_00000_0000_10_00000_0_0000
|
0b0_1_1_11010010_00000_0000_10_00000_0_0000
|
||||||
| size.sf_bit() << 31
|
| size.sf_bit() << 31
|
||||||
@@ -322,6 +324,29 @@ fn enc_ccmp_imm(size: OperandSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond)
|
|||||||
| nzcv.bits()
|
| nzcv.bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enc_bfm(opc: u8, size: OperandSize, rd: Writable<Reg>, rn: Reg, immr: u8, imms: u8) -> u32 {
|
||||||
|
match size {
|
||||||
|
OperandSize::Size64 => {
|
||||||
|
debug_assert!(immr <= 63);
|
||||||
|
debug_assert!(imms <= 63);
|
||||||
|
}
|
||||||
|
OperandSize::Size32 => {
|
||||||
|
debug_assert!(immr <= 31);
|
||||||
|
debug_assert!(imms <= 31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_assert_eq!(opc & 0b11, opc);
|
||||||
|
let n_bit = size.sf_bit();
|
||||||
|
0b0_00_100110_0_000000_000000_00000_00000
|
||||||
|
| size.sf_bit() << 31
|
||||||
|
| u32::from(opc) << 29
|
||||||
|
| n_bit << 22
|
||||||
|
| u32::from(immr) << 16
|
||||||
|
| u32::from(imms) << 10
|
||||||
|
| machreg_to_gpr(rn) << 5
|
||||||
|
| machreg_to_gpr(rd.to_reg())
|
||||||
|
}
|
||||||
|
|
||||||
fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
|
fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
|
||||||
0b00001110_101_00000_00011_1_00000_00000
|
0b00001110_101_00000_00011_1_00000_00000
|
||||||
| ((is_16b as u32) << 30)
|
| ((is_16b as u32) << 30)
|
||||||
@@ -1045,6 +1070,9 @@ impl MachInstEmit for Inst {
|
|||||||
&Inst::CSet { rd, cond } => {
|
&Inst::CSet { rd, cond } => {
|
||||||
sink.put4(enc_cset(rd, cond));
|
sink.put4(enc_cset(rd, cond));
|
||||||
}
|
}
|
||||||
|
&Inst::CSetm { rd, cond } => {
|
||||||
|
sink.put4(enc_csetm(rd, cond));
|
||||||
|
}
|
||||||
&Inst::CCmpImm {
|
&Inst::CCmpImm {
|
||||||
size,
|
size,
|
||||||
rn,
|
rn,
|
||||||
@@ -1985,75 +2013,47 @@ impl MachInstEmit for Inst {
|
|||||||
&Inst::Extend {
|
&Inst::Extend {
|
||||||
rd,
|
rd,
|
||||||
rn,
|
rn,
|
||||||
signed,
|
signed: false,
|
||||||
from_bits,
|
from_bits: 1,
|
||||||
to_bits,
|
to_bits,
|
||||||
} if from_bits >= 8 => {
|
} => {
|
||||||
let top22 = match (signed, from_bits, to_bits) {
|
|
||||||
(false, 8, 32) => 0b010_100110_0_000000_000111, // UXTB (32)
|
|
||||||
(false, 16, 32) => 0b010_100110_0_000000_001111, // UXTH (32)
|
|
||||||
(true, 8, 32) => 0b000_100110_0_000000_000111, // SXTB (32)
|
|
||||||
(true, 16, 32) => 0b000_100110_0_000000_001111, // SXTH (32)
|
|
||||||
// The 64-bit unsigned variants are the same as the 32-bit ones,
|
|
||||||
// because writes to Wn zero out the top 32 bits of Xn
|
|
||||||
(false, 8, 64) => 0b010_100110_0_000000_000111, // UXTB (64)
|
|
||||||
(false, 16, 64) => 0b010_100110_0_000000_001111, // UXTH (64)
|
|
||||||
(true, 8, 64) => 0b100_100110_1_000000_000111, // SXTB (64)
|
|
||||||
(true, 16, 64) => 0b100_100110_1_000000_001111, // SXTH (64)
|
|
||||||
// 32-to-64: the unsigned case is a 'mov' (special-cased below).
|
|
||||||
(false, 32, 64) => 0, // MOV
|
|
||||||
(true, 32, 64) => 0b100_100110_1_000000_011111, // SXTW (64)
|
|
||||||
_ => panic!(
|
|
||||||
"Unsupported extend combination: signed = {}, from_bits = {}, to_bits = {}",
|
|
||||||
signed, from_bits, to_bits
|
|
||||||
),
|
|
||||||
};
|
|
||||||
if top22 != 0 {
|
|
||||||
sink.put4(enc_extend(top22, rd, rn));
|
|
||||||
} else {
|
|
||||||
let mov = Inst::Mov32 { rd, rm: rn };
|
|
||||||
|
|
||||||
mov.emit(sink, emit_info, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Inst::Extend {
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
signed,
|
|
||||||
from_bits,
|
|
||||||
to_bits,
|
|
||||||
} if from_bits == 1 && signed => {
|
|
||||||
assert!(to_bits <= 64);
|
|
||||||
// Reduce sign-extend-from-1-bit to:
|
|
||||||
// - and rd, rn, #1
|
|
||||||
// - sub rd, zr, rd
|
|
||||||
|
|
||||||
// We don't have ImmLogic yet, so we just hardcode this. FIXME.
|
|
||||||
sink.put4(0x92400000 | (machreg_to_gpr(rn) << 5) | machreg_to_gpr(rd.to_reg()));
|
|
||||||
let sub_inst = Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Sub64,
|
|
||||||
rd,
|
|
||||||
rn: zero_reg(),
|
|
||||||
rm: rd.to_reg(),
|
|
||||||
};
|
|
||||||
sub_inst.emit(sink, emit_info, state);
|
|
||||||
}
|
|
||||||
&Inst::Extend {
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
signed,
|
|
||||||
from_bits,
|
|
||||||
to_bits,
|
|
||||||
} if from_bits == 1 && !signed => {
|
|
||||||
assert!(to_bits <= 64);
|
assert!(to_bits <= 64);
|
||||||
// Reduce zero-extend-from-1-bit to:
|
// Reduce zero-extend-from-1-bit to:
|
||||||
// - and rd, rn, #1
|
// - and rd, rn, #1
|
||||||
|
// Note: This is special cased as UBFX may take more cycles
|
||||||
// We don't have ImmLogic yet, so we just hardcode this. FIXME.
|
// than AND on smaller cores.
|
||||||
sink.put4(0x92400000 | (machreg_to_gpr(rn) << 5) | machreg_to_gpr(rd.to_reg()));
|
let imml = ImmLogic::maybe_from_u64(1, I32).unwrap();
|
||||||
|
Inst::AluRRImmLogic {
|
||||||
|
alu_op: ALUOp::And32,
|
||||||
|
rd,
|
||||||
|
rn,
|
||||||
|
imml,
|
||||||
|
}
|
||||||
|
.emit(sink, emit_info, state);
|
||||||
}
|
}
|
||||||
&Inst::Extend { .. } => {
|
&Inst::Extend {
|
||||||
panic!("Unsupported extend variant");
|
rd,
|
||||||
|
rn,
|
||||||
|
signed: false,
|
||||||
|
from_bits: 32,
|
||||||
|
to_bits: 64,
|
||||||
|
} => {
|
||||||
|
let mov = Inst::Mov32 { rd, rm: rn };
|
||||||
|
mov.emit(sink, emit_info, state);
|
||||||
|
}
|
||||||
|
&Inst::Extend {
|
||||||
|
rd,
|
||||||
|
rn,
|
||||||
|
signed,
|
||||||
|
from_bits,
|
||||||
|
to_bits,
|
||||||
|
} => {
|
||||||
|
let (opc, size) = if signed {
|
||||||
|
(0b00, OperandSize::from_bits(to_bits))
|
||||||
|
} else {
|
||||||
|
(0b10, OperandSize::Size32)
|
||||||
|
};
|
||||||
|
sink.put4(enc_bfm(opc, size, rd, rn, 0, from_bits - 1));
|
||||||
}
|
}
|
||||||
&Inst::Jump { ref dest } => {
|
&Inst::Jump { ref dest } => {
|
||||||
let off = sink.cur_offset();
|
let off = sink.cur_offset();
|
||||||
|
|||||||
@@ -1846,6 +1846,22 @@ fn test_aarch64_binemit() {
|
|||||||
"EFB79F9A",
|
"EFB79F9A",
|
||||||
"cset x15, ge",
|
"cset x15, ge",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::CSetm {
|
||||||
|
rd: writable_xreg(0),
|
||||||
|
cond: Cond::Eq,
|
||||||
|
},
|
||||||
|
"E0139FDA",
|
||||||
|
"csetm x0, eq",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::CSetm {
|
||||||
|
rd: writable_xreg(16),
|
||||||
|
cond: Cond::Vs,
|
||||||
|
},
|
||||||
|
"F0739FDA",
|
||||||
|
"csetm x16, vs",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::CCmpImm {
|
Inst::CCmpImm {
|
||||||
size: OperandSize::Size64,
|
size: OperandSize::Size64,
|
||||||
@@ -3952,6 +3968,50 @@ fn test_aarch64_binemit() {
|
|||||||
"vcsel v5.16b, v10.16b, v19.16b, gt (if-then-else diamond)",
|
"vcsel v5.16b, v10.16b, v19.16b, gt (if-then-else diamond)",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
insns.push((
|
||||||
|
Inst::Extend {
|
||||||
|
rd: writable_xreg(3),
|
||||||
|
rn: xreg(5),
|
||||||
|
signed: false,
|
||||||
|
from_bits: 1,
|
||||||
|
to_bits: 32,
|
||||||
|
},
|
||||||
|
"A3000012",
|
||||||
|
"and w3, w5, #1",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::Extend {
|
||||||
|
rd: writable_xreg(3),
|
||||||
|
rn: xreg(5),
|
||||||
|
signed: false,
|
||||||
|
from_bits: 1,
|
||||||
|
to_bits: 64,
|
||||||
|
},
|
||||||
|
"A3000012",
|
||||||
|
"and w3, w5, #1",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::Extend {
|
||||||
|
rd: writable_xreg(10),
|
||||||
|
rn: xreg(21),
|
||||||
|
signed: true,
|
||||||
|
from_bits: 1,
|
||||||
|
to_bits: 32,
|
||||||
|
},
|
||||||
|
"AA020013",
|
||||||
|
"sbfx w10, w21, #0, #1",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::Extend {
|
||||||
|
rd: writable_xreg(1),
|
||||||
|
rn: xreg(2),
|
||||||
|
signed: true,
|
||||||
|
from_bits: 1,
|
||||||
|
to_bits: 64,
|
||||||
|
},
|
||||||
|
"41004093",
|
||||||
|
"sbfx x1, x2, #0, #1",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::Extend {
|
Inst::Extend {
|
||||||
rd: writable_xreg(1),
|
rd: writable_xreg(1),
|
||||||
@@ -4005,7 +4065,7 @@ fn test_aarch64_binemit() {
|
|||||||
to_bits: 64,
|
to_bits: 64,
|
||||||
},
|
},
|
||||||
"411C0053",
|
"411C0053",
|
||||||
"uxtb x1, w2",
|
"uxtb w1, w2",
|
||||||
));
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::Extend {
|
Inst::Extend {
|
||||||
@@ -4027,7 +4087,7 @@ fn test_aarch64_binemit() {
|
|||||||
to_bits: 64,
|
to_bits: 64,
|
||||||
},
|
},
|
||||||
"413C0053",
|
"413C0053",
|
||||||
"uxth x1, w2",
|
"uxth w1, w2",
|
||||||
));
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::Extend {
|
Inst::Extend {
|
||||||
|
|||||||
@@ -661,6 +661,12 @@ pub enum Inst {
|
|||||||
cond: Cond,
|
cond: Cond,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A conditional-set-mask operation.
|
||||||
|
CSetm {
|
||||||
|
rd: Writable<Reg>,
|
||||||
|
cond: Cond,
|
||||||
|
},
|
||||||
|
|
||||||
/// A conditional comparison with an immediate.
|
/// A conditional comparison with an immediate.
|
||||||
CCmpImm {
|
CCmpImm {
|
||||||
size: OperandSize,
|
size: OperandSize,
|
||||||
@@ -1674,7 +1680,7 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
collector.add_use(rn);
|
collector.add_use(rn);
|
||||||
collector.add_use(rm);
|
collector.add_use(rm);
|
||||||
}
|
}
|
||||||
&Inst::CSet { rd, .. } => {
|
&Inst::CSet { rd, .. } | &Inst::CSetm { rd, .. } => {
|
||||||
collector.add_def(rd);
|
collector.add_def(rd);
|
||||||
}
|
}
|
||||||
&Inst::CCmpImm { rn, .. } => {
|
&Inst::CCmpImm { rn, .. } => {
|
||||||
@@ -2242,7 +2248,7 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
map_use(mapper, rn);
|
map_use(mapper, rn);
|
||||||
map_use(mapper, rm);
|
map_use(mapper, rm);
|
||||||
}
|
}
|
||||||
&mut Inst::CSet { ref mut rd, .. } => {
|
&mut Inst::CSet { ref mut rd, .. } | &mut Inst::CSetm { ref mut rd, .. } => {
|
||||||
map_def(mapper, rd);
|
map_def(mapper, rd);
|
||||||
}
|
}
|
||||||
&mut Inst::CCmpImm { ref mut rn, .. } => {
|
&mut Inst::CCmpImm { ref mut rn, .. } => {
|
||||||
@@ -3157,6 +3163,11 @@ impl Inst {
|
|||||||
let cond = cond.show_rru(mb_rru);
|
let cond = cond.show_rru(mb_rru);
|
||||||
format!("cset {}, {}", rd, cond)
|
format!("cset {}, {}", rd, cond)
|
||||||
}
|
}
|
||||||
|
&Inst::CSetm { rd, cond } => {
|
||||||
|
let rd = rd.to_reg().show_rru(mb_rru);
|
||||||
|
let cond = cond.show_rru(mb_rru);
|
||||||
|
format!("csetm {}, {}", rd, cond)
|
||||||
|
}
|
||||||
&Inst::CCmpImm {
|
&Inst::CCmpImm {
|
||||||
size,
|
size,
|
||||||
rn,
|
rn,
|
||||||
@@ -3737,63 +3748,60 @@ impl Inst {
|
|||||||
&Inst::Extend {
|
&Inst::Extend {
|
||||||
rd,
|
rd,
|
||||||
rn,
|
rn,
|
||||||
signed,
|
signed: false,
|
||||||
from_bits,
|
from_bits: 1,
|
||||||
to_bits,
|
|
||||||
} if from_bits >= 8 => {
|
|
||||||
// Is the destination a 32-bit register? Corresponds to whether
|
|
||||||
// extend-to width is <= 32 bits, *unless* we have an unsigned
|
|
||||||
// 32-to-64-bit extension, which is implemented with a "mov" to a
|
|
||||||
// 32-bit (W-reg) dest, because this zeroes the top 32 bits.
|
|
||||||
let dest_size = if !signed && from_bits == 32 && to_bits == 64 {
|
|
||||||
OperandSize::Size32
|
|
||||||
} else {
|
|
||||||
OperandSize::from_bits(to_bits)
|
|
||||||
};
|
|
||||||
let rd = show_ireg_sized(rd.to_reg(), mb_rru, dest_size);
|
|
||||||
let rn = show_ireg_sized(rn, mb_rru, OperandSize::from_bits(from_bits));
|
|
||||||
let op = match (signed, from_bits, to_bits) {
|
|
||||||
(false, 8, 32) => "uxtb",
|
|
||||||
(true, 8, 32) => "sxtb",
|
|
||||||
(false, 16, 32) => "uxth",
|
|
||||||
(true, 16, 32) => "sxth",
|
|
||||||
(false, 8, 64) => "uxtb",
|
|
||||||
(true, 8, 64) => "sxtb",
|
|
||||||
(false, 16, 64) => "uxth",
|
|
||||||
(true, 16, 64) => "sxth",
|
|
||||||
(false, 32, 64) => "mov", // special case (see above).
|
|
||||||
(true, 32, 64) => "sxtw",
|
|
||||||
_ => panic!("Unsupported Extend case: {:?}", self),
|
|
||||||
};
|
|
||||||
format!("{} {}, {}", op, rd, rn)
|
|
||||||
}
|
|
||||||
&Inst::Extend {
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
signed,
|
|
||||||
from_bits,
|
|
||||||
to_bits,
|
|
||||||
} if from_bits == 1 && signed => {
|
|
||||||
let dest_size = OperandSize::from_bits(to_bits);
|
|
||||||
let zr = if dest_size.is32() { "wzr" } else { "xzr" };
|
|
||||||
let rd32 = show_ireg_sized(rd.to_reg(), mb_rru, OperandSize::Size32);
|
|
||||||
let rd = show_ireg_sized(rd.to_reg(), mb_rru, dest_size);
|
|
||||||
let rn = show_ireg_sized(rn, mb_rru, OperandSize::Size32);
|
|
||||||
format!("and {}, {}, #1 ; sub {}, {}, {}", rd32, rn, rd, zr, rd)
|
|
||||||
}
|
|
||||||
&Inst::Extend {
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
signed,
|
|
||||||
from_bits,
|
|
||||||
..
|
..
|
||||||
} if from_bits == 1 && !signed => {
|
} => {
|
||||||
let rd = show_ireg_sized(rd.to_reg(), mb_rru, OperandSize::Size32);
|
let rd = show_ireg_sized(rd.to_reg(), mb_rru, OperandSize::Size32);
|
||||||
let rn = show_ireg_sized(rn, mb_rru, OperandSize::Size32);
|
let rn = show_ireg_sized(rn, mb_rru, OperandSize::Size32);
|
||||||
format!("and {}, {}, #1", rd, rn)
|
format!("and {}, {}, #1", rd, rn)
|
||||||
}
|
}
|
||||||
&Inst::Extend { .. } => {
|
&Inst::Extend {
|
||||||
panic!("Unsupported Extend case");
|
rd,
|
||||||
|
rn,
|
||||||
|
signed: false,
|
||||||
|
from_bits: 32,
|
||||||
|
to_bits: 64,
|
||||||
|
} => {
|
||||||
|
// The case of a zero extension from 32 to 64 bits, is implemented
|
||||||
|
// with a "mov" to a 32-bit (W-reg) dest, because this zeroes
|
||||||
|
// the top 32 bits.
|
||||||
|
let rd = show_ireg_sized(rd.to_reg(), mb_rru, OperandSize::Size32);
|
||||||
|
let rn = show_ireg_sized(rn, mb_rru, OperandSize::Size32);
|
||||||
|
format!("mov {}, {}", rd, rn)
|
||||||
|
}
|
||||||
|
&Inst::Extend {
|
||||||
|
rd,
|
||||||
|
rn,
|
||||||
|
signed,
|
||||||
|
from_bits,
|
||||||
|
to_bits,
|
||||||
|
} => {
|
||||||
|
assert!(from_bits <= to_bits);
|
||||||
|
let op = match (signed, from_bits) {
|
||||||
|
(false, 8) => "uxtb",
|
||||||
|
(true, 8) => "sxtb",
|
||||||
|
(false, 16) => "uxth",
|
||||||
|
(true, 16) => "sxth",
|
||||||
|
(true, 32) => "sxtw",
|
||||||
|
(true, _) => "sbfx",
|
||||||
|
(false, _) => "ubfx",
|
||||||
|
};
|
||||||
|
if op == "sbfx" || op == "ubfx" {
|
||||||
|
let dest_size = OperandSize::from_bits(to_bits);
|
||||||
|
let rd = show_ireg_sized(rd.to_reg(), mb_rru, dest_size);
|
||||||
|
let rn = show_ireg_sized(rn, mb_rru, dest_size);
|
||||||
|
format!("{} {}, {}, #0, #{}", op, rd, rn, from_bits)
|
||||||
|
} else {
|
||||||
|
let dest_size = if signed {
|
||||||
|
OperandSize::from_bits(to_bits)
|
||||||
|
} else {
|
||||||
|
OperandSize::Size32
|
||||||
|
};
|
||||||
|
let rd = show_ireg_sized(rd.to_reg(), mb_rru, dest_size);
|
||||||
|
let rn = show_ireg_sized(rn, mb_rru, OperandSize::from_bits(from_bits));
|
||||||
|
format!("{} {}, {}", op, rd, rn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&Inst::Call { .. } => format!("bl 0"),
|
&Inst::Call { .. } => format!("bl 0"),
|
||||||
&Inst::CallInd { ref info, .. } => {
|
&Inst::CallInd { ref info, .. } => {
|
||||||
|
|||||||
@@ -1151,21 +1151,21 @@ pub(crate) fn lower_fcmp_or_ffcmp_to_flags<C: LowerCtx<I = Inst>>(ctx: &mut C, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a 0 / 1 result, such as from a conditional-set instruction, into a 0
|
/// Materialize a boolean value into a register from the flags
|
||||||
/// / -1 (all-ones) result as expected for bool operations.
|
/// (e.g set by a comparison).
|
||||||
pub(crate) fn normalize_bool_result<C: LowerCtx<I = Inst>>(
|
/// A 0 / -1 (all-ones) result as expected for bool operations.
|
||||||
|
pub(crate) fn materialize_bool_result<C: LowerCtx<I = Inst>>(
|
||||||
ctx: &mut C,
|
ctx: &mut C,
|
||||||
insn: IRInst,
|
insn: IRInst,
|
||||||
rd: Writable<Reg>,
|
rd: Writable<Reg>,
|
||||||
|
cond: Cond,
|
||||||
) {
|
) {
|
||||||
// A boolean is 0 / -1; if output width is > 1, negate.
|
// A boolean is 0 / -1; if output width is > 1 use `csetm`,
|
||||||
|
// otherwise use `cset`.
|
||||||
if ty_bits(ctx.output_ty(insn, 0)) > 1 {
|
if ty_bits(ctx.output_ty(insn, 0)) > 1 {
|
||||||
ctx.emit(Inst::AluRRR {
|
ctx.emit(Inst::CSetm { rd, cond });
|
||||||
alu_op: ALUOp::Sub64,
|
} else {
|
||||||
rd,
|
ctx.emit(Inst::CSet { rd, cond });
|
||||||
rn: zero_reg(),
|
|
||||||
rm: rd.to_reg(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1475,8 +1475,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
||||||
lower_icmp_or_ifcmp_to_flags(ctx, ifcmp_insn, is_signed);
|
lower_icmp_or_ifcmp_to_flags(ctx, ifcmp_insn, is_signed);
|
||||||
let rd = get_output_reg(ctx, outputs[0]);
|
let rd = get_output_reg(ctx, outputs[0]);
|
||||||
ctx.emit(Inst::CSet { rd, cond });
|
materialize_bool_result(ctx, insn, rd, cond);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Trueff => {
|
Opcode::Trueff => {
|
||||||
@@ -1485,8 +1484,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
let ffcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ffcmp).unwrap();
|
let ffcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ffcmp).unwrap();
|
||||||
lower_fcmp_or_ffcmp_to_flags(ctx, ffcmp_insn);
|
lower_fcmp_or_ffcmp_to_flags(ctx, ffcmp_insn);
|
||||||
let rd = get_output_reg(ctx, outputs[0]);
|
let rd = get_output_reg(ctx, outputs[0]);
|
||||||
ctx.emit(Inst::CSet { rd, cond });
|
materialize_bool_result(ctx, insn, rd, cond);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::IsNull | Opcode::IsInvalid => {
|
Opcode::IsNull | Opcode::IsInvalid => {
|
||||||
@@ -1509,8 +1507,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
};
|
};
|
||||||
let const_value = ResultRSEImm12::Imm12(Imm12::maybe_from_u64(const_value).unwrap());
|
let const_value = ResultRSEImm12::Imm12(Imm12::maybe_from_u64(const_value).unwrap());
|
||||||
ctx.emit(alu_inst_imm12(alu_op, writable_zero_reg(), rn, const_value));
|
ctx.emit(alu_inst_imm12(alu_op, writable_zero_reg(), rn, const_value));
|
||||||
ctx.emit(Inst::CSet { rd, cond: Cond::Eq });
|
materialize_bool_result(ctx, insn, rd, Cond::Eq);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Copy => {
|
Opcode::Copy => {
|
||||||
@@ -1535,11 +1532,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
// sign-extend the -1 to a -1 in the wider width.
|
// sign-extend the -1 to a -1 in the wider width.
|
||||||
// - Bmask, because the resulting integer mask value must be
|
// - Bmask, because the resulting integer mask value must be
|
||||||
// all-ones (-1) if the argument is true.
|
// all-ones (-1) if the argument is true.
|
||||||
//
|
|
||||||
// For a sign-extension from a 1-bit value (Case 1 below), we need
|
|
||||||
// to do things a bit specially, because the ISA does not have a
|
|
||||||
// 1-to-N-bit sign extension instruction. For 8-bit or wider
|
|
||||||
// sources (Case 2 below), we do a sign extension normally.
|
|
||||||
|
|
||||||
let from_ty = ctx.input_ty(insn, 0);
|
let from_ty = ctx.input_ty(insn, 0);
|
||||||
let to_ty = ctx.output_ty(insn, 0);
|
let to_ty = ctx.output_ty(insn, 0);
|
||||||
@@ -1554,41 +1546,23 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
if from_bits == to_bits {
|
if from_bits == to_bits {
|
||||||
// Nothing.
|
// Nothing.
|
||||||
} else if from_bits == 1 {
|
} else {
|
||||||
assert!(to_bits >= 8);
|
|
||||||
// Case 1: 1-bit to N-bit extension: AND the LSB of source into
|
|
||||||
// dest, generating a value of 0 or 1, then negate to get
|
|
||||||
// 0x000... or 0xfff...
|
|
||||||
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
|
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
|
||||||
let rd = get_output_reg(ctx, outputs[0]);
|
let rd = get_output_reg(ctx, outputs[0]);
|
||||||
// AND Rdest, Rsource, #1
|
let to_bits = if to_bits == 64 {
|
||||||
ctx.emit(Inst::AluRRImmLogic {
|
64
|
||||||
alu_op: ALUOp::And64,
|
|
||||||
rd,
|
|
||||||
rn,
|
|
||||||
imml: ImmLogic::maybe_from_u64(1, I64).unwrap(),
|
|
||||||
});
|
|
||||||
// SUB Rdest, XZR, Rdest (i.e., NEG Rdest)
|
|
||||||
ctx.emit(Inst::AluRRR {
|
|
||||||
alu_op: ALUOp::Sub64,
|
|
||||||
rd,
|
|
||||||
rn: zero_reg(),
|
|
||||||
rm: rd.to_reg(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Case 2: 8-or-more-bit to N-bit extension: just sign-extend. A
|
|
||||||
// `true` (all ones, or `-1`) will be extended to -1 with the
|
|
||||||
// larger width.
|
|
||||||
assert!(from_bits >= 8);
|
|
||||||
let narrow_mode = if to_bits == 64 {
|
|
||||||
NarrowValueMode::SignExtend64
|
|
||||||
} else {
|
} else {
|
||||||
assert!(to_bits <= 32);
|
assert!(to_bits <= 32);
|
||||||
NarrowValueMode::SignExtend32
|
32
|
||||||
};
|
};
|
||||||
let rn = put_input_in_reg(ctx, inputs[0], narrow_mode);
|
let from_bits = from_bits as u8;
|
||||||
let rd = get_output_reg(ctx, outputs[0]);
|
ctx.emit(Inst::Extend {
|
||||||
ctx.emit(Inst::gen_move(rd, rn, to_ty));
|
rd,
|
||||||
|
rn,
|
||||||
|
signed: true,
|
||||||
|
from_bits,
|
||||||
|
to_bits,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1699,8 +1673,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
let alu_op = choose_32_64(ty, ALUOp::SubS32, ALUOp::SubS64);
|
let alu_op = choose_32_64(ty, ALUOp::SubS32, ALUOp::SubS64);
|
||||||
let rm = put_input_in_rse_imm12(ctx, inputs[1], narrow_mode);
|
let rm = put_input_in_rse_imm12(ctx, inputs[1], narrow_mode);
|
||||||
ctx.emit(alu_inst_imm12(alu_op, writable_zero_reg(), rn, rm));
|
ctx.emit(alu_inst_imm12(alu_op, writable_zero_reg(), rn, rm));
|
||||||
ctx.emit(Inst::CSet { cond, rd });
|
materialize_bool_result(ctx, insn, rd, cond);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
} else {
|
} else {
|
||||||
let rm = put_input_in_reg(ctx, inputs[1], narrow_mode);
|
let rm = put_input_in_reg(ctx, inputs[1], narrow_mode);
|
||||||
lower_vector_compare(ctx, rd, rn, rm, ty, cond)?;
|
lower_vector_compare(ctx, rd, rn, rm, ty, cond)?;
|
||||||
@@ -1725,8 +1698,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
}
|
}
|
||||||
_ => panic!("Bad float size"),
|
_ => panic!("Bad float size"),
|
||||||
}
|
}
|
||||||
ctx.emit(Inst::CSet { cond, rd });
|
materialize_bool_result(ctx, insn, rd, cond);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
} else {
|
} else {
|
||||||
lower_vector_compare(ctx, rd, rn, rm, ty, cond)?;
|
lower_vector_compare(ctx, rd, rn, rm, ty, cond)?;
|
||||||
}
|
}
|
||||||
@@ -2089,8 +2061,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
imm12: Imm12::zero(),
|
imm12: Imm12::zero(),
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.emit(Inst::CSet { rd, cond: Cond::Ne });
|
materialize_bool_result(ctx, insn, rd, Cond::Ne);
|
||||||
normalize_bool_result(ctx, insn, rd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::VhighBits => {
|
Opcode::VhighBits => {
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ block0(v0: i16):
|
|||||||
|
|
||||||
; check: stp fp, lr, [sp, #-16]!
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
; nextln: mov fp, sp
|
; nextln: mov fp, sp
|
||||||
; nextln: uxth x0, w0
|
; nextln: uxth w0, w0
|
||||||
; nextln: lsr w1, w0, #1
|
; nextln: lsr w1, w0, #1
|
||||||
; nextln: and x1, x1, #6148914691236517205
|
; nextln: and x1, x1, #6148914691236517205
|
||||||
; nextln: sub x1, x0, x1
|
; nextln: sub x1, x0, x1
|
||||||
@@ -307,7 +307,7 @@ block0(v0: i8):
|
|||||||
|
|
||||||
; check: stp fp, lr, [sp, #-16]!
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
; nextln: mov fp, sp
|
; nextln: mov fp, sp
|
||||||
; nextln: uxtb x0, w0
|
; nextln: uxtb w0, w0
|
||||||
; nextln: lsr w1, w0, #1
|
; nextln: lsr w1, w0, #1
|
||||||
; nextln: and x1, x1, #6148914691236517205
|
; nextln: and x1, x1, #6148914691236517205
|
||||||
; nextln: sub x1, x0, x1
|
; nextln: sub x1, x0, x1
|
||||||
@@ -324,3 +324,33 @@ block0(v0: i8):
|
|||||||
; nextln: mov sp, fp
|
; nextln: mov sp, fp
|
||||||
; nextln: ldp fp, lr, [sp], #16
|
; nextln: ldp fp, lr, [sp], #16
|
||||||
; nextln: ret
|
; nextln: ret
|
||||||
|
|
||||||
|
function %bextend_b8() -> b32 {
|
||||||
|
block0:
|
||||||
|
v1 = bconst.b8 true
|
||||||
|
v2 = bextend.b32 v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
|
; nextln: mov fp, sp
|
||||||
|
; nextln: movz x0, #255
|
||||||
|
; nextln: sxtb w0, w0
|
||||||
|
; nextln: mov sp, fp
|
||||||
|
; nextln: ldp fp, lr, [sp], #16
|
||||||
|
; nextln: ret
|
||||||
|
|
||||||
|
function %bextend_b1() -> b32 {
|
||||||
|
block0:
|
||||||
|
v1 = bconst.b1 true
|
||||||
|
v2 = bextend.b32 v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
|
; nextln: mov fp, sp
|
||||||
|
; nextln: movz x0, #1
|
||||||
|
; nextln: sbfx w0, w0, #0, #1
|
||||||
|
; nextln: mov sp, fp
|
||||||
|
; nextln: ldp fp, lr, [sp], #16
|
||||||
|
; nextln: ret
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ block0(v0: i8, v1: i8):
|
|||||||
|
|
||||||
; check: stp fp, lr, [sp, #-16]!
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
; nextln: mov fp, sp
|
; nextln: mov fp, sp
|
||||||
; nextln: uxtb x0, w0
|
; nextln: uxtb w0, w0
|
||||||
; nextln: uxtb x1, w1
|
; nextln: uxtb w1, w1
|
||||||
; nextln: fmov d0, x0
|
; nextln: fmov d0, x0
|
||||||
; nextln: fmov d1, x1
|
; nextln: fmov d1, x1
|
||||||
; nextln: uqadd d0, d0, d1
|
; nextln: uqadd d0, d0, d1
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ block0(v0: i8):
|
|||||||
|
|
||||||
; check: stp fp, lr, [sp, #-16]!
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
; nextln: mov fp, sp
|
; nextln: mov fp, sp
|
||||||
; nextln: uxtb x0, w0
|
; nextln: uxtb w0, w0
|
||||||
; nextln: mov sp, fp
|
; nextln: mov sp, fp
|
||||||
; nextln: ldp fp, lr, [sp], #16
|
; nextln: ldp fp, lr, [sp], #16
|
||||||
; nextln: ret
|
; nextln: ret
|
||||||
@@ -87,7 +87,7 @@ block0(v0: i16):
|
|||||||
|
|
||||||
; check: stp fp, lr, [sp, #-16]!
|
; check: stp fp, lr, [sp, #-16]!
|
||||||
; nextln: mov fp, sp
|
; nextln: mov fp, sp
|
||||||
; nextln: uxth x0, w0
|
; nextln: uxth w0, w0
|
||||||
; nextln: mov sp, fp
|
; nextln: mov sp, fp
|
||||||
; nextln: ldp fp, lr, [sp], #16
|
; nextln: ldp fp, lr, [sp], #16
|
||||||
; nextln: ret
|
; nextln: ret
|
||||||
|
|||||||
Reference in New Issue
Block a user