need help adding arch-specific builtin

Hi lists,

I'm trying to add a new compiler builtin for AVR architecture,
`void __builtin_avr_delay_cycles(int32)`.

I already made clang recognize this as a builtin with the correct type.
Now there are some assumptions on what I have to do:

* I think have to map this to an arch-specific intrinsic in LLVM
* in clang/lib/CodeGen/CGBuiltin I'd have to add a function for AVR
   builtins and call it from EmitTargetArchBuiltinExpr
* in this new function, I would generate the actual instructions -
   building the "generate code from builtin call" part

I added an intrinsic for this[1] and added the function in CGBuiltin and
call it for Arch == llvm::Triple::avr - but cannot get my new code to be
called. I even added an `assert(false)` in EmitTargetArchBuiltinExpr(),
which should cause the compiler to crash on that assert whenever it is
supposed to handle a builtin for AVR targets - but that assert never

Instead, I get the error given below [2], which I cannot make a lot out
of it.

With my not-yet-very-good knowledge how everything is combined together
in clang and llvm, I assume this might be because it tries to pass a i32
to the builtin (which is expected), but cannot do that because the arch
cannot pass i32s around in arguments? But that shouldn't be needed for a
builtin - that call to it shouldn't be in the resulting machine code

Any clues where to find more information on how to achieve what I'm
trying to do would be appreciated. I poked around at a lot of different
places in the code base by now, trying to find more info by myself, but
am stuck.

The builtin in question is supposed to generate a loop taking the given
amount of clock cycles to complete - something commonly used on
microcontrollers to have timing. Frequency of the CPU is known at
compile time via preprocessor definition for that and the builtin
already exists on gcc, I just want to also have it in clang.

Thanks for any help and comments
(I subscribed to cfe-dev in digest mode only - answering me directly too
would be appreciated)

[1] I added this into llvm/include/llvm/IR/, which I
include from llvm/include/llvm/IR/

let TargetPrefix = "avr" in { // All intrinsics start with "llvm.avr."
   def int_avr_delay_cycles : GCCBuiltin<"__builtin_avr_delay_cycles">,
               Intrinsic<, [llvm_i32_ty], [IntrInaccessibleMemOnly, IntrCold, IntrNoDuplicate, IntrNoMerge, IntrHasSideEffects]>;

[2] Trying to compile code using this builtin results in this error:
ExpandIntegerOperand Op #2: t8: ch = llvm.avr.delay.cycles t5, TargetConstant:i16<2445>, Constant:i32<8000000>

If you add GCCBuiltin to the intrinsic definition, clang will automatically do the conversion from C to IR. EmitTargetArchBuiltin will only be called if no GCCBuiltin can be found.

that's good to know, thank you. Where is the code generation for those
intrinsics then?

(forwarded to list because I don't use mailings lists very often and
answered Craig only..)

The C to IR conversion happens in CGBuiltin.cpp where it calls

The error your getting is coming from SelectionDAG. The error seems to indicate that i32 is not a legal type for the AVR and LegalizeIntegerTypes.cpp does know how to make it legal. It wants to split into 2 i16s but it doesn’t know how. Intrinsics with illegal types are usually handled by adding setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom) to the AVRTargetLowering constructor. And then adding a case for INTRINSIC_W_CHAIN to AVRTargetLowering::LowerOperation to detect the specific intrinsic and handle it.

Alternatively you chang the intrinsic to use i16 instead of i32 if that meets your needs.

Changing to an i16 is not going to work, sadly. But I can think the
other things you wrote will help me going forward - thank you :slight_smile: