[llvm-dev] Fixed Point Support in LLVM

John McCall via llvm-dev llvm-dev at lists.llvm.org
Mon Aug 20 13:14:38 PDT 2018

> On Aug 20, 2018, at 1:59 PM, Leonard Chan via llvm-dev <llvm-dev at lists.llvm.org> wrote:
> We would like to discuss the possibility of adding support for fixed
> point operations, either through new types, instructions, or
> intrinsics. This is an extension to a previous proposal
> (http://lists.llvm.org/pipermail/cfe-dev/2018-April/057756.html) for
> implementing fixed point arithmetic entirely in clang, but John McCall
> brings up good points in the comments thread of
> https://reviews.llvm.org/D50616 for adding LLVM support.
> Just to summarize the proposal, Embedded-C lays out an implementation
> for fixed point data types and operations on them. A fixed point
> number is a number that contains a fractional and integral part. These
> types can essentially be represented as scaled integers, that is, a
> radix point exists somewhere in the integer that divides it into
> integral and fractional bits.
> Adding a new type seems unnecessary since all fixed point types in the
> spec can be represented as integers. For operations involving these
> integers, the scale could ideally be passed as an argument to whatever
> instruction or intrinsic is performing a fixed point operation. Iā€™m
> not sure of the difference in work between adding a new instruction vs
> intrinsic, but this would ideally be done for complex operations.

At the risk of distracting from your narrower proposal, I'd like to pitch the idea of adding
fixed-point values as a new fundamental type in IR.  I think it's really easy to assume
that this would be a dauntingly complicated task just because it's not something that
most people have experience doing.  Most of the complexity would be in targets, and
we could easily eliminate these types in a generic legalization pass in the backend to
reduce that impact.

And "all fixed point types in the spec can be represented as integers" is true
of literally everything in LLVM.  Every type we've got (except for opaque structs,
I guess) is a finite, fixed-size sequence of bits; nonetheless, we have direct support
for representing pointers, vectors, FP, and so on, when we could absolutely instead
use an appropriately-sized integer type, a large collection of intrinsics, and some sort
of "fpreg" attribute on call arguments to mark the difference in CCs.

In general, I think LLVM has gotten way too addicted to the pretense that adding things
as intrinsics or funky instruction attributes isn't adding just as much complexity as adding
new types and instructions.  LLVM should clearly provide portable support for fixed-point
operations.  We can do that with weird integer constants and a bunch of intrinsics, but
that seems to me like it's just hiding the complexity and making things harder for everyone

Fixed-point types would be quite similar to floating-point types in terms of their
overall impact on the complexity of IR ā€” which is to say, not very big ā€” except
predictably smaller because there's no analogue to the complexity around the
floating-point special cases (i.e. NaNs, negative zero, and infinities) and the various
features relating to them (e.g. the fast-math flags).  Type layout would just default to
using the rules for an integer of the same width.  There just isn't that much code in
LLVM that tries to do something different for every possible type instead of assuming

If we did this, I would suggest separating types by representation differences, not the
semantics of the operations on them.  For example, we'd have different operations for
saturating and non-saturating arithmetic, but saturating and non-saturing types would
get lowered to the same IR type.  Unlike integers, though, I think maybe we wouldn't
want to unify signed and unsigned types because of the padded-representation issue;
or maybe we'd only unify types with the same internal layout, so that a padded unsigned
type would be different from an unpadded one of the same overall width.

Note that having saturating-arithmetic instructions would also be useful for integers
and integer vectors, and could similarly be legalized generically in the backend for
targets that don't have direct ISA support for them.


> Namely, intrinsics/instructions would be added for these operations:
> - signed multiplication
> - signed saturating multiplication
> - signed division
> - unsigned division
> - signed saturating division
> - unsigned saturating division
> - saturation
> - saturating addition
> - saturating subtraction
> - floating-point to fixed-point conversion
> Bevin Hansson has implemented these in his downstream version of
> clang/llvm (http://lists.llvm.org/pipermail/cfe-dev/2018-May/058019.html),
> and I imagine this is all we may need for intrinsics. We would like to
> offset complicated instructions to llvm for targets that provide
> native support for these operations while still being able to manage
> most of the semantics on the frontend since many simple operations can
> be done using existing instructions. These operations will default to
> code generated IR for architectures that do not support fixed points
> natively.
> Does anyone have any more thoughts on how to correctly approach this?
> Thanks,
> Leo
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

More information about the llvm-dev mailing list