AArch64: implement efficient f16 bitcasts

Because i16 is illegal, there's no native DAG method to
represent a bitcast to or from an f16 type. This meant LLVM was
inserting a stack store/load pair which is really not ideal.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213378 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tim Northover 2014-07-18 13:07:05 +00:00
parent b41b1d4bac
commit e72ff8829e
2 changed files with 64 additions and 0 deletions

View File

@ -317,6 +317,10 @@ AArch64TargetLowering::AArch64TargetLowering(TargetMachine &TM)
setTruncStoreAction(MVT::f128, MVT::f64, Expand); setTruncStoreAction(MVT::f128, MVT::f64, Expand);
setTruncStoreAction(MVT::f128, MVT::f32, Expand); setTruncStoreAction(MVT::f128, MVT::f32, Expand);
setTruncStoreAction(MVT::f128, MVT::f16, Expand); setTruncStoreAction(MVT::f128, MVT::f16, Expand);
setOperationAction(ISD::BITCAST, MVT::i16, Custom);
setOperationAction(ISD::BITCAST, MVT::f16, Custom);
// Indexed loads and stores are supported. // Indexed loads and stores are supported.
for (unsigned im = (unsigned)ISD::PRE_INC; for (unsigned im = (unsigned)ISD::PRE_INC;
im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) {
@ -1510,12 +1514,30 @@ SDValue AArch64TargetLowering::LowerFSINCOS(SDValue Op,
return CallResult.first; return CallResult.first;
} }
static SDValue LowerBITCAST(SDValue Op, SelectionDAG &DAG) {
if (Op.getValueType() != MVT::f16)
return SDValue();
assert(Op.getOperand(0).getValueType() == MVT::i16);
SDLoc DL(Op);
Op = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Op.getOperand(0));
Op = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Op);
return SDValue(
DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, MVT::f16, Op,
DAG.getTargetConstant(AArch64::hsub, MVT::i32)),
0);
}
SDValue AArch64TargetLowering::LowerOperation(SDValue Op, SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const { SelectionDAG &DAG) const {
switch (Op.getOpcode()) { switch (Op.getOpcode()) {
default: default:
llvm_unreachable("unimplemented operand"); llvm_unreachable("unimplemented operand");
return SDValue(); return SDValue();
case ISD::BITCAST:
return LowerBITCAST(Op, DAG);
case ISD::GlobalAddress: case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG); return LowerGlobalAddress(Op, DAG);
case ISD::GlobalTLSAddress: case ISD::GlobalTLSAddress:
@ -7942,11 +7964,32 @@ bool AArch64TargetLowering::getPostIndexedAddressParts(
return true; return true;
} }
static void ReplaceBITCASTResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) {
if (N->getValueType(0) != MVT::i16)
return;
SDLoc DL(N);
SDValue Op = N->getOperand(0);
assert(Op.getValueType() == MVT::f16 &&
"Inconsistent bitcast? Only 16-bit types should be i16 or f16");
Op = SDValue(
DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL, MVT::f32,
DAG.getUNDEF(MVT::i32), Op,
DAG.getTargetConstant(AArch64::hsub, MVT::i32)),
0);
Op = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op);
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Op));
}
void AArch64TargetLowering::ReplaceNodeResults( void AArch64TargetLowering::ReplaceNodeResults(
SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const { SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
switch (N->getOpcode()) { switch (N->getOpcode()) {
default: default:
llvm_unreachable("Don't know how to custom expand this"); llvm_unreachable("Don't know how to custom expand this");
case ISD::BITCAST:
ReplaceBITCASTResults(N, Results, DAG);
return;
case ISD::FP_TO_UINT: case ISD::FP_TO_UINT:
case ISD::FP_TO_SINT: case ISD::FP_TO_SINT:
assert(N->getValueType(0) == MVT::i128 && "unexpected illegal conversion"); assert(N->getValueType(0) == MVT::i128 && "unexpected illegal conversion");

View File

@ -17,6 +17,16 @@ define i16 @test_bitcast_from_half(half* %addr) {
ret i16 %val_int ret i16 %val_int
} }
define i16 @test_reg_bitcast_from_half(half %in) {
; CHECK-LABEL: test_reg_bitcast_from_half:
; CHECK-NOT: str
; CHECK-NOT: ldr
; CHECK-DAG: fmov w0, s0
; CHECK: ret
%val = bitcast half %in to i16
ret i16 %val
}
define void @test_bitcast_to_half(half* %addr, i16 %in) { define void @test_bitcast_to_half(half* %addr, i16 %in) {
; CHECK-LABEL: test_bitcast_to_half: ; CHECK-LABEL: test_bitcast_to_half:
; CHECK: strh w1, [x0] ; CHECK: strh w1, [x0]
@ -25,6 +35,17 @@ define void @test_bitcast_to_half(half* %addr, i16 %in) {
ret void ret void
} }
define half @test_reg_bitcast_to_half(i16 %in) {
; CHECK-LABEL: test_reg_bitcast_to_half:
; CHECK-NOT: str
; CHECK-NOT: ldr
; CHECK-DAG: fmov s0, w0
; CHECK: ret
%val = bitcast i16 %in to half
ret half %val
}
define float @test_extend32(half* %addr) { define float @test_extend32(half* %addr) {
; CHECK-LABEL: test_extend32: ; CHECK-LABEL: test_extend32:
; CHECK: fcvt {{s[0-9]+}}, {{h[0-9]+}} ; CHECK: fcvt {{s[0-9]+}}, {{h[0-9]+}}