1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
// Tests inline IR + math optimizations
// REQUIRES: target_X86
// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s --check-prefix LLVM < %t.ll
// RUN: %ldc -mtriple=x86_64-linux-gnu -mattr=+fma -O3 -release -c -output-s -of=%t.s %s && FileCheck %s --check-prefix ASM < %t.s
import ldc.attributes;
import ldc.llvmasm;
// Test that internal @inline.ir.*" functions for the inlined IR pieces are always inlined and are not present as a global symbol
// LLVM-NOT: @inline.ir.
// LLVM-NOT: alwaysinline
// __ir should inherit the enclosing function attributes, thus preserving the enclosing function attributes after inlining.
// LLVM-LABEL: define{{.*}} @dot
// LLVM-SAME: #[[UNSAFEFPMATH:[0-9]+]]
// ASM-LABEL: dot:
@llvmAttr("unsafe-fp-math", "true")
extern (C) double dot(double[] a, double[] b)
{
double s = 0;
// ASM: vfmadd{{[123][123][123]}}pd
foreach (size_t i; 0 .. a.length)
{
s = __ir!(`%p = fmul fast double %0, %1
%r = fadd fast double %p, %2
ret double %r`, double)(a[i], b[i], s);
}
return s;
}
// LLVM-LABEL: define{{.*}} @features
// LLVM-SAME: #[[FEAT:[0-9]+]]
@target("fma")
extern (C) double features(double[] a, double[] b)
{
double s = 0;
foreach (size_t i; 0 .. a.length)
{
s = __ir!(`%p = fmul fast double %0, %1
%r = fadd fast double %p, %2
ret double %r`, double)(a[i], b[i], s);
}
return s;
}
// Test that inline IR works when calling function has special attributes defined for its parameters
// LLVM-LABEL: define{{.*}} @dot160
// ASM-LABEL: dot160:
extern (C) double dot160(double[160] a, double[160] b)
{
double s = 0;
// ASM-NOT: vfmadd
foreach (size_t i; 0 .. a.length)
{
s = __ir!(`%p = fmul double %0, %1
%r = fadd double %p, %2
ret double %r`, double)(a[i], b[i], s);
}
return s;
}
// Test inline IR alias defined outside any function
alias __ir!(`%p = fmul fast double %0, %1
%r = fadd fast double %p, %2
ret double %r`,
double, double, double, double) muladdFast;
alias __ir!(`%p = fmul double %0, %1
%r = fadd double %p, %2
ret double %r`,
double, double, double, double) muladd;
// LLVM-LABEL: define{{.*}} @aliasInlineUnsafe
// LLVM-SAME: #[[UNSAFEFPMATH]]
// ASM-LABEL: aliasInlineUnsafe:
@llvmAttr("unsafe-fp-math", "true")
extern (C) double aliasInlineUnsafe(double[] a, double[] b)
{
double s = 0;
// ASM: vfmadd{{[123][123][123]}}pd
foreach (size_t i; 0 .. a.length)
{
s = muladdFast(a[i], b[i], s);
}
return s;
}
// LLVM-LABEL: define{{.*}} @aliasInlineSafe
// LLVM-SAME: #[[NO_UNSAFEFPMATH:[0-9]+]]
// ASM-LABEL: aliasInlineSafe:
extern (C) double aliasInlineSafe(double[] a, double[] b)
{
double s = 0;
// ASM-NOT: vfmadd{{[123][123][123]}}pd
foreach (size_t i; 0 .. a.length)
{
s = muladd(a[i], b[i], s);
}
return s;
}
// Make sure an enclosing function's 'noinline' attribute isn't copied to
// the inlined IR function (having 'alwaysinline') (issue #1711).
double neverInlinedEnclosingFunction()
{
pragma(inline, false);
return muladd(1.0, 2.0, 3.0);
}
// LLVM: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true"
// LLVM: attributes #[[FEAT]] ={{.*}} "target-features"="{{.*}}+fma{{.*}}"
// LLVM: attributes #[[NO_UNSAFEFPMATH]] =
// LLVM-NOT: "unsafe-fp-math"="true"
|