Skip to content

Commit

Permalink
Review
Browse files Browse the repository at this point in the history
  • Loading branch information
JonPsson1 committed Nov 20, 2024
1 parent f0f15ef commit a128da7
Show file tree
Hide file tree
Showing 13 changed files with 480 additions and 283 deletions.
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ to ``float``; see below for more information on this emulation.
* SPIR (natively)
* X86 (if SSE2 is available; natively if AVX512-FP16 is also available)
* RISC-V (natively if Zfh or Zhinx is available)
* SystemZ (emulated)

* ``__bf16`` is supported on the following targets (currently never natively):

Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
// and instead the backend will promote each half operation to float
// individually.
HasLegalHalfType = false;
// Allow half arguments and return values (__fp16).
HalfArgsAndReturns = true;
// Support _Float16.
HasFloat16 = true;

Expand Down
1 change: 0 additions & 1 deletion clang/lib/CodeGen/Targets/SystemZ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {

if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
switch (BT->getKind()) {
case BuiltinType::Half: // __fp16
case BuiltinType::Float16: // _Float16
case BuiltinType::Float:
case BuiltinType::Double:
Expand Down
51 changes: 29 additions & 22 deletions clang/test/CodeGen/SystemZ/fp16.c
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -o - %s \
// RUN: | FileCheck %s

__fp16 f(__fp16 a, __fp16 b, __fp16 c, __fp16 d) {
return a * b + c * d;
void f(__fp16 *a, __fp16 *b, __fp16 *c, __fp16 *d, __fp16 *e) {
*e = (*a) * (*b) + (*c) * (*d);
}

// CHECK-LABEL: define dso_local half @f(half noundef %a, half noundef %b, half noundef %c, half noundef %d) #0 {
// CHECK-LABEL: define dso_local void @f(ptr noundef %a, ptr noundef %b, ptr noundef %c, ptr noundef %d, ptr noundef %e) #0 {
// CHECK-NEXT: entry:
// CHECK-NEXT: %a.addr = alloca half, align 2
// CHECK-NEXT: %b.addr = alloca half, align 2
// CHECK-NEXT: %c.addr = alloca half, align 2
// CHECK-NEXT: %d.addr = alloca half, align 2
// CHECK-NEXT: store half %a, ptr %a.addr, align 2
// CHECK-NEXT: store half %b, ptr %b.addr, align 2
// CHECK-NEXT: store half %c, ptr %c.addr, align 2
// CHECK-NEXT: store half %d, ptr %d.addr, align 2
// CHECK-NEXT: %0 = load half, ptr %a.addr, align 2
// CHECK-NEXT: %conv = fpext half %0 to float
// CHECK-NEXT: %1 = load half, ptr %b.addr, align 2
// CHECK-NEXT: %conv1 = fpext half %1 to float
// CHECK-NEXT: %a.addr = alloca ptr, align 8
// CHECK-NEXT: %b.addr = alloca ptr, align 8
// CHECK-NEXT: %c.addr = alloca ptr, align 8
// CHECK-NEXT: %d.addr = alloca ptr, align 8
// CHECK-NEXT: %e.addr = alloca ptr, align 8
// CHECK-NEXT: store ptr %a, ptr %a.addr, align 8
// CHECK-NEXT: store ptr %b, ptr %b.addr, align 8
// CHECK-NEXT: store ptr %c, ptr %c.addr, align 8
// CHECK-NEXT: store ptr %d, ptr %d.addr, align 8
// CHECK-NEXT: store ptr %e, ptr %e.addr, align 8
// CHECK-NEXT: %0 = load ptr, ptr %a.addr, align 8
// CHECK-NEXT: %1 = load half, ptr %0, align 2
// CHECK-NEXT: %conv = fpext half %1 to float
// CHECK-NEXT: %2 = load ptr, ptr %b.addr, align 8
// CHECK-NEXT: %3 = load half, ptr %2, align 2
// CHECK-NEXT: %conv1 = fpext half %3 to float
// CHECK-NEXT: %mul = fmul float %conv, %conv1
// CHECK-NEXT: %2 = load half, ptr %c.addr, align 2
// CHECK-NEXT: %conv2 = fpext half %2 to float
// CHECK-NEXT: %3 = load half, ptr %d.addr, align 2
// CHECK-NEXT: %conv3 = fpext half %3 to float
// CHECK-NEXT: %4 = load ptr, ptr %c.addr, align 8
// CHECK-NEXT: %5 = load half, ptr %4, align 2
// CHECK-NEXT: %conv2 = fpext half %5 to float
// CHECK-NEXT: %6 = load ptr, ptr %d.addr, align 8
// CHECK-NEXT: %7 = load half, ptr %6, align 2
// CHECK-NEXT: %conv3 = fpext half %7 to float
// CHECK-NEXT: %mul4 = fmul float %conv2, %conv3
// CHECK-NEXT: %add = fadd float %mul, %mul4
// CHECK-NEXT: %4 = fptrunc float %add to half
// CHECK-NEXT: ret half %4
// CHECK-NEXT: %8 = fptrunc float %add to half
// CHECK-NEXT: %9 = load ptr, ptr %e.addr, align 8
// CHECK-NEXT: store half %8, ptr %9, align 2
// CHECK-NEXT: ret void
// CHECK-NEXT: }

43 changes: 0 additions & 43 deletions clang/test/CodeGen/SystemZ/systemz-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ long long pass_longlong(long long arg) { return arg; }
__int128 pass_int128(__int128 arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_int128(ptr dead_on_unwind noalias writable sret(i128) align 8 %{{.*}}, ptr %0)

__fp16 pass___fp16(__fp16 arg) { return arg; }
// CHECK-LABEL: define{{.*}} half @pass___fp16(half %{{.*}})

_Float16 pass__Float16(_Float16 arg) { return arg; }
// CHECK-LABEL: define{{.*}} half @pass__Float16(half %{{.*}})

Expand Down Expand Up @@ -78,8 +75,6 @@ _Complex long pass_complex_long(_Complex long arg) { return arg; }
_Complex long long pass_complex_longlong(_Complex long long arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_complex_longlong(ptr dead_on_unwind noalias writable sret({ i64, i64 }) align 8 %{{.*}}, ptr %{{.*}}arg)

// _Complex __fp16 is (currently?) not allowed.

_Complex _Float16 pass_complex__Float16(_Complex _Float16 arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_complex__Float16(ptr dead_on_unwind noalias writable sret({ half, half }) align 2 %{{.*}}, ptr %{{.*}}arg)

Expand Down Expand Up @@ -134,11 +129,6 @@ struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }

// Float-like aggregate types

struct agg___fp16 { __fp16 a; };
struct agg___fp16 pass_agg___fp16(struct agg___fp16 arg) { return arg; }
// HARD-FLOAT-LABEL: define{{.*}} void @pass_agg___fp16(ptr dead_on_unwind noalias writable sret(%struct.agg___fp16) align 2 %{{.*}}, half %{{.*}})
// SOFT-FLOAT-LABEL: define{{.*}} void @pass_agg___fp16(ptr dead_on_unwind noalias writable sret(%struct.agg___fp16) align 2 %{{.*}}, i16 noext %{{.*}})

struct agg__Float16 { _Float16 a; };
struct agg__Float16 pass_agg__Float16(struct agg__Float16 arg) { return arg; }
// HARD-FLOAT-LABEL: define{{.*}} void @pass_agg__Float16(ptr dead_on_unwind noalias writable sret(%struct.agg__Float16) align 2 %{{.*}}, half %{{.*}})
Expand All @@ -158,11 +148,6 @@ struct agg_longdouble { long double a; };
struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_agg_longdouble(ptr dead_on_unwind noalias writable sret(%struct.agg_longdouble) align 8 %{{.*}}, ptr %{{.*}})

struct agg___fp16_a8 { __fp16 a __attribute__((aligned (8))); };
struct agg___fp16_a8 pass_agg___fp16_a8(struct agg___fp16_a8 arg) { return arg; }
// HARD-FLOAT-LABEL: define{{.*}} void @pass_agg___fp16_a8(ptr dead_on_unwind noalias writable sret(%struct.agg___fp16_a8) align 8 %{{.*}}, double %{{.*}})
// SOFT-FLOAT-LABEL: define{{.*}} void @pass_agg___fp16_a8(ptr dead_on_unwind noalias writable sret(%struct.agg___fp16_a8) align 8 %{{.*}}, i64 %{{.*}})

struct agg__Float16_a8 { _Float16 a __attribute__((aligned (8))); };
struct agg__Float16_a8 pass_agg__Float16_a8(struct agg__Float16_a8 arg) { return arg; }
// HARD-FLOAT-LABEL: define{{.*}} void @pass_agg__Float16_a8(ptr dead_on_unwind noalias writable sret(%struct.agg__Float16_a8) align 8 %{{.*}}, double %{{.*}})
Expand Down Expand Up @@ -195,10 +180,6 @@ struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }

// Union types likewise are *not* float-like aggregate types

union union___fp16 { __fp16 a; };
union union___fp16 pass_union___fp16(union union___fp16 arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_union___fp16(ptr dead_on_unwind noalias writable sret(%union.union___fp16) align 2 %{{.*}}, i16 noext %{{.*}})

union union__Float16 { _Float16 a; };
union union__Float16 pass_union__Float16(union union__Float16 arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_union__Float16(ptr dead_on_unwind noalias writable sret(%union.union__Float16) align 2 %{{.*}}, i16 noext %{{.*}})
Expand Down Expand Up @@ -480,30 +461,6 @@ struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l,
// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi ptr [ [[RAW_REG_ADDR]], %{{.*}} ], [ [[RAW_MEM_ADDR]], %{{.*}} ]
// CHECK: ret void

struct agg___fp16 va_agg___fp16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg___fp16); }
// CHECK-LABEL: define{{.*}} void @va_agg___fp16(ptr dead_on_unwind noalias writable sret(%struct.agg___fp16) align 2 %{{.*}}, ptr %{{.*}}
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %{{.*}}, i32 0, i32 1
// SOFT-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %{{.*}}, i32 0, i32 0
// CHECK: [[REG_COUNT:%[^ ]+]] = load i64, ptr [[REG_COUNT_PTR]]
// HARD-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4
// SOFT-FLOAT: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5
// CHECK: br i1 [[FITS_IN_REGS]],
// CHECK: [[SCALED_REG_COUNT:%[^ ]+]] = mul i64 [[REG_COUNT]], 8
// HARD-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 128
// SOFT-FLOAT: [[REG_OFFSET:%[^ ]+]] = add i64 [[SCALED_REG_COUNT]], 22
// CHECK: [[REG_SAVE_AREA_PTR:%[^ ]+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %{{.*}}, i32 0, i32 3
// CHECK: [[REG_SAVE_AREA:%[^ ]+]] = load ptr, ptr [[REG_SAVE_AREA_PTR:[^ ]+]]
// CHECK: [[RAW_REG_ADDR:%[^ ]+]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i64 [[REG_OFFSET]]
// CHECK: [[REG_COUNT1:%[^ ]+]] = add i64 [[REG_COUNT]], 1
// CHECK: store i64 [[REG_COUNT1]], ptr [[REG_COUNT_PTR]]
// CHECK: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %{{.*}}, i32 0, i32 2
// CHECK: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load ptr, ptr [[OVERFLOW_ARG_AREA_PTR]]
// CHECK: [[RAW_MEM_ADDR:%[^ ]+]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i64 6
// CHECK: [[OVERFLOW_ARG_AREA2:%[^ ]+]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i64 8
// CHECK: store ptr [[OVERFLOW_ARG_AREA2]], ptr [[OVERFLOW_ARG_AREA_PTR]]
// CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi ptr [ [[RAW_REG_ADDR]], %{{.*}} ], [ [[RAW_MEM_ADDR]], %{{.*}} ]
// CHECK: ret void

struct agg__Float16 va_agg__Float16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg__Float16); }
// CHECK-LABEL: define{{.*}} void @va_agg__Float16(ptr dead_on_unwind noalias writable sret(%struct.agg__Float16) align 2 %{{.*}}, ptr %{{.*}}
// HARD-FLOAT: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %{{.*}}, i32 0, i32 1
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT) {
if (!TT.isWasm()) {
// These libcalls are only available in compiler-rt, not libgcc.
if (TT.isArch32Bit()) {
setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
setLibcallName(RTLIB::SHL_I128, nullptr);
setLibcallName(RTLIB::SRL_I128, nullptr);
setLibcallName(RTLIB::SRA_I128, nullptr);
Expand All @@ -257,4 +255,9 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT) {
}
setLibcallName(RTLIB::MULO_I128, nullptr);
}

if (TT.isSystemZ()) {
setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
}
}
104 changes: 18 additions & 86 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,25 +524,16 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FP_EXTEND, VT, Custom);
setOperationAction(ISD::STRICT_FP_EXTEND, VT, Custom);
}
for (auto Op : {ISD::LOAD, ISD::ATOMIC_LOAD,
ISD::STORE, ISD::ATOMIC_STORE,
ISD::FP_ROUND, ISD::STRICT_FP_ROUND})
for (auto Op : {ISD::LOAD, ISD::ATOMIC_LOAD, ISD::STORE, ISD::ATOMIC_STORE})
setOperationAction(Op, MVT::f16, Custom);
setOperationAction(ISD::FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, LibCall);

for (unsigned I = MVT::FIRST_FP_VALUETYPE;
I <= MVT::LAST_FP_VALUETYPE;
++I) {
MVT VT = MVT::SimpleValueType(I);
if (isTypeLegal(VT)) {
// No special instructions for these.
setOperationAction(ISD::FSIN, VT, Expand);
setOperationAction(ISD::FCOS, VT, Expand);
setOperationAction(ISD::FSINCOS, VT, Expand);
setOperationAction(ISD::FREM, VT, Expand);
setOperationAction(ISD::FPOW, VT, Expand);
if (VT == MVT::f16)
continue;

if (isTypeLegal(VT) && VT != MVT::f16) {
// We can use FI for FRINT.
setOperationAction(ISD::FRINT, VT, Legal);

Expand All @@ -555,6 +546,13 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FROUND, VT, Legal);
}

// No special instructions for these.
setOperationAction(ISD::FSIN, VT, Expand);
setOperationAction(ISD::FCOS, VT, Expand);
setOperationAction(ISD::FSINCOS, VT, Expand);
setOperationAction(ISD::FREM, VT, Expand);
setOperationAction(ISD::FPOW, VT, Expand);

// Special treatment.
setOperationAction(ISD::IS_FPCLASS, VT, Custom);

Expand Down Expand Up @@ -6157,80 +6155,18 @@ static SDValue lowerAddrSpaceCast(SDValue Op, SelectionDAG &DAG) {
return Op;
}

SDValue SystemZTargetLowering::LowerFP_EXTEND(SDValue Op,
SDValue SystemZTargetLowering::lowerFP_EXTEND(SDValue Op,
SelectionDAG &DAG) const {
bool IsStrict = Op->isStrictFPOpcode();
SDValue In = Op.getOperand(IsStrict ? 1 : 0);
MVT VT = Op.getSimpleValueType();
MVT SVT = In.getSimpleValueType();
if (SVT != MVT::f16)
SDValue In = Op.getOperand(Op->isStrictFPOpcode() ? 1 : 0);
if (In.getSimpleValueType() != MVT::f16)
return Op; // Legal

SDLoc DL(Op);
SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue();

// Need a libcall. XXX factor out (below)
TargetLowering::CallLoweringInfo CLI(DAG);
Chain = IsStrict ? Op.getOperand(0) : DAG.getEntryNode();
TargetLowering::ArgListTy Args;
TargetLowering::ArgListEntry Entry;
Entry.Node = In;
Entry.Ty = EVT(SVT).getTypeForEVT(*DAG.getContext());
Args.push_back(Entry);
SDValue Callee = DAG.getExternalSymbol(
getLibcallName(RTLIB::FPEXT_F16_F32), getPointerTy(DAG.getDataLayout()));
CLI.setDebugLoc(DL).setChain(Chain).setLibCallee(
CallingConv::C, EVT(MVT::f32).getTypeForEVT(*DAG.getContext()), Callee,
std::move(Args));
SDValue Res;
std::tie(Res,Chain) = LowerCallTo(CLI);
if (IsStrict)
Res = DAG.getMergeValues({Res, Chain}, DL);

return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
}

SDValue SystemZTargetLowering::LowerFP_ROUND(SDValue Op,
SelectionDAG &DAG) const {
bool IsStrict = Op->isStrictFPOpcode();
SDValue In = Op.getOperand(IsStrict ? 1 : 0);
MVT VT = Op.getSimpleValueType();
MVT SVT = In.getSimpleValueType();
assert(VT == MVT::f16 && "Only rounding to f16 needs custom handling.");

SDLoc DL(Op);
SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue();

if (SVT != MVT::f32) {
SDValue Rnd = DAG.getIntPtrConstant(0, DL, /*isTarget=*/true);
In = DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, In, Rnd);
}

// We need a libcall.
TargetLowering::CallLoweringInfo CLI(DAG);
Chain = IsStrict ? Op.getOperand(0) : DAG.getEntryNode();
TargetLowering::ArgListTy Args;
TargetLowering::ArgListEntry Entry;
Entry.Node = In;
Entry.Ty = EVT(MVT::f32).getTypeForEVT(*DAG.getContext());
Args.push_back(Entry);
SDValue Callee = DAG.getExternalSymbol(
getLibcallName(RTLIB::FPROUND_F32_F16), getPointerTy(DAG.getDataLayout()));
CLI.setDebugLoc(DL).setChain(Chain).setLibCallee(
CallingConv::C, EVT(MVT::f16).getTypeForEVT(*DAG.getContext()), Callee,
std::move(Args));
SDValue Res;
std::tie(Res, Chain) = LowerCallTo(CLI);
if (IsStrict)
Res = DAG.getMergeValues({Res, Chain}, DL);
return Res;
return SDValue(); // Let legalizer emit the libcall.
}

SDValue SystemZTargetLowering::lowerLoadF16(SDValue Op,
SelectionDAG &DAG) const {
MVT RegVT = Op.getSimpleValueType();
if (RegVT != MVT::f16)
return SDValue();
assert(RegVT == MVT::f16 && "Expected to lower an f16 load.");

SDLoc DL(Op);
SDValue NewLd;
Expand Down Expand Up @@ -6262,8 +6198,7 @@ SDValue SystemZTargetLowering::lowerStoreF16(SDValue Op,
SelectionDAG &DAG) const {
SDValue StoredVal = Op->getOperand(1);
MVT StoreVT = StoredVal.getSimpleValueType();
if (StoreVT != MVT::f16)
return SDValue();
assert(StoreVT == MVT::f16 && "Expected to lower an f16 store.");

// Move into a GPR, shift and store the 2 bytes. TODO: Use VSTEH if available.
SDLoc DL(Op);
Expand Down Expand Up @@ -6463,10 +6398,7 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
return lowerShift(Op, DAG, SystemZISD::VROTL_BY_SCALAR);
case ISD::FP_EXTEND:
case ISD::STRICT_FP_EXTEND:
return LowerFP_EXTEND(Op, DAG);
case ISD::FP_ROUND:
case ISD::STRICT_FP_ROUND:
return LowerFP_ROUND(Op, DAG);
return lowerFP_EXTEND(Op, DAG);
case ISD::LOAD:
return lowerLoadF16(Op, DAG);
case ISD::STORE:
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,8 +721,7 @@ class SystemZTargetLowering : public TargetLowering {
SDValue lowerSIGN_EXTEND_VECTOR_INREG(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerZERO_EXTEND_VECTOR_INREG(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerShift(SDValue Op, SelectionDAG &DAG, unsigned ByScalar) const;
SDValue LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerLoadF16(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerStoreF16(SDValue Op, SelectionDAG &DAG) const;

Expand Down
Loading

0 comments on commit a128da7

Please sign in to comment.