From eb922109f9d451c05dd258df5e4580ebc3249e51 Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Mon, 18 Aug 2014 14:22:39 +0000 Subject: [PATCH] Teach the AArch64 backend to handle f16 This allows the AArch64 backend to handle fadd, fsub, fmul and fdiv operations on f16 (half-precision) types by promoting to f32. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215891 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 3 + lib/Target/AArch64/AArch64ISelLowering.cpp | 9 ++ test/CodeGen/AArch64/fp16-instructions.ll | 109 +++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 test/CodeGen/AArch64/fp16-instructions.ll diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 232cbd81f76..ea88264d95f 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -4264,6 +4264,9 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) { Tmp1, Tmp2, Node->getOperand(2))); break; } + case ISD::FADD: + case ISD::FSUB: + case ISD::FMUL: case ISD::FDIV: case ISD::FREM: case ISD::FPOW: { diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index e277a5e0780..49e0ed2e2ab 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -278,6 +278,15 @@ AArch64TargetLowering::AArch64TargetLowering(TargetMachine &TM) setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); + // f16 is storage-only, so we promote operations to f32 if we know this is + // valid, and ignore them otherwise. The operations not mentioned here will + // fail to select, but this is not a major problem as no source language + // should be emitting native f16 operations yet. + setOperationAction(ISD::FADD, MVT::f16, Promote); + setOperationAction(ISD::FDIV, MVT::f16, Promote); + setOperationAction(ISD::FMUL, MVT::f16, Promote); + setOperationAction(ISD::FSUB, MVT::f16, Promote); + // AArch64 has implementations of a lot of rounding-like FP operations. static MVT RoundingTypes[] = { MVT::f32, MVT::f64}; for (unsigned I = 0; I < array_lengthof(RoundingTypes); ++I) { diff --git a/test/CodeGen/AArch64/fp16-instructions.ll b/test/CodeGen/AArch64/fp16-instructions.ll new file mode 100644 index 00000000000..ab5cf6c6047 --- /dev/null +++ b/test/CodeGen/AArch64/fp16-instructions.ll @@ -0,0 +1,109 @@ +; RUN: llc < %s -mtriple=aarch64-none-eabi | FileCheck %s + +define half @add_h(half %a, half %b) { +entry: +; CHECK-LABEL: add_h: +; CHECK: fcvt +; CHECK: fcvt +; CHECK: fadd +; CHECK: fcvt + %0 = fadd half %a, %b + ret half %0 +} + + +define half @sub_h(half %a, half %b) { +entry: +; CHECK-LABEL: sub_h: +; CHECK: fcvt +; CHECK: fcvt +; CHECK: fsub +; CHECK: fcvt + %0 = fsub half %a, %b + ret half %0 +} + + +define half @mul_h(half %a, half %b) { +entry: +; CHECK-LABEL: mul_h: +; CHECK: fcvt +; CHECK: fcvt +; CHECK: fmul +; CHECK: fcvt + %0 = fmul half %a, %b + ret half %0 +} + + +define half @div_h(half %a, half %b) { +entry: +; CHECK-LABEL: div_h: +; CHECK: fcvt +; CHECK: fcvt +; CHECK: fdiv +; CHECK: fcvt + %0 = fdiv half %a, %b + ret half %0 +} + + +define half @load_h(half* %a) { +entry: +; CHECK-LABEL: load_h: +; CHECK: ldr h + %0 = load half* %a, align 4 + ret half %0 +} + + +define void @store_h(half* %a, half %b) { +entry: +; CHECK-LABEL: store_h: +; CHECK: str h + store half %b, half* %a, align 4 + ret void +} + +define half @s_to_h(float %a) { +; CHECK-LABEL: s_to_h: +; CHECK: fcvt + %1 = fptrunc float %a to half + ret half %1 +} + +define half @d_to_h(double %a) { +; CHECK-LABEL: d_to_h: +; CHECK: fcvt + %1 = fptrunc double %a to half + ret half %1 +} + +define float @h_to_s(half %a) { +; CHECK-LABEL: h_to_s: +; CHECK: fcvt + %1 = fpext half %a to float + ret float %1 +} + +define double @h_to_d(half %a) { +; CHECK-LABEL: h_to_d: +; CHECK: fcvt + %1 = fpext half %a to double + ret double %1 +} + +define half @bitcast_i_to_h(i16 %a) { +; CHECK-LABEL: bitcast_i_to_h: +; CHECK: fmov + %1 = bitcast i16 %a to half + ret half %1 +} + + +define i16 @bitcast_h_to_i(half %a) { +; CHECK-LABEL: bitcast_h_to_i: +; CHECK: fmov + %1 = bitcast half %a to i16 + ret i16 %1 +}