[FastISel][AArch64] Add support for non-native types for logical ops.

Extend the logical ops selection to also support non-native types such as i1,
i8, and i16.

Fixes rdar://problem/18330589.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217732 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Juergen Ributzka 2014-09-13 23:46:28 +00:00
parent c2104d4856
commit 5bf1f01c15
2 changed files with 224 additions and 36 deletions

View File

@ -114,7 +114,7 @@ class AArch64FastISel : public FastISel {
private: private:
// Selection routines. // Selection routines.
bool selectAddSub(const Instruction *I); bool selectAddSub(const Instruction *I);
bool selectLogicalOp(const Instruction *I); bool selectLogicalOp(const Instruction *I, unsigned ISDOpcode);
bool SelectLoad(const Instruction *I); bool SelectLoad(const Instruction *I);
bool SelectStore(const Instruction *I); bool SelectStore(const Instruction *I);
bool SelectBranch(const Instruction *I); bool SelectBranch(const Instruction *I);
@ -1235,9 +1235,6 @@ unsigned AArch64FastISel::emitSubs_rs(MVT RetVT, unsigned LHSReg,
unsigned AArch64FastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT, unsigned AArch64FastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT,
const Value *LHS, const Value *RHS) { const Value *LHS, const Value *RHS) {
if (RetVT != MVT::i32 && RetVT != MVT::i64)
return 0;
// Canonicalize immediates to the RHS first. // Canonicalize immediates to the RHS first.
if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS)) if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS))
std::swap(LHS, RHS); std::swap(LHS, RHS);
@ -1281,8 +1278,13 @@ unsigned AArch64FastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT,
return 0; return 0;
bool RHSIsKill = hasTrivialKill(RHS); bool RHSIsKill = hasTrivialKill(RHS);
return fastEmit_rr(RetVT, RetVT, ISDOpc, LHSReg, LHSIsKill, RHSReg, MVT VT = std::max(MVT::i32, RetVT.SimpleTy);
RHSIsKill); ResultReg = fastEmit_rr(VT, VT, ISDOpc, LHSReg, LHSIsKill, RHSReg, RHSIsKill);
if (RetVT >= MVT::i8 && RetVT <= MVT::i16) {
uint64_t Mask = (RetVT == MVT::i8) ? 0xff : 0xffff;
ResultReg = emitAnd_ri(MVT::i32, ResultReg, /*IsKill=*/true, Mask);
}
return ResultReg;
} }
unsigned AArch64FastISel::emitLogicalOp_ri(unsigned ISDOpc, MVT RetVT, unsigned AArch64FastISel::emitLogicalOp_ri(unsigned ISDOpc, MVT RetVT,
@ -1301,6 +1303,9 @@ unsigned AArch64FastISel::emitLogicalOp_ri(unsigned ISDOpc, MVT RetVT,
switch (RetVT.SimpleTy) { switch (RetVT.SimpleTy) {
default: default:
return 0; return 0;
case MVT::i1:
case MVT::i8:
case MVT::i16:
case MVT::i32: { case MVT::i32: {
unsigned Idx = ISDOpc - ISD::AND; unsigned Idx = ISDOpc - ISD::AND;
Opc = OpcTable[Idx][0]; Opc = OpcTable[Idx][0];
@ -1318,8 +1323,14 @@ unsigned AArch64FastISel::emitLogicalOp_ri(unsigned ISDOpc, MVT RetVT,
if (!AArch64_AM::isLogicalImmediate(Imm, RegSize)) if (!AArch64_AM::isLogicalImmediate(Imm, RegSize))
return 0; return 0;
return fastEmitInst_ri(Opc, RC, LHSReg, LHSIsKill, unsigned ResultReg =
AArch64_AM::encodeLogicalImmediate(Imm, RegSize)); fastEmitInst_ri(Opc, RC, LHSReg, LHSIsKill,
AArch64_AM::encodeLogicalImmediate(Imm, RegSize));
if (RetVT >= MVT::i8 && RetVT <= MVT::i16 && ISDOpc != ISD::AND) {
uint64_t Mask = (RetVT == MVT::i8) ? 0xff : 0xffff;
ResultReg = emitAnd_ri(MVT::i32, ResultReg, /*IsKill=*/true, Mask);
}
return ResultReg;
} }
unsigned AArch64FastISel::emitLogicalOp_rs(unsigned ISDOpc, MVT RetVT, unsigned AArch64FastISel::emitLogicalOp_rs(unsigned ISDOpc, MVT RetVT,
@ -1336,19 +1347,28 @@ unsigned AArch64FastISel::emitLogicalOp_rs(unsigned ISDOpc, MVT RetVT,
const TargetRegisterClass *RC; const TargetRegisterClass *RC;
unsigned Opc; unsigned Opc;
switch (RetVT.SimpleTy) { switch (RetVT.SimpleTy) {
default: default:
return 0; return 0;
case MVT::i32: case MVT::i1:
Opc = OpcTable[ISDOpc - ISD::AND][0]; case MVT::i8:
RC = &AArch64::GPR32RegClass; case MVT::i16:
break; case MVT::i32:
case MVT::i64: Opc = OpcTable[ISDOpc - ISD::AND][0];
Opc = OpcTable[ISDOpc - ISD::AND][1]; RC = &AArch64::GPR32RegClass;
RC = &AArch64::GPR64RegClass; break;
break; case MVT::i64:
Opc = OpcTable[ISDOpc - ISD::AND][1];
RC = &AArch64::GPR64RegClass;
break;
} }
return fastEmitInst_rri(Opc, RC, LHSReg, LHSIsKill, RHSReg, RHSIsKill, unsigned ResultReg =
AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftImm)); fastEmitInst_rri(Opc, RC, LHSReg, LHSIsKill, RHSReg, RHSIsKill,
AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftImm));
if (RetVT >= MVT::i8 && RetVT <= MVT::i16) {
uint64_t Mask = (RetVT == MVT::i8) ? 0xff : 0xffff;
ResultReg = emitAnd_ri(MVT::i32, ResultReg, /*IsKill=*/true, Mask);
}
return ResultReg;
} }
unsigned AArch64FastISel::emitAnd_ri(MVT RetVT, unsigned LHSReg, bool LHSIsKill, unsigned AArch64FastISel::emitAnd_ri(MVT RetVT, unsigned LHSReg, bool LHSIsKill,
@ -1447,25 +1467,11 @@ bool AArch64FastISel::selectAddSub(const Instruction *I) {
return true; return true;
} }
bool AArch64FastISel::selectLogicalOp(const Instruction *I) { bool AArch64FastISel::selectLogicalOp(const Instruction *I, unsigned ISDOpc) {
MVT VT; MVT VT;
if (!isTypeSupported(I->getType(), VT)) if (!isTypeSupported(I->getType(), VT))
return false; return false;
unsigned ISDOpc;
switch (I->getOpcode()) {
default:
llvm_unreachable("Unexpected opcode.");
case Instruction::And:
ISDOpc = ISD::AND;
break;
case Instruction::Or:
ISDOpc = ISD::OR;
break;
case Instruction::Xor:
ISDOpc = ISD::XOR;
break;
}
unsigned ResultReg = unsigned ResultReg =
emitLogicalOp(ISDOpc, VT, I->getOperand(0), I->getOperand(1)); emitLogicalOp(ISDOpc, VT, I->getOperand(0), I->getOperand(1));
if (!ResultReg) if (!ResultReg)
@ -3578,9 +3584,15 @@ bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
return true; return true;
break; break;
case Instruction::And: case Instruction::And:
if (selectLogicalOp(I, ISD::AND))
return true;
break;
case Instruction::Or: case Instruction::Or:
if (selectLogicalOp(I, ISD::OR))
return true;
break;
case Instruction::Xor: case Instruction::Xor:
if (selectLogicalOp(I)) if (selectLogicalOp(I, ISD::XOR))
return true; return true;
break; break;
case Instruction::Br: case Instruction::Br:

View File

@ -2,6 +2,29 @@
; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel=1 -fast-isel-abort -verify-machineinstrs < %s | FileCheck %s ; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel=1 -fast-isel-abort -verify-machineinstrs < %s | FileCheck %s
; AND ; AND
define zeroext i1 @and_rr_i1(i1 signext %a, i1 signext %b) {
; CHECK-LABEL: and_rr_i1
; CHECK: and [[REG:w[0-9]+]], w0, w1
%1 = and i1 %a, %b
ret i1 %1
}
define zeroext i8 @and_rr_i8(i8 signext %a, i8 signext %b) {
; CHECK-LABEL: and_rr_i8
; CHECK: and [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xff
%1 = and i8 %a, %b
ret i8 %1
}
define zeroext i16 @and_rr_i16(i16 signext %a, i16 signext %b) {
; CHECK-LABEL: and_rr_i16
; CHECK: and [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xffff
%1 = and i16 %a, %b
ret i16 %1
}
define i32 @and_rr_i32(i32 %a, i32 %b) { define i32 @and_rr_i32(i32 %a, i32 %b) {
; CHECK-LABEL: and_rr_i32 ; CHECK-LABEL: and_rr_i32
; CHECK: and w0, w0, w1 ; CHECK: and w0, w0, w1
@ -16,6 +39,27 @@ define i64 @and_rr_i64(i64 %a, i64 %b) {
ret i64 %1 ret i64 %1
} }
define zeroext i1 @and_ri_i1(i1 signext %a) {
; CHECK-LABEL: and_ri_i1
; CHECK: and {{w[0-9]+}}, w0, #0x1
%1 = and i1 %a, 1
ret i1 %1
}
define zeroext i8 @and_ri_i8(i8 signext %a) {
; CHECK-LABEL: and_ri_i8
; CHECK: and {{w[0-9]+}}, w0, #0xf
%1 = and i8 %a, 15
ret i8 %1
}
define zeroext i16 @and_ri_i16(i16 signext %a) {
; CHECK-LABEL: and_ri_i16
; CHECK: and {{w[0-9]+}}, w0, #0xff
%1 = and i16 %a, 255
ret i16 %1
}
define i32 @and_ri_i32(i32 %a) { define i32 @and_ri_i32(i32 %a) {
; CHECK-LABEL: and_ri_i32 ; CHECK-LABEL: and_ri_i32
; CHECK: and w0, w0, #0xff ; CHECK: and w0, w0, #0xff
@ -30,6 +74,24 @@ define i64 @and_ri_i64(i64 %a) {
ret i64 %1 ret i64 %1
} }
define zeroext i8 @and_rs_i8(i8 signext %a, i8 signext %b) {
; CHECK-LABEL: and_rs_i8
; CHECK: and [[REG:w[0-9]+]], w0, w1, lsl #4
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xff|#0xf0}}
%1 = shl i8 %b, 4
%2 = and i8 %a, %1
ret i8 %2
}
define zeroext i16 @and_rs_i16(i16 signext %a, i16 signext %b) {
; CHECK-LABEL: and_rs_i16
; CHECK: and [[REG:w[0-9]+]], w0, w1, lsl #8
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xffff|#0xff00}}
%1 = shl i16 %b, 8
%2 = and i16 %a, %1
ret i16 %2
}
define i32 @and_rs_i32(i32 %a, i32 %b) { define i32 @and_rs_i32(i32 %a, i32 %b) {
; CHECK-LABEL: and_rs_i32 ; CHECK-LABEL: and_rs_i32
; CHECK: and w0, w0, w1, lsl #8 ; CHECK: and w0, w0, w1, lsl #8
@ -47,6 +109,29 @@ define i64 @and_rs_i64(i64 %a, i64 %b) {
} }
; OR ; OR
define zeroext i1 @or_rr_i1(i1 signext %a, i1 signext %b) {
; CHECK-LABEL: or_rr_i1
; CHECK: orr [[REG:w[0-9]+]], w0, w1
%1 = or i1 %a, %b
ret i1 %1
}
define zeroext i8 @or_rr_i8(i8 signext %a, i8 signext %b) {
; CHECK-LABEL: or_rr_i8
; CHECK: orr [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xff
%1 = or i8 %a, %b
ret i8 %1
}
define zeroext i16 @or_rr_i16(i16 signext %a, i16 signext %b) {
; CHECK-LABEL: or_rr_i16
; CHECK: orr [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xffff
%1 = or i16 %a, %b
ret i16 %1
}
define i32 @or_rr_i32(i32 %a, i32 %b) { define i32 @or_rr_i32(i32 %a, i32 %b) {
; CHECK-LABEL: or_rr_i32 ; CHECK-LABEL: or_rr_i32
; CHECK: orr w0, w0, w1 ; CHECK: orr w0, w0, w1
@ -61,6 +146,22 @@ define i64 @or_rr_i64(i64 %a, i64 %b) {
ret i64 %1 ret i64 %1
} }
define zeroext i8 @or_ri_i8(i8 %a) {
; CHECK-LABEL: or_ri_i8
; CHECK: orr [[REG:w[0-9]+]], w0, #0xf
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xff
%1 = or i8 %a, 15
ret i8 %1
}
define zeroext i16 @or_ri_i16(i16 %a) {
; CHECK-LABEL: or_ri_i16
; CHECK: orr [[REG:w[0-9]+]], w0, #0xff
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xffff
%1 = or i16 %a, 255
ret i16 %1
}
define i32 @or_ri_i32(i32 %a) { define i32 @or_ri_i32(i32 %a) {
; CHECK-LABEL: or_ri_i32 ; CHECK-LABEL: or_ri_i32
; CHECK: orr w0, w0, #0xff ; CHECK: orr w0, w0, #0xff
@ -75,6 +176,24 @@ define i64 @or_ri_i64(i64 %a) {
ret i64 %1 ret i64 %1
} }
define zeroext i8 @or_rs_i8(i8 signext %a, i8 signext %b) {
; CHECK-LABEL: or_rs_i8
; CHECK: orr [[REG:w[0-9]+]], w0, w1, lsl #4
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xff|#0xf0}}
%1 = shl i8 %b, 4
%2 = or i8 %a, %1
ret i8 %2
}
define zeroext i16 @or_rs_i16(i16 signext %a, i16 signext %b) {
; CHECK-LABEL: or_rs_i16
; CHECK: orr [[REG:w[0-9]+]], w0, w1, lsl #8
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xffff|#0xff00}}
%1 = shl i16 %b, 8
%2 = or i16 %a, %1
ret i16 %2
}
define i32 @or_rs_i32(i32 %a, i32 %b) { define i32 @or_rs_i32(i32 %a, i32 %b) {
; CHECK-LABEL: or_rs_i32 ; CHECK-LABEL: or_rs_i32
; CHECK: orr w0, w0, w1, lsl #8 ; CHECK: orr w0, w0, w1, lsl #8
@ -92,6 +211,29 @@ define i64 @or_rs_i64(i64 %a, i64 %b) {
} }
; XOR ; XOR
define zeroext i1 @xor_rr_i1(i1 signext %a, i1 signext %b) {
; CHECK-LABEL: xor_rr_i1
; CHECK: eor [[REG:w[0-9]+]], w0, w1
%1 = xor i1 %a, %b
ret i1 %1
}
define zeroext i8 @xor_rr_i8(i8 signext %a, i8 signext %b) {
; CHECK-LABEL: xor_rr_i8
; CHECK: eor [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xff
%1 = xor i8 %a, %b
ret i8 %1
}
define zeroext i16 @xor_rr_i16(i16 signext %a, i16 signext %b) {
; CHECK-LABEL: xor_rr_i16
; CHECK: eor [[REG:w[0-9]+]], w0, w1
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xffff
%1 = xor i16 %a, %b
ret i16 %1
}
define i32 @xor_rr_i32(i32 %a, i32 %b) { define i32 @xor_rr_i32(i32 %a, i32 %b) {
; CHECK-LABEL: xor_rr_i32 ; CHECK-LABEL: xor_rr_i32
; CHECK: eor w0, w0, w1 ; CHECK: eor w0, w0, w1
@ -106,6 +248,22 @@ define i64 @xor_rr_i64(i64 %a, i64 %b) {
ret i64 %1 ret i64 %1
} }
define zeroext i8 @xor_ri_i8(i8 signext %a) {
; CHECK-LABEL: xor_ri_i8
; CHECK: eor [[REG:w[0-9]+]], w0, #0xf
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xff
%1 = xor i8 %a, 15
ret i8 %1
}
define zeroext i16 @xor_ri_i16(i16 signext %a) {
; CHECK-LABEL: xor_ri_i16
; CHECK: eor [[REG:w[0-9]+]], w0, #0xff
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], #0xffff
%1 = xor i16 %a, 255
ret i16 %1
}
define i32 @xor_ri_i32(i32 %a) { define i32 @xor_ri_i32(i32 %a) {
; CHECK-LABEL: xor_ri_i32 ; CHECK-LABEL: xor_ri_i32
; CHECK: eor w0, w0, #0xff ; CHECK: eor w0, w0, #0xff
@ -120,6 +278,24 @@ define i64 @xor_ri_i64(i64 %a) {
ret i64 %1 ret i64 %1
} }
define zeroext i8 @xor_rs_i8(i8 %a, i8 %b) {
; CHECK-LABEL: xor_rs_i8
; CHECK: eor [[REG:w[0-9]+]], w0, w1, lsl #4
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xff|#0xf0}}
%1 = shl i8 %b, 4
%2 = xor i8 %a, %1
ret i8 %2
}
define zeroext i16 @xor_rs_i16(i16 %a, i16 %b) {
; CHECK-LABEL: xor_rs_i16
; CHECK: eor [[REG:w[0-9]+]], w0, w1, lsl #8
; CHECK-NEXT: and {{w[0-9]+}}, [[REG]], {{#0xffff|#0xff00}}
%1 = shl i16 %b, 8
%2 = xor i16 %a, %1
ret i16 %2
}
define i32 @xor_rs_i32(i32 %a, i32 %b) { define i32 @xor_rs_i32(i32 %a, i32 %b) {
; CHECK-LABEL: xor_rs_i32 ; CHECK-LABEL: xor_rs_i32
; CHECK: eor w0, w0, w1, lsl #8 ; CHECK: eor w0, w0, w1, lsl #8