Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,9 @@ LLVM_ABI extern char &MachineCFGPrinterID;
/// LiveDebugValues pass
LLVM_ABI extern char &LiveDebugValuesID;

/// UnisonMIRPrepare - This pass prepares for printing Unison-style MIR.
LLVM_ABI extern char &UnisonMIRPrepareID;

/// InterleavedAccess Pass - This pass identifies and matches interleaved
/// memory accesses to target specific intrinsics.
///
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ LLVM_ABI void initializeWasmEHPreparePass(PassRegistry &);
LLVM_ABI void initializeWinEHPreparePass(PassRegistry &);
LLVM_ABI void initializeWriteBitcodePassPass(PassRegistry &);
LLVM_ABI void initializeXRayInstrumentationLegacyPass(PassRegistry &);
LLVM_ABI void initializeUnisonMIRPreparePass(PassRegistry&);

} // end namespace llvm

Expand Down
153 changes: 153 additions & 0 deletions llvm/include/llvm/TableGen/Unison.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
//===- llvm/TableGen/Unison.h - Unison tool ---------------------*- C++ -*-===//
//
// Main authors:
// Jan Tomljanovic <[email protected]>
// Roberto Castaneda Lozano <[email protected]>
//
// This file is part of Unison, see http://unison-code.github.io
//
// Copyright (c) 2016, RISE SICS AB
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Extraction of the following information about each instruction for Unison:
/// - id (opcode)
/// - type (linear, call, or branch)
/// - operands (including use/def information and reg. class, if applicable)
/// - size
/// - side effects (including memory reads and writes)
/// - itinerary
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TABLEGEN_UNISON_H
#define LLVM_TABLEGEN_UNISON_H

#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Record.h"
#include <string>
#include <utility>
#include <vector>

// An Operand can be a Register, Label or a Bound (any other Operand that is not
// interpreted by Unison, such as immediates). If it is a register, UseDef and
// RegType are defined.
namespace unison {

struct Operand {
enum { Register, Label, Bound } Type;
std::string Name;
std::string UseDef;
std::string RegType;
};

} // end namespace unison

typedef std::pair<std::string, std::string> StringPair;
typedef std::vector<StringPair> StringPairVector;
typedef std::vector<std::string> StringVector;
typedef std::vector<unison::Operand> OperandVector;

/// Instruction with methods to be printed in .yaml format.
class Instruction {
private:
std::string Id;
std::string Type;
OperandVector Operands;
StringVector Uses;
StringVector Defs;
int Size;
bool AffectsMem;
bool AffectedMem;
StringVector AffectsReg;
StringVector AffectedReg;
std::string Itinerary;

void printAffs(llvm::raw_ostream &OS, std::string Name, bool Memory,
StringVector Regs);
void printUseDefs(llvm::raw_ostream &OS, StringVector UseDefs,
std::string Name);
void printAttribute(std::string Name, std::string Value,
llvm::raw_ostream &OS);
void printField(std::string Name, std::string Value, llvm::raw_ostream &OS);

public:
Instruction(std::string Id, std::string Type, OperandVector Operands,
StringVector Uses, StringVector Defs, int Size, bool AffectsMem,
bool AffectedMem, StringVector AffectsReg,
StringVector AffectedReg, std::string Itinerary);
void printId(llvm::raw_ostream &OS);
void printType(llvm::raw_ostream &OS);
void printOperands(llvm::raw_ostream &OS);
void printUses(llvm::raw_ostream &OS);
void printDefs(llvm::raw_ostream &OS);
void printSize(llvm::raw_ostream &OS);
void printAffects(llvm::raw_ostream &OS);
void printAffected(llvm::raw_ostream &OS);
void printItinerary(llvm::raw_ostream &OS);
void printAll(llvm::raw_ostream &OS);
};

namespace llvm {

/// \brief outputs information for Unison.
///
/// Prints extracted information for the Unison compiler as a valid
/// .yaml file.
/// \param OS output stream to which it prints the .yaml file.
/// \param Records structure that holds all the information about the
/// data which TableGen tool has.
void EmitUnisonFile(const RecordKeeper &Records, raw_ostream &OS);

StringVector flat(const Record *Rec);
void printYaml(std::vector<Instruction> Instructions, raw_ostream &OS);
std::string getRecordItinerary(Record *Rec);
StringVector getRegisterList(std::string Field, Record *Rec);
bool getRecordBool(Record *Rec, std::string Field, bool Def);
int getRecordSize(Record *Rec);
StringPairVector *parseOperands(std::string Field, Record *Rec);
StringVector getNames(StringPairVector *List);
void executeConstraints(StringPairVector *Outs, std::string Cons);
OperandVector getOperands(StringPairVector *Outs, StringPairVector *ins,
const RecordKeeper &Records);
void getOperandsFromVector(StringPairVector *Vec, StringPairVector *Help,
OperandVector *Operands, bool Defs,
const RecordKeeper &Records);
bool isRegister(const Record *Rec);
bool isLabel(const Record *Rec);
std::string getRecordType(Record *Rec);
std::string getRecordId(Record *Rec);
bool fieldExists(Record *Rec, std::string Field);
bool allNeededFieldsExist(Record *Rec);
StringVector split(std::string Str, char Del);
std::string trim(std::string Str);
std::string escape(std::string Name);

} // end namespace llvm

#endif
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ add_llvm_component_library(LLVMCodeGen
TargetSubtargetInfo.cpp
TwoAddressInstructionPass.cpp
TypePromotion.cpp
UnisonMIRPrepare.cpp
UnreachableBlockElim.cpp
ValueTypes.cpp
VLIWMachineScheduler.cpp
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,5 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeWasmEHPreparePass(Registry);
initializeWinEHPreparePass(Registry);
initializeXRayInstrumentationLegacyPass(Registry);
initializeUnisonMIRPreparePass(Registry);
}
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,19 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("dereferenceable", MIToken::kw_dereferenceable)
.Case("invariant", MIToken::kw_invariant)
.Case("align", MIToken::kw_align)
.Case("freq", MIToken::kw_freq)
.Case("basealign", MIToken::kw_basealign)
.Case("addrspace", MIToken::kw_addrspace)
.Case("stack", MIToken::kw_stack)
.Case("got", MIToken::kw_got)
.Case("jump-table", MIToken::kw_jump_table)
.Case("constant-pool", MIToken::kw_constant_pool)
.Case("unknown", MIToken::kw_unknown)
.Case("call-entry", MIToken::kw_call_entry)
.Case("custom", MIToken::kw_custom)
.Case("liveout", MIToken::kw_liveout)
.Case("liveouts", MIToken::kw_liveouts)
.Case("exit", MIToken::kw_exit)
.Case("landing-pad", MIToken::kw_landing_pad)
.Case("inlineasm-br-indirect-target",
MIToken::kw_inlineasm_br_indirect_target)
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,19 @@ struct MIToken {
kw_non_temporal,
kw_invariant,
kw_align,
kw_freq, // Unison MIR style extension.
kw_basealign,
kw_addrspace,
kw_stack,
kw_got,
kw_jump_table,
kw_constant_pool,
kw_call_entry,
kw_unknown, // Unison MIR style extension.
kw_custom,
kw_liveout,
kw_liveouts,
kw_exit, // Unison MIR style extension.
kw_landing_pad,
kw_inlineasm_br_indirect_target,
kw_ehfunclet_entry,
Expand Down
41 changes: 41 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MIParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ class MIParser {
parseBasicBlockDefinition(DenseMap<unsigned, MachineBasicBlock *> &MBBSlots);
bool parseBasicBlock(MachineBasicBlock &MBB,
MachineBasicBlock *&AddFalthroughFrom);
// Unison MIR style extension: list of basic block live-out registers.
bool parseBasicBlockLiveouts();
bool parseBasicBlockLiveins(MachineBasicBlock &MBB);
bool parseBasicBlockSuccessors(MachineBasicBlock &MBB);

Expand Down Expand Up @@ -751,6 +753,13 @@ bool MIParser::parseBasicBlockDefinition(
if (parseAlignment(Alignment))
return true;
break;
case MIToken::kw_freq:
// Unison MIR style extension: basic block execution frequency.
lex();
if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned())
return error("expected an integer literal");
lex();
break;
case MIToken::IRBlock:
case MIToken::NamedIRBlock:
// TODO: Report an error when both name and ir block are specified.
Expand Down Expand Up @@ -888,6 +897,25 @@ bool MIParser::parseBasicBlockLiveins(MachineBasicBlock &MBB) {
return false;
}

bool MIParser::parseBasicBlockLiveouts() {
assert(Token.is(MIToken::kw_liveouts));
lex();
if (expectAndConsume(MIToken::colon))
return true;
if (Token.isNewlineOrEOF()) // Allow an empty list of liveouts.
return false;
do {
if (Token.isNot(MIToken::NamedRegister))
return error("expected a named register");
Register Reg{0};
VRegInfo *RegInfo;
if (parseRegister(Reg, RegInfo))
return true;
lex();
} while (consumeIfPresent(MIToken::comma));
return false;
}

bool MIParser::parseBasicBlockSuccessors(MachineBasicBlock &MBB) {
assert(Token.is(MIToken::kw_successors));
lex();
Expand Down Expand Up @@ -949,6 +977,11 @@ bool MIParser::parseBasicBlock(MachineBasicBlock &MBB,
} else if (Token.is(MIToken::kw_liveins)) {
if (parseBasicBlockLiveins(MBB))
return true;
} else if (Token.is(MIToken::kw_liveouts)) {
if (parseBasicBlockLiveouts())
return true;
} else if (Token.is(MIToken::kw_exit)) {
lex();
} else if (consumeIfPresent(MIToken::Newline)) {
continue;
} else
Expand Down Expand Up @@ -3285,6 +3318,14 @@ bool MIParser::parseMemoryPseudoSourceValue(const PseudoSourceValue *&PSV) {
}

bool MIParser::parseMachinePointerInfo(MachinePointerInfo &Dest) {
// Unison MIR style extension: accept "unknown" pseudo-values, just return a
// null pointer.
if (Token.is(MIToken::kw_unknown)) {
lex();
const Value *V = nullptr;
Dest = MachinePointerInfo(V);
return false;
}
if (Token.is(MIToken::kw_constant_pool) || Token.is(MIToken::kw_stack) ||
Token.is(MIToken::kw_got) || Token.is(MIToken::kw_jump_table) ||
Token.is(MIToken::FixedStackObject) || Token.is(MIToken::StackObject) ||
Expand Down
55 changes: 55 additions & 0 deletions llvm/lib/CodeGen/MIRPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ static cl::opt<bool> SimplifyMIR(
static cl::opt<bool> PrintLocations("mir-debug-loc", cl::Hidden, cl::init(true),
cl::desc("Print MIR debug-locations"));

extern cl::opt<bool> UnisonMIR;

namespace {

/// This structure describes how to print out stack object references.
Expand Down Expand Up @@ -688,6 +690,19 @@ void printMBB(raw_ostream &OS, MFPrintState &State,
OS << ":\n";

bool HasLineAttributes = false;

if (UnisonMIR) {
// In Unison MIR style, the first instruction of each block contains the
// block's estimated execution frequency as a metadata operand. The
// instruction is emitted, but Unison is expected to disregard it.
OS << (HasLineAttributes ? ", " : " (");
auto MO = MBB.instr_begin()->operands_begin();
auto MD = MO->getMetadata()->getOperand(1).get();
auto MV = cast<ConstantAsMetadata>(MD)->getValue();
OS << "freq " << MV->getUniqueInteger();
HasLineAttributes = true;
}

// Print the successors
bool canPredictProbs = MBB.canPredictBranchProbabilities();
// Even if the list of successors is empty, if we cannot guess it,
Expand All @@ -704,6 +719,12 @@ void printMBB(raw_ostream &OS, MFPrintState &State,
ListSeparator LS;
for (auto I = MBB.succ_begin(), E = MBB.succ_end(); I != E; ++I) {
OS << LS << printMBBReference(**I);
// The Unison style uses a simpler formatting of the probabilities.
if (UnisonMIR && (!SimplifyMIR || !canPredictProbs))
OS << '('
<< MBB.getSuccProbability(I).scale(100)
<< ')';
else // Intentional indention to reduce merge conflicts.
if (!SimplifyMIR || !canPredictProbs)
OS << format("(0x%08" PRIx32 ")",
MBB.getSuccProbability(I).getNumerator());
Expand All @@ -727,6 +748,35 @@ void printMBB(raw_ostream &OS, MFPrintState &State,
HasLineAttributes = true;
}

if (UnisonMIR) {
// In the Unison style we print the live out registers. If there are no
// registers live-out, the marker still provides the information that the
// function actually returns (which is important e.g. to implement calling
// conventions).
if (MBB.isReturnBlock()) {
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
const MachineInstr &I = MBB.back();
OS.indent(2) << "liveouts:";
std::string Sep = " ";
// We assume that I's implicit uses correspond to the live out registers
// while the explicit uses are just common operands (such as the return
// address, predicate operands, etc.).
for (auto MO : I.uses())
if (MO.isReg() && MO.isImplicit()) {
OS << Sep << printReg(MO.getReg(), &TRI);
Sep = ", ";
}
OS << "\n";
HasLineAttributes = true;
}
// Print the 'exit' marker for basic blocks that exit but do not return to
// their caller function.
if (MBB.succ_empty() && (MBB.empty() || !MBB.back().isReturn())) {
OS.indent(2) << "exit\n";
HasLineAttributes = true;
}
}

if (HasLineAttributes && !MBB.empty())
OS << "\n";
bool IsInBundle = false;
Expand Down Expand Up @@ -918,6 +968,11 @@ static void printMIOperand(raw_ostream &OS, MFPrintState &State,
case MachineOperand::MO_BlockAddress:
case MachineOperand::MO_DbgInstrRef:
case MachineOperand::MO_ShuffleMask: {
// Unison expects metadata operands in a raw format.
if (UnisonMIR && Op.getType() == MachineOperand::MO_Metadata) {
OS << *(Op.getMetadata());
break;
}
unsigned TiedOperandIdx = 0;
if (ShouldPrintRegisterTies && Op.isReg() && Op.isTied() && !Op.isDef())
TiedOperandIdx = Op.getParent()->findTiedOperandIdx(OpIdx);
Expand Down
Loading
Loading