Skip to content

Commit

Permalink
Add LDC-specific traits for CTFE information about the target machine.
Browse files Browse the repository at this point in the history
__traits(targetCPU) == "broadwell"
__traits(targetHasFeature, "sse2") == bool
  • Loading branch information
JohanEngelen committed Jun 6, 2016
1 parent 51d40ba commit 59e9b21
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 1 deletion.
5 changes: 4 additions & 1 deletion ddmd/hooks.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ module ddmd.hooks;
import ddmd.dscope;
import ddmd.expression;

import gen.ldctraits;

/// Returns `null` when the __trait was not recognized.
Expression semanticTraitsHook(TraitsExp e, Scope* sc)
{
return null;
return semanticTraitsLDC(e, sc);
}
4 changes: 4 additions & 0 deletions ddmd/idgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ Msgtable[] msgtable =
{ "LDC_global_crt_ctor" },
{ "LDC_global_crt_dtor" },
{ "LDC_extern_weak" },

// IN_LLVM: LDC-specific traits.
{ "targetCPU" },
{ "targetHasFeature" },
];


Expand Down
56 changes: 56 additions & 0 deletions gen/ldctraits.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===-- ldctraits.cpp -----------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#include "gen/irstate.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/MC/MCSubtargetInfo.h"

// TODO: move this to a D interfacing helper file
struct Dstring {
const char *ptr;
size_t len;
};

Dstring traitsGetTargetCPU() {
auto cpu = gTargetMachine->getTargetCPU();
return {cpu.data(), cpu.size()};
}

bool traitsTargetHasFeature(Dstring feature) {
#if LDC_LLVM_VER < 307
// LLVM below 3.7 does not provide the necessary means to obtain the needed information,
// return the safe "feature not enabled".
return false;
#else
auto feat = llvm::StringRef(feature.ptr, feature.len);

// This is a work-around to a missing interface in LLVM to query whether a
// feature is set.

// Copy MCSubtargetInfo so we can modify it.
llvm::MCSubtargetInfo mcinfo = *gTargetMachine->getMCSubtargetInfo();
auto savedFeatbits = mcinfo.getFeatureBits();

// Nothing will change if the feature string is not recognized or if the
// feature is disabled.
{
auto newFeatbits = mcinfo.ApplyFeatureFlag(("-" + feat).str());
if (savedFeatbits == newFeatbits) {
return false;
}
mcinfo.setFeatureBits(savedFeatbits);
}
{
// Now that unrecognized feature strings are excluded,
// nothing will change iff the feature and its implied features are enabled.
auto newFeatbits = mcinfo.ApplyFeatureFlag(("+" + feat).str());
return savedFeatbits == newFeatbits;
}
#endif
}
82 changes: 82 additions & 0 deletions gen/ldctraits.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//===-- gen/ldctraits.d - LDC-specific __traits handling ----------*- D -*-===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

module gen.ldctraits;

import ddmd.arraytypes;
import ddmd.dscope;
import ddmd.dtemplate;
import ddmd.expression;
import ddmd.errors;
import ddmd.mtype;
import ddmd.id;

// TODO: move this to a D interfacing helper file
extern(C++) struct Dstring
{
const(char)* ptr;
size_t len;
};

extern(C++) Dstring traitsGetTargetCPU();
extern(C++) bool traitsTargetHasFeature(Dstring feature);

Expression semanticTraitsLDC(TraitsExp e, Scope* sc)
{
size_t arg_count = e.args ? e.args.dim : 0;

if (e.ident == Id.targetCPU)
{
if (arg_count != 0)
{
e.warning("ignoring arguments for __traits %s", e.ident.toChars());
}

auto cpu = traitsGetTargetCPU();
auto se = new StringExp(e.loc, cast(void*)cpu.ptr, cpu.len);
return se.semantic(sc);
}
if (e.ident == Id.targetHasFeature)
{
if (arg_count != 1)
{
e.error("__traits %s expects one argument, not %u", e.ident.toChars(), cast(uint)arg_count);
return new ErrorExp();
}

auto ex = isExpression((*e.args)[0]);
if (!ex)
{
e.error("expression expected as argument of __traits %s", e.ident.toChars());
return new ErrorExp();
}
ex = ex.ctfeInterpret();

StringExp se = ex.toStringExp();
if (!se || se.len == 0)
{
e.error("string expected as argument of __traits %s instead of %s", e.ident.toChars(), ex.toChars());
return new ErrorExp();
}
se = se.toUTF8(sc);
if (se.sz != 1)
{
e.error("argument of __traits %s must be char string", e.ident.toChars());
return new ErrorExp();
}

auto featureFound = traitsTargetHasFeature(Dstring(se.toPtr(), se.len));
return new IntegerExp(e.loc, featureFound ? 1 : 0, Type.tbool);
}
return null;
}
55 changes: 55 additions & 0 deletions tests/semantic/target_traits.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Tests LDC-specific target __traits

// RUN: %ldc -mcpu=haswell -d-version=CPU_HASWELL -c %s
// RUN: %ldc -mcpu=pentium -mattr=+fma -d-version=ATTR_FMA -c %s
// RUN: %ldc -mcpu=pentium -mattr=+fma,-sse -d-version=ATTR_FMA_MINUS_SSE -c %s

// Important: LLVM's default CPU selection already enables some features (like sse3)

// Querying feature information is only available from LLVM 3.7.
// Below 3.7, __traits(targetHasFeature,...) should always return false.
version (LDC_LLVM_305)
{
}
else version (LDC_LLVM_306)
{
}
else
{
version = HASFEATURE;
}

void main()
{
version (CPU_HASWELL)
{
static assert(__traits(targetCPU) == "haswell");
version (HASFEATURE)
{
static assert(__traits(targetHasFeature, "sse3"));
static assert(__traits(targetHasFeature, "sse4.1"));
}
static assert(!__traits(targetHasFeature, "sse4"));
static assert(!__traits(targetHasFeature, "sse4a"));
static assert(!__traits(targetHasFeature, "unrecognized feature"));
}
version (ATTR_FMA)
{
version (HASFEATURE)
{
static assert(__traits(targetHasFeature, "sse"));
static assert(__traits(targetHasFeature, "sse2"));
static assert(__traits(targetHasFeature, "sse3"));
static assert(__traits(targetHasFeature, "sse4.1"));
static assert(__traits(targetHasFeature, "fma"));
static assert(__traits(targetHasFeature, "avx"));
}
static assert(!__traits(targetHasFeature, "avx2"));
static assert(!__traits(targetHasFeature, "unrecognized feature"));
}
version (ATTR_FMA_MINUS_SSE)
{
// All implied features must be enabled for targetHasFeature to return true
static assert(!__traits(targetHasFeature, "fma"));
}
}

0 comments on commit 59e9b21

Please sign in to comment.