In LLVM system compiler, there is an option in the command command -mattr called target specific attributes. You may check each target attributes by using this command.

llvm-as < /dev/null || llc -march=aemb -mattr=help

note that -march=aemb is to select target architecture, in my case, aeMB.

A list of attributes will appear as below.

Available features for this target:

barrel - Implements barrel shifter.
div - Implements hardware divider.
efsl - Implements extended FSL instructions.
esr - Implements ESR and EAR registers.
exception - Implements hardware exception support.
fpu - Implements floating point unit.
fsl - Implements FSL instructions.
msrset - Implements MSR register set and clear.
mul - Implements hardware multiplier.
mul64 - Implements multiplier with 64-bit result.
patcmp - Implements pattern compare instruction.
pipe3 - Implements 3-stage pipeline.
pvr - Implements processor version register.
sqrt - Implements sqrt and floating point convert.

You can enable each feature by +feature and to disable it, -feature.


llc -march=aemb -mattr=+features1, +feature2

When writing LLVM backend, most probably one may want to customize this feature list, and add their own special attributes. To do that, first declare the feature name inside *Subtarget.h and *Subtarget.cpp.  The content of the file looks like this, with a bunch of other features.


// aeMB architecture version
aeMBArchEnum aeMBArchVersion;

bool HasPipe3;
bool HasBarrel;
bool HasDiv;

bool HasMul;
... remainder not shown for space ...


aeMBSubtarget::aeMBSubtarget(const std::string &TT, const std::string &FS):
HasPipe3(false), HasBarrel(false), HasDiv(false), HasMul(false),
// Parse features string.
ParseSubtargetFeatures(FS, CPU);


And then go to target *,  put that feature under predicate definition.

// aeMB Instruction Predicate Definitions.
def HasPipe3     : Predicate<"Subtarget.hasPipe3()">;
def HasBarrel    : Predicate<"Subtarget.hasBarrel()">;
def HasDiv       : Predicate<"Subtarget.hasDiv()">;
def HasMul       : Predicate<"Subtarget.hasMul()">;

inside *, there are also a lot of instruction definition for that specific target. Define the instructions involve with the feature (predicate) using let expression. Below is an example how HasMul feature implemented.

let isCommutable = 1, Predicates=[HasMul] in {
def MUL    : Arith<0x10, 0x000, "mul    ", mul,   IIAlu>;

By doing this, basically we are telling LLVM that we want MUL instruction to be a conditional instruction. And lastly, go to *ISelLowering.cpp, by using expand, promote or custom capability of LLVM (read my previous post–>link),

Do this.  

// If the processor doesn't support multiply then expand it
if (!Subtarget->hasMul()) {
setOperationAction(ISD::MUL, MVT::i32, Expand);

Which mean whenever MUL instrucion is disable command line, LLVM should expand it and use other instruction to complete the multiplication. So, thats how you add your target specific features or attributes.


Categories: Experiential


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.