Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,8 @@ impl MachInstEmit for Inst {
ALUOp::Orr64 => 0b10101010_000,
ALUOp::And32 => 0b00001010_000,
ALUOp::And64 => 0b10001010_000,
ALUOp::AndS32 => 0b01101010_000,
ALUOp::AndS64 => 0b11101010_000,
ALUOp::Eor32 => 0b01001010_000,
ALUOp::Eor64 => 0b11001010_000,
ALUOp::OrrNot32 => 0b00101010_001,
Expand Down Expand Up @@ -694,6 +696,8 @@ impl MachInstEmit for Inst {
ALUOp::Orr64 => (0b101_100100, false),
ALUOp::And32 => (0b000_100100, false),
ALUOp::And64 => (0b100_100100, false),
ALUOp::AndS32 => (0b011_100100, false),
ALUOp::AndS64 => (0b111_100100, false),
ALUOp::Eor32 => (0b010_100100, false),
ALUOp::Eor64 => (0b110_100100, false),
ALUOp::OrrNot32 => (0b001_100100, true),
Expand Down Expand Up @@ -763,6 +767,8 @@ impl MachInstEmit for Inst {
ALUOp::Orr64 => 0b101_01010000,
ALUOp::And32 => 0b000_01010000,
ALUOp::And64 => 0b100_01010000,
ALUOp::AndS32 => 0b011_01010000,
ALUOp::AndS64 => 0b111_01010000,
ALUOp::Eor32 => 0b010_01010000,
ALUOp::Eor64 => 0b110_01010000,
ALUOp::OrrNot32 => 0b001_01010001,
Expand Down
68 changes: 68 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,26 @@ fn test_aarch64_binemit() {
"A400068A",
"and x4, x5, x6",
));
insns.push((
Inst::AluRRR {
alu_op: ALUOp::AndS32,
rd: writable_xreg(1),
rn: xreg(2),
rm: xreg(3),
},
"4100036A",
"ands w1, w2, w3",
));
insns.push((
Inst::AluRRR {
alu_op: ALUOp::AndS64,
rd: writable_xreg(4),
rn: xreg(5),
rm: xreg(6),
},
"A40006EA",
"ands x4, x5, x6",
));
insns.push((
Inst::AluRRR {
alu_op: ALUOp::SubS32,
Expand Down Expand Up @@ -648,6 +668,34 @@ fn test_aarch64_binemit() {
"6A5D0C8A",
"and x10, x11, x12, LSL 23",
));
insns.push((
Inst::AluRRRShift {
alu_op: ALUOp::AndS32,
rd: writable_xreg(10),
rn: xreg(11),
rm: xreg(12),
shiftop: ShiftOpAndAmt::new(
ShiftOp::LSL,
ShiftOpShiftImm::maybe_from_shift(23).unwrap(),
),
},
"6A5D0C6A",
"ands w10, w11, w12, LSL 23",
));
insns.push((
Inst::AluRRRShift {
alu_op: ALUOp::AndS64,
rd: writable_xreg(10),
rn: xreg(11),
rm: xreg(12),
shiftop: ShiftOpAndAmt::new(
ShiftOp::LSL,
ShiftOpShiftImm::maybe_from_shift(23).unwrap(),
),
},
"6A5D0CEA",
"ands x10, x11, x12, LSL 23",
));
insns.push((
Inst::AluRRRShift {
alu_op: ALUOp::Eor32,
Expand Down Expand Up @@ -1015,6 +1063,26 @@ fn test_aarch64_binemit() {
"C7381592",
"and x7, x6, #288221580125796352",
));
insns.push((
Inst::AluRRImmLogic {
alu_op: ALUOp::AndS32,
rd: writable_xreg(21),
rn: xreg(27),
imml: ImmLogic::maybe_from_u64(0x80003fff, I32).unwrap(),
},
"753B0172",
"ands w21, w27, #2147500031",
));
insns.push((
Inst::AluRRImmLogic {
alu_op: ALUOp::AndS64,
rd: writable_xreg(7),
rn: xreg(6),
imml: ImmLogic::maybe_from_u64(0x3fff80003fff800, I64).unwrap(),
},
"C73815F2",
"ands x7, x6, #288221580125796352",
));
insns.push((
Inst::AluRRImmLogic {
alu_op: ALUOp::Orr32,
Expand Down
4 changes: 4 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub enum ALUOp {
OrrNot64,
And32,
And64,
AndS32,
AndS64,
AndNot32,
AndNot64,
/// XOR (AArch64 calls this "EOR")
Expand Down Expand Up @@ -3186,6 +3188,8 @@ impl Inst {
ALUOp::Orr64 => ("orr", OperandSize::Size64),
ALUOp::And32 => ("and", OperandSize::Size32),
ALUOp::And64 => ("and", OperandSize::Size64),
ALUOp::AndS32 => ("ands", OperandSize::Size32),
ALUOp::AndS64 => ("ands", OperandSize::Size64),
ALUOp::Eor32 => ("eor", OperandSize::Size32),
ALUOp::Eor64 => ("eor", OperandSize::Size64),
ALUOp::AddS32 => ("adds", OperandSize::Size32),
Expand Down
205 changes: 205 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,211 @@ pub(crate) fn lower_load<C: LowerCtx<I = Inst>, F: FnMut(&mut C, Writable<Reg>,
f(ctx, rd, elem_ty, mem);
}

pub(crate) fn emit_shl_i128<C: LowerCtx<I = Inst>>(
ctx: &mut C,
src: ValueRegs<Reg>,
dst: ValueRegs<Writable<Reg>>,
amt: Reg,
) {
let src_lo = src.regs()[0];
let src_hi = src.regs()[1];
let dst_lo = dst.regs()[0];
let dst_hi = dst.regs()[1];

// mvn inv_amt, amt
// lsr tmp1, src_lo, #1
// lsl tmp2, src_hi, amt
// lsr tmp1, tmp1, inv_amt
// lsl tmp3, src_lo, amt
// tst amt, #0x40
// orr tmp2, tmp2, tmp1
// csel dst_hi, tmp3, tmp2, ne
// csel dst_lo, xzr, tmp3, ne

let xzr = writable_zero_reg();
let inv_amt = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp1 = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp2 = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp3 = ctx.alloc_tmp(I64).only_reg().unwrap();

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::OrrNot32,
rd: inv_amt,
rn: xzr.to_reg(),
rm: amt,
});

ctx.emit(Inst::AluRRImmShift {
alu_op: ALUOp::Lsr64,
rd: tmp1,
rn: src_lo,
immshift: ImmShift::maybe_from_u64(1).unwrap(),
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Lsl64,
rd: tmp2,
rn: src_hi,
rm: amt,
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Lsr64,
rd: tmp1,
rn: tmp1.to_reg(),
rm: inv_amt.to_reg(),
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Lsl64,
rd: tmp3,
rn: src_lo,
rm: amt,
});

ctx.emit(Inst::AluRRImmLogic {
alu_op: ALUOp::AndS64,
rd: xzr,
rn: amt,
imml: ImmLogic::maybe_from_u64(64, I64).unwrap(),
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Orr64,
rd: tmp2,
rn: tmp2.to_reg(),
rm: tmp1.to_reg(),
});

ctx.emit(Inst::CSel {
cond: Cond::Ne,
rd: dst_hi,
rn: tmp3.to_reg(),
rm: tmp2.to_reg(),
});

ctx.emit(Inst::CSel {
cond: Cond::Ne,
rd: dst_lo,
rn: xzr.to_reg(),
rm: tmp3.to_reg(),
});
}

pub(crate) fn emit_shr_i128<C: LowerCtx<I = Inst>>(
ctx: &mut C,
src: ValueRegs<Reg>,
dst: ValueRegs<Writable<Reg>>,
amt: Reg,
is_signed: bool,
) {
let src_lo = src.regs()[0];
let src_hi = src.regs()[1];
let dst_lo = dst.regs()[0];
let dst_hi = dst.regs()[1];

// mvn inv_amt, amt
// lsl tmp1, src_lo, #1
// lsr tmp2, src_hi, amt
// lsl tmp1, tmp1, inv_amt
// lsr/asr tmp3, src_lo, amt
// tst amt, #0x40
// orr tmp2, tmp2, tmp1
//
// if signed:
// asr tmp4, src_hi, #63
// csel dst_hi, tmp4, tmp3, ne
// else:
// csel dst_hi, xzr, tmp3, ne
//
// csel dst_lo, tmp3, tmp2, ne

let xzr = writable_zero_reg();
let inv_amt = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp1 = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp2 = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp3 = ctx.alloc_tmp(I64).only_reg().unwrap();
let tmp4 = ctx.alloc_tmp(I64).only_reg().unwrap();

let shift_op = if is_signed {
ALUOp::Asr64
} else {
ALUOp::Lsr64
};

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::OrrNot32,
rd: inv_amt,
rn: xzr.to_reg(),
rm: amt,
});

ctx.emit(Inst::AluRRImmShift {
alu_op: ALUOp::Lsl64,
rd: tmp1,
rn: src_hi,
immshift: ImmShift::maybe_from_u64(1).unwrap(),
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Lsr64,
rd: tmp2,
rn: src_lo,
rm: amt,
});

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Lsl64,
rd: tmp1,
rn: tmp1.to_reg(),
rm: inv_amt.to_reg(),
});

ctx.emit(Inst::AluRRR {
alu_op: shift_op,
rd: tmp3,
rn: src_hi,
rm: amt,
});

ctx.emit(Inst::AluRRImmLogic {
alu_op: ALUOp::AndS64,
rd: xzr,
rn: amt,
imml: ImmLogic::maybe_from_u64(64, I64).unwrap(),
});

if is_signed {
ctx.emit(Inst::AluRRImmShift {
alu_op: ALUOp::Asr64,
rd: tmp4,
rn: src_hi,
immshift: ImmShift::maybe_from_u64(63).unwrap(),
});
}

ctx.emit(Inst::AluRRR {
alu_op: ALUOp::Orr64,
rd: tmp2,
rn: tmp2.to_reg(),
rm: tmp1.to_reg(),
});

ctx.emit(Inst::CSel {
cond: Cond::Ne,
rd: dst_hi,
rn: if is_signed { tmp4 } else { xzr }.to_reg(),
rm: tmp3.to_reg(),
});

ctx.emit(Inst::CSel {
cond: Cond::Ne,
rd: dst_lo,
rn: tmp3.to_reg(),
rm: tmp2.to_reg(),
});
}

//=============================================================================
// Lowering-backend trait implementation.

Expand Down
Loading