Skip to content

Commit 003b58f

Browse files
committed
IR: Add llvm.frexp intrinsic
Add an intrinsic which returns the two pieces as multiple return values. Alternatively could introduce a pair of intrinsics to separately return the fractional and exponent parts. AMDGPU has native instructions to return the two halves, but could use some generic legalization and optimization handling. For example, we should be able to handle legalization of f16 on older targets, and for bf16. Additionally antique targets need a hardware workaround which would be better handled in the backend rather than in library code where it is now.
1 parent ee47699 commit 003b58f

31 files changed

+3184
-22
lines changed

llvm/docs/AMDGPUUsage.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ The AMDGPU backend implements the following LLVM IR intrinsics.
964964
inputs. Backend will optimize out denormal scaling if
965965
marked with the :ref:`afn <fastmath_afn>` flag.
966966

967+
:ref:`llvm.frexp <int_frexp>` Implemented for half, float and double.
967968

968969
========================================= ==========================================================
969970

llvm/docs/LangRef.rst

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14757,6 +14757,62 @@ value is returned. If the result underflows a zero with the same sign
1475714757
is returned. If the result overflows, the result is an infinity with
1475814758
the same sign.
1475914759

14760+
.. _int_frexp:
14761+
14762+
'``llvm.frexp.*``' Intrinsic
14763+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
14764+
14765+
Syntax:
14766+
"""""""
14767+
14768+
This is an overloaded intrinsic. You can use ``llvm.frexp`` on any
14769+
floating point or vector of floating point type. Not all targets support
14770+
all types however.
14771+
14772+
::
14773+
14774+
declare { float, i32 } @llvm.frexp.f32.i32(float %Val)
14775+
declare { double, i32 } @llvm.frexp.f64.i32(double %Val)
14776+
declare { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80 %Val)
14777+
declare { fp128, i32 } @llvm.frexp.f128.i32(fp128 %Val)
14778+
declare { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 %Val)
14779+
declare { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %Val)
14780+
14781+
Overview:
14782+
"""""""""
14783+
14784+
The '``llvm.frexp.*``' intrinsics perform the frexp function.
14785+
14786+
Arguments:
14787+
""""""""""
14788+
14789+
The argument is a :ref:`floating-point <t_floating>` or
14790+
:ref:`vector <t_vector>` of floating-point values. Returns two values
14791+
in a struct. The first struct field matches the argument type, and the
14792+
second field is an integer or a vector of integer values with the same
14793+
number of elements as the argument.
14794+
14795+
Semantics:
14796+
""""""""""
14797+
14798+
This intrinsic splits a floating point value into a normalized
14799+
fractional component and integral exponent.
14800+
14801+
For a non-zero argument, returns the argument multiplied by some power
14802+
of two such that the absolute value of the returned value is in the
14803+
range [0.5, 1.0), with the same sign as the argument. The second
14804+
result is an integer such that the first result raised to the power of
14805+
the second result is the input argument.
14806+
14807+
If the argument is a zero, returns a zero with the same sign and a 0
14808+
exponent.
14809+
14810+
If the argument is a NaN, a NaN is returned and the returned exponent
14811+
is unspecified.
14812+
14813+
If the argument is an infinity, returns an infinity with the same sign
14814+
and an unspecified exponent.
14815+
1476014816
'``llvm.log.*``' Intrinsic
1476114817
^^^^^^^^^^^^^^^^^^^^^^^^^^
1476214818

llvm/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ Changes to the LLVM IR
6363

6464
* Introduced new ``llvm.ldexp`` and ``llvm.experimental.constrained.ldexp`` intrinsics.
6565

66+
* Introduced new ``llvm.frexp`` intrinsic.
67+
6668
* The constant expression variants of the following instructions have been
6769
removed:
6870

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,13 @@ class MachineIRBuilder {
18321832
return buildInstr(TargetOpcode::G_FLDEXP, {Dst}, {Src0, Src1}, Flags);
18331833
}
18341834

1835+
/// Build and insert \p Fract, \p Exp = G_FFREXP \p Src
1836+
MachineInstrBuilder
1837+
buildFFrexp(const DstOp &Fract, const DstOp &Exp, const SrcOp &Src,
1838+
std::optional<unsigned> Flags = std::nullopt) {
1839+
return buildInstr(TargetOpcode::G_FFREXP, {Fract, Exp}, {Src}, Flags);
1840+
}
1841+
18351842
/// Build and insert \p Res = G_FCOPYSIGN \p Op0, \p Op1
18361843
MachineInstrBuilder buildFCopysign(const DstOp &Dst, const SrcOp &Src0,
18371844
const SrcOp &Src1) {

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,12 @@ enum NodeType {
931931
FPOWI,
932932
/// FLDEXP - ldexp, inspired by libm (op0 * 2**op1).
933933
FLDEXP,
934+
935+
/// FFREXP - frexp, extract fractional and exponent component of a
936+
/// floating-point value. Returns the two components as separate return
937+
/// values.
938+
FFREXP,
939+
934940
FLOG,
935941
FLOG2,
936942
FLOG10,

llvm/include/llvm/CodeGen/RuntimeLibcalls.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ namespace RTLIB {
7474
/// UNKNOWN_LIBCALL if there is none.
7575
Libcall getLDEXP(EVT RetVT);
7676

77+
/// getFREXP - Return the FREXP_* value for the given types, or
78+
/// UNKNOWN_LIBCALL if there is none.
79+
Libcall getFREXP(EVT RetVT);
80+
7781
/// Return the SYNC_FETCH_AND_* value for the given opcode and type, or
7882
/// UNKNOWN_LIBCALL if there is none.
7983
Libcall getSYNC(unsigned Opc, MVT VT);

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,9 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
10461046
// TODO: int operand should be constrained to same number of elements as the result.
10471047
def int_ldexp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>,
10481048
llvm_anyint_ty]>;
1049+
1050+
// TODO: Should constrain all element counts to match
1051+
def int_frexp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty, llvm_anyint_ty], [LLVMMatchType<0>]>;
10491052
}
10501053

10511054
def int_minnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],

llvm/include/llvm/IR/RuntimeLibcalls.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ HANDLE_LIBCALL(LDEXP_F64, "ldexp")
284284
HANDLE_LIBCALL(LDEXP_F80, "ldexpl")
285285
HANDLE_LIBCALL(LDEXP_F128, "ldexpl")
286286
HANDLE_LIBCALL(LDEXP_PPCF128, "ldexpl")
287+
HANDLE_LIBCALL(FREXP_F32, "frexpf")
288+
HANDLE_LIBCALL(FREXP_F64, "frexp")
289+
HANDLE_LIBCALL(FREXP_F80, "frexpl")
290+
HANDLE_LIBCALL(FREXP_F128, "frexpl")
291+
HANDLE_LIBCALL(FREXP_PPCF128, "frexpl")
287292

288293
// Floating point environment
289294
HANDLE_LIBCALL(FEGETENV, "fegetenv")

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,9 @@ HANDLE_TARGET_OPCODE(G_FLOG10)
619619
/// Floating point x * 2^n
620620
HANDLE_TARGET_OPCODE(G_FLDEXP)
621621

622+
/// Floating point extract fraction and exponent.
623+
HANDLE_TARGET_OPCODE(G_FFREXP)
624+
622625
/// Generic FP negation.
623626
HANDLE_TARGET_OPCODE(G_FNEG)
624627

llvm/include/llvm/Target/GenericOpcodes.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,13 @@ def G_FLDEXP : GenericInstruction {
930930
let hasSideEffects = false;
931931
}
932932

933+
// Floating point frexp
934+
def G_FFREXP : GenericInstruction {
935+
let OutOperandList = (outs type0:$dst0, type1:$dst1);
936+
let InOperandList = (ins type0:$src0);
937+
let hasSideEffects = false;
938+
}
939+
933940
// Floating point ceiling of a value.
934941
def G_FCEIL : GenericInstruction {
935942
let OutOperandList = (outs type0:$dst);

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,13 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
21752175
getOrCreateVReg(*CI.getArgOperand(0)),
21762176
MachineInstr::copyFlagsFromInstruction(CI));
21772177
return true;
2178+
case Intrinsic::frexp: {
2179+
ArrayRef<Register> VRegs = getOrCreateVRegs(CI);
2180+
MIRBuilder.buildFFrexp(VRegs[0], VRegs[1],
2181+
getOrCreateVReg(*CI.getArgOperand(0)),
2182+
MachineInstr::copyFlagsFromInstruction(CI));
2183+
return true;
2184+
}
21782185
case Intrinsic::memcpy_inline:
21792186
return translateMemFunc(CI, MIRBuilder, TargetOpcode::G_MEMCPY_INLINE);
21802187
case Intrinsic::memcpy:

llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,6 +2584,19 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
25842584

25852585
return UnableToLegalize;
25862586
}
2587+
case TargetOpcode::G_FFREXP: {
2588+
Observer.changingInstr(MI);
2589+
2590+
if (TypeIdx == 0) {
2591+
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
2592+
widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2593+
} else {
2594+
widenScalarDst(MI, WideTy, 1);
2595+
}
2596+
2597+
Observer.changedInstr(MI);
2598+
return Legalized;
2599+
}
25872600
case TargetOpcode::G_INTTOPTR:
25882601
if (TypeIdx != 1)
25892602
return UnableToLegalize;
@@ -4235,6 +4248,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
42354248
case G_STRICT_FMUL:
42364249
case G_STRICT_FMA:
42374250
case G_STRICT_FLDEXP:
4251+
case G_FFREXP:
42384252
return fewerElementsVectorMultiEltType(GMI, NumElts);
42394253
case G_ICMP:
42404254
case G_FCMP:

0 commit comments

Comments
 (0)