view runtime/import/ldc/intrinsics.di @ 1076:39b7c32cd010

Reformat intrinsics.di a bit.
author Frits van Bommel <fvbommel wxs.nl>
date Mon, 09 Mar 2009 21:38:24 +0100
parents 34bc1945bc85
children 4e388d9d0e25
line wrap: on
line source

/*
 * This module holds declarations to LLVM intrinsics.
 *
 * See the LLVM language reference for more information:
 *
 * - http://llvm.org/docs/LangRef.html#intrinsics
 *
 */

module ldc.intrinsics;

// Check for the right compiler
version(LDC)
{
    // OK
}
else
{
    static assert(false, "This module is only valid for LDC");
}

version(X86)
    version = Reals_80Bit;
else version(X86_64)
    version = Reals_80Bit;

//
// CODE GENERATOR INTRINSICS
//


// The 'llvm.returnaddress' intrinsic attempts to compute a target-specific
// value indicating the return address of the current function or one of its
// callers.

pragma(intrinsic, "llvm.returnaddress")
    void* llvm_returnaddress(uint level);


// The 'llvm.frameaddress' intrinsic attempts to return the target-specific
// frame pointer value for the specified stack frame.

pragma(intrinsic, "llvm.frameaddress")
    void* llvm_frameaddress(uint level);


// The 'llvm.stacksave' intrinsic is used to remember the current state of the
// function stack, for use with llvm.stackrestore. This is useful for
// implementing language features like scoped automatic variable sized arrays
// in C99.

pragma(intrinsic, "llvm.stacksave")
    void* llvm_stacksave();


// The 'llvm.stackrestore' intrinsic is used to restore the state of the
// function stack to the state it was in when the corresponding llvm.stacksave
// intrinsic executed. This is useful for implementing language features like
// scoped automatic variable sized arrays in C99.

pragma(intrinsic, "llvm.stackrestore")
    void llvm_stackrestore(void* ptr);


// The 'llvm.prefetch' intrinsic is a hint to the code generator to insert a
// prefetch instruction if supported; otherwise, it is a noop. Prefetches have
// no effect on the behavior of the program but can change its performance
// characteristics.

pragma(intrinsic, "llvm.prefetch")
    void llvm_prefetch(void* ptr, uint rw, uint locality);


// The 'llvm.pcmarker' intrinsic is a method to export a Program Counter (PC)
// in a region of code to simulators and other tools. The method is target
// specific, but it is expected that the marker will use exported symbols to
// transmit the PC of the marker. The marker makes no guarantees that it will
// remain with any specific instruction after optimizations. It is possible
// that the presence of a marker will inhibit optimizations. The intended use
// is to be inserted after optimizations to allow correlations of simulation
// runs.

pragma(intrinsic, "llvm.pcmarker")
    void llvm_pcmarker(uint id);


// The 'llvm.readcyclecounter' intrinsic provides access to the cycle counter
// register (or similar low latency, high accuracy clocks) on those targets that
// support it. On X86, it should map to RDTSC. On Alpha, it should map to RPCC.
// As the backing counters overflow quickly (on the order of 9 seconds on
// alpha), this should only be used for small timings.

pragma(intrinsic, "llvm.readcyclecounter")
    ulong readcyclecounter();




//
// STANDARD C LIBRARY INTRINSICS
//


// The 'llvm.memcpy.*' intrinsics copy a block of memory from the source
// location to the destination location.
// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do
// not return a value, and takes an extra alignment argument.

pragma(intrinsic, "llvm.memcpy.i32")
    void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);

pragma(intrinsic, "llvm.memcpy.i64")
    void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);


// The 'llvm.memmove.*' intrinsics move a block of memory from the source
// location to the destination location. It is similar to the 'llvm.memcpy'
// intrinsic but allows the two memory locations to overlap.
// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics
// do not return a value, and takes an extra alignment argument.

pragma(intrinsic, "llvm.memmove.i32")
    void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);

pragma(intrinsic, "llvm.memmove.i64")
    void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);


// The 'llvm.memset.*' intrinsics fill a block of memory with a particular byte
// value.
// Note that, unlike the standard libc function, the llvm.memset intrinsic does
// not return a value, and takes an extra alignment argument.

pragma(intrinsic, "llvm.memset.i32")
    void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);

pragma(intrinsic, "llvm.memset.i64")
    void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);


// The 'llvm.sqrt' intrinsics return the sqrt of the specified operand,
// returning the same value as the libm 'sqrt' functions would. Unlike sqrt in
// libm, however, llvm.sqrt has undefined behavior for negative numbers other
// than -0.0 (which allows for better optimization, because there is no need to
// worry about errno being set). llvm.sqrt(-0.0) is defined to return -0.0 like
// IEEE sqrt.

pragma(intrinsic, "llvm.sqrt.f32")
    float llvm_sqrt_f32(float val);

pragma(intrinsic, "llvm.sqrt.f64")
    double llvm_sqrt_f64(double val);

version(Reals_80Bit)
{
    pragma(intrinsic, "llvm.sqrt.f80")
        real llvm_sqrt_f80(real val);
    alias llvm_sqrt_f80 llvm_sqrt_real;
}
else
{
    pragma(intrinsic, "llvm.sqrt.f64")
        real llvm_sqrt_real(real val);
}


// The 'llvm.sin.*' intrinsics return the sine of the operand.

pragma(intrinsic, "llvm.sin.f32")
    float llvm_sin_f32(float val);

pragma(intrinsic, "llvm.sin.f64")
    double llvm_sin_f64(double val);

version(Reals_80Bit)
{
    pragma(intrinsic, "llvm.sin.f80")
        real llvm_sin_f80(real val);
    alias llvm_sin_f80 llvm_sin_real;
}
else
{
    pragma(intrinsic, "llvm.sin.f64")
        real llvm_sin_real(real val);
}


// The 'llvm.cos.*' intrinsics return the cosine of the operand.

pragma(intrinsic, "llvm.cos.f32")
    float llvm_cos_f32(float val);

pragma(intrinsic, "llvm.cos.f64")
    double llvm_cos_f64(double val);

version(Reals_80Bit)
{
    pragma(intrinsic, "llvm.cos.f80")
        real llvm_cos_f80(real val);
    alias llvm_cos_f80 llvm_cos_real;
}
else
{
    pragma(intrinsic, "llvm.cos.f64")
        real llvm_cos_real(real val);
}


// The 'llvm.powi.*' intrinsics return the first operand raised to the specified
// (positive or negative) power. The order of evaluation of multiplications is
// not defined. When a vector of floating point type is used, the second
// argument remains a scalar integer value.

pragma(intrinsic, "llvm.powi.f32")
    float llvm_powi_f32(float val, int power);

pragma(intrinsic, "llvm.powi.f64")
    double llvm_powi_f64(double val, int power);

version(Reals_80Bit)
{
    pragma(intrinsic, "llvm.powi.f80")
        real llvm_powi_f80(real val, int power);
    alias llvm_powi_f80 llvm_powi_real;
}
else
{
    pragma(intrinsic, "llvm.powi.f64")
        real llvm_powi_real(real val, int power);
}


// The 'llvm.pow.*' intrinsics return the first operand raised to the specified
// (positive or negative) power.

pragma(intrinsic, "llvm.pow.f32")
    float llvm_pow_f32(float val, float power);

pragma(intrinsic, "llvm.pow.f64")
    double llvm_pow_f64(double val, double power);

version(Reals_80Bit)
{
    pragma(intrinsic, "llvm.pow.f80")
        real llvm_pow_f80(real val, real power);
    alias llvm_pow_f80 llvm_pow_real;
}
else
{
    pragma(intrinsic, "llvm.pow.f64")
        real llvm_pow_real(real val, real power);
}


//
// BIT MANIPULATION INTRINSICS
//

// The 'llvm.bswap' family of intrinsics is used to byte swap integer values
// with an even number of bytes (positive multiple of 16 bits). These are
// useful for performing operations on data that is not in the target's native
// byte order.

pragma(intrinsic, "llvm.bswap.i16.i16")
    ushort llvm_bswap_i16(ushort val);

pragma(intrinsic, "llvm.bswap.i32.i32")
    uint llvm_bswap_i32(uint val);

pragma(intrinsic, "llvm.bswap.i64.i64")
    ulong llvm_bswap_i64(ulong val);


// The 'llvm.ctpop' family of intrinsics counts the number of bits set in a
// value.

pragma(intrinsic, "llvm.ctpop.i8")
    ubyte llvm_ctpop_i8(ubyte src);

pragma(intrinsic, "llvm.ctpop.i16")
    ushort llvm_ctpop_i16(ushort src);

pragma(intrinsic, "llvm.ctpop.i32")
    uint llvm_ctpop_i32(uint src);

pragma(intrinsic, "llvm.ctpop.i64")
    ulong llvm_ctpop_i64(ulong src);


// The 'llvm.ctlz' family of intrinsic functions counts the number of leading
// zeros in a variable.

pragma(intrinsic, "llvm.ctlz.i8")
    ubyte llvm_ctlz_i8(ubyte src);

pragma(intrinsic, "llvm.ctlz.i16")
    ushort llvm_ctlz_i16(ushort src);

pragma(intrinsic, "llvm.ctlz.i32")
    uint llvm_ctlz_i32(uint src);

pragma(intrinsic, "llvm.ctlz.i64")
    ulong llvm_ctlz_i64(ulong src);


// The 'llvm.cttz' family of intrinsic functions counts the number of trailing
// zeros.

pragma(intrinsic, "llvm.cttz.i8")
    ubyte llvm_cttz_i8(ubyte src);

pragma(intrinsic, "llvm.cttz.i16")
    ushort llvm_cttz_i16(ushort src);

pragma(intrinsic, "llvm.cttz.i32")
    uint llvm_cttz_i32(uint src);

pragma(intrinsic, "llvm.cttz.i64")
    ulong llvm_cttz_i64(ulong src);


// The 'llvm.part.select' family of intrinsic functions selects a range of bits
// from an integer value and returns them in the same bit width as the original
// value.

pragma(intrinsic, "llvm.part.select.i8")
    ubyte llvm_part_select_i(ubyte val, uint loBit, uint hiBit);

pragma(intrinsic, "llvm.part.select.i16")
    ushort llvm_part_select_i(ushort val, uint loBit, uint hiBit);

pragma(intrinsic, "llvm.part.select.i32")
    uint llvm_part_select_i(uint val, uint loBit, uint hiBit);

pragma(intrinsic, "llvm.part.select.i64")
    ulong llvm_part_select_i(ulong val, uint loBit, uint hiBit);


// The 'llvm.part.set' family of intrinsic functions replaces a range of bits
// in an integer value with another integer value. It returns the integer with
// the replaced bits.

// TODO
// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)




//
// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
//

// The llvm.memory.barrier intrinsic guarantees ordering between specific
// pairs of memory access types.

pragma(intrinsic, "llvm.memory.barrier")
    void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);

// This loads a value in memory and compares it to a given value. If they are
// equal, it stores a new value into the memory.

pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
    T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);

// This intrinsic loads the value stored in memory at ptr and yields the value
// from memory. It then stores the value in val in the memory at ptr.

pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
    T llvm_atomic_swap(T)(T* ptr, T val);

// This intrinsic adds delta to the value stored in memory at ptr. It yields
// the original value at ptr.

pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
    T llvm_atomic_load_add(T)(T* ptr, T val);

// This intrinsic subtracts delta to the value stored in memory at ptr. It
// yields the original value at ptr.

pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
    T llvm_atomic_load_sub(T)(T* ptr, T val);

// These intrinsics bitwise the operation (and, nand, or, xor) delta to the
// value stored in memory at ptr. It yields the original value at ptr.

pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
    T llvm_atomic_load_and(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
    T llvm_atomic_load_nand(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
    T llvm_atomic_load_or(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
    T llvm_atomic_load_xor(T)(T* ptr, T val);

// These intrinsics takes the signed or unsigned minimum or maximum of delta
// and the value stored in memory at ptr. It yields the original value at ptr.

pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
    T llvm_atomic_load_max(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
    T llvm_atomic_load_min(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
    T llvm_atomic_load_umax(T)(T* ptr, T val);

pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
    T llvm_atomic_load_umin(T)(T* ptr, T val);


//
// ARITHMETIC-WITH-OVERFLOW INTRINSICS
//

struct OverflowRet(T) {
    static assert(is(T : int), T.stringof ~ " is not an integer type!");
    T result;
    bool overflow;
}

// Signed and unsigned addition
pragma(intrinsic, "llvm.sadd.with.overflow.i#")
    OverflowRet!(T) llvm_sadd_with_overflow(T)(T lhs, T rhs);

pragma(intrinsic, "llvm.uadd.with.overflow.i#")
    OverflowRet!(T) llvm_uadd_with_overflow(T)(T lhs, T rhs);


// Signed and unsigned subtraction
pragma(intrinsic, "llvm.ssub.with.overflow.i#")
    OverflowRet!(T) llvm_ssub_with_overflow(T)(T lhs, T rhs);

pragma(intrinsic, "llvm.usub.with.overflow.i#")
    OverflowRet!(T) llvm_usub_with_overflow(T)(T lhs, T rhs);


// Signed and unsigned multiplication
pragma(intrinsic, "llvm.smul.with.overflow.i#")
    OverflowRet!(T) llvm_smul_with_overflow(T)(T lhs, T rhs);

/* Note: LLVM documentations says:
 *  Warning: 'llvm.umul.with.overflow' is badly broken.
 *  It is actively being fixed, but it should not currently be used!
 *
 * See: http://llvm.org/docs/LangRef.html#int_umul_overflow
 */
pragma(intrinsic, "llvm.umul.with.overflow.i#")
    OverflowRet!(T) llvm_umul_with_overflow(T)(T lhs, T rhs);


//
// GENERAL INTRINSICS
//


// This intrinsics is lowered to the target dependent trap instruction. If the
// target does not have a trap instruction, this intrinsic will be lowered to
// the call of the abort() function.

pragma(intrinsic, "llvm.trap")
    void llvm_trap();