On calling intrinsics

I'm working on a simple embedded language which runs via the JIT. I've
reached the point of calling external functions.

I'm finding that when the docs say that not all intrinsics are supported
on all architectures, they're not kidding. For example, on my vanilla
amd64 box running Linux, if I try to use llvm.ceil.f64, I get an
unresolved symbol error ("Program used external function 'llvm.ceil.f64'
which could not be resolved!").

What's the best way around this?

AFAICT, I have two options:

- test for the presence of the intrinsic before emitting it, and call
out to libc if it's not

- always generate a libc function call, and trust to some optimisation
pass to convert it to an intrinsic if the target supports it

Any suggestions? I'm tending towards the second, as it involves less
target-specific knowledge, but I haven't found such an optimisation pass
yet...

From: llvmdev-bounces@cs.uiuc.edu [mailto:llvmdev-bounces@cs.uiuc.edu] On Behalf Of David Given
Subject: [LLVMdev] On calling intrinsics

if I try to use llvm.ceil.f64, I get an unresolved symbol error

That's because there is no llvm.ceil.* intrinsic defined in include/llvm/Intrinsics.td for 3.2; one for floor exists, but not ceil. However, ceil is defined in trunk, so you could download that from svn.

- Chuck

THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers.

[...]

That's because there is no llvm.ceil.* intrinsic defined in include/llvm/Intrinsics.td for 3.2

Ah. Yes, that would explain it... does this mean that I can rely on all
the intrinsics listed existing for the common types (int, float,
double)? Or should I be trying to follow the libc call route?

I've noticed that llc is successfully turning this:

define float @t(float %f) nounwind uwtable readnone {
  %1 = tail call float @sqrtf(float %f) nounwind readnone
  ret float %1
}

...into this:

t:
  sqrtss %xmm0, %xmm0
  ret

...but I haven't figured out what pass does it yet.

sqrtf is detected by code in SelectionDAGBuilder.cpp. This gets turns into a FSQRT ISD node type that the target can handle just like any other ISD node. If the target doesn’t mark ISD::FSQRT as Legal or Custom then ExpandNode in LegalizeDAG.cpp turns it back into a sqrtf libcall.

Solved! It turns out that the secret is that SelectionDAGBuilder only
converts such libcalls into intrinsics *if they are marked readnone*.
Which, of course, I wasn't doing in my JIT.

Anyway, ta. I'm producing much better code now.