Skip to content

Commit

Permalink
[Sparc] Add membar assembler tags
Browse files Browse the repository at this point in the history
Summary: The Sparc V9 membar instruction can enforce different types of
memory orderings depending on the value in its immediate field.  In the
architectural manual the type is selected by combining different assembler
tags into a mask. This patch adds support for these tags.

Reviewers: jyknight, venkatra, brad

Reviewed By: jyknight

Subscribers: fedor.sergeev, jrtc27, jfb, llvm-commits

Differential Revision: https://reviews.llvm.org/D53491

llvm-svn: 349048
  • Loading branch information
doac committed Dec 13, 2018
1 parent ba91ff4 commit 7761142
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 5 deletions.
55 changes: 55 additions & 0 deletions llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
Expand Up @@ -78,6 +78,8 @@ class SparcAsmParser : public MCTargetAsmParser {
// Custom parse functions for Sparc specific operands.
OperandMatchResultTy parseMEMOperand(OperandVector &Operands);

OperandMatchResultTy parseMembarTag(OperandVector &Operands);

OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name);

OperandMatchResultTy
Expand Down Expand Up @@ -256,6 +258,7 @@ class SparcOperand : public MCParsedAsmOperand {
bool isMem() const override { return isMEMrr() || isMEMri(); }
bool isMEMrr() const { return Kind == k_MemoryReg; }
bool isMEMri() const { return Kind == k_MemoryImm; }
bool isMembarTag() const { return Kind == k_Immediate; }

bool isIntReg() const {
return (Kind == k_Register && Reg.Kind == rk_IntReg);
Expand Down Expand Up @@ -366,6 +369,12 @@ class SparcOperand : public MCParsedAsmOperand {
addExpr(Inst, Expr);
}

void addMembarTagOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCExpr *Expr = getImm();
addExpr(Inst, Expr);
}

static std::unique_ptr<SparcOperand> CreateToken(StringRef Str, SMLoc S) {
auto Op = make_unique<SparcOperand>(k_Token);
Op->Tok.Data = Str.data();
Expand Down Expand Up @@ -742,6 +751,52 @@ SparcAsmParser::parseMEMOperand(OperandVector &Operands) {
return MatchOperand_Success;
}

OperandMatchResultTy SparcAsmParser::parseMembarTag(OperandVector &Operands) {
SMLoc S = Parser.getTok().getLoc();
const MCExpr *EVal;
int64_t ImmVal = 0;

std::unique_ptr<SparcOperand> Mask;
if (parseSparcAsmOperand(Mask) == MatchOperand_Success) {
if (!Mask->isImm() || !Mask->getImm()->evaluateAsAbsolute(ImmVal) ||
ImmVal < 0 || ImmVal > 127) {
Error(S, "invalid membar mask number");
return MatchOperand_ParseFail;
}
}

while (getLexer().getKind() == AsmToken::Hash) {
SMLoc TagStart = getLexer().getLoc();
Parser.Lex(); // Eat the '#'.
unsigned MaskVal = StringSwitch<unsigned>(Parser.getTok().getString())
.Case("LoadLoad", 0x1)
.Case("StoreLoad", 0x2)
.Case("LoadStore", 0x4)
.Case("StoreStore", 0x8)
.Case("Lookaside", 0x10)
.Case("MemIssue", 0x20)
.Case("Sync", 0x40)
.Default(0);

Parser.Lex(); // Eat the identifier token.

if (!MaskVal) {
Error(TagStart, "unknown membar tag");
return MatchOperand_ParseFail;
}

ImmVal |= MaskVal;

if (getLexer().getKind() == AsmToken::Pipe)
Parser.Lex(); // Eat the '|'.
}

EVal = MCConstantExpr::create(ImmVal, getContext());
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(SparcOperand::CreateImm(EVal, S, E));
return MatchOperand_Success;
}

OperandMatchResultTy
SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {

Expand Down
23 changes: 23 additions & 0 deletions llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
Expand Up @@ -195,3 +195,26 @@ bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX.");
return true;
}

void SparcInstPrinter::printMembarTag(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
static const char *const TagNames[] = {
"#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore",
"#Lookaside", "#MemIssue", "#Sync"};

unsigned Imm = MI->getOperand(opNum).getImm();

if (Imm > 127) {
O << Imm;
return;
}

bool First = true;
for (unsigned i = 0; i < sizeof(TagNames) / sizeof(char *); i++) {
if (Imm & (1 << i)) {
O << (First ? "" : " | ") << TagNames[i];
First = false;
}
}
}
2 changes: 2 additions & 0 deletions llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
Expand Up @@ -49,6 +49,8 @@ class SparcInstPrinter : public MCInstPrinter {
raw_ostream &OS);
bool printGetPCX(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &OS);
void printMembarTag(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &O);
};
} // end namespace llvm

Expand Down
12 changes: 11 additions & 1 deletion llvm/lib/Target/Sparc/SparcInstrInfo.td
Expand Up @@ -138,6 +138,16 @@ def MEMri : Operand<iPTR> {

def TLSSym : Operand<iPTR>;

def SparcMembarTagAsmOperand : AsmOperandClass {
let Name = "MembarTag";
let ParserMethod = "parseMembarTag";
}

def MembarTag : Operand<i32> {
let PrintMethod = "printMembarTag";
let ParserMatchClass = SparcMembarTagAsmOperand;
}

// Branch targets have OtherVT type.
def brtarget : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValue";
Expand Down Expand Up @@ -1503,7 +1513,7 @@ def : Pat<(ctpop i32:$src),
(POPCrr (SRLri $src, 0))>;

let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in
def MEMBARi : F3_2<2, 0b101000, (outs), (ins simm13Op:$simm13),
def MEMBARi : F3_2<2, 0b101000, (outs), (ins MembarTag:$simm13),
"membar $simm13", []>;

// The CAS instruction, unlike other instructions, only comes in a
Expand Down
17 changes: 16 additions & 1 deletion llvm/test/MC/Disassembler/Sparc/sparc-v9.txt
Expand Up @@ -115,4 +115,19 @@
0x9f 0xd0 0x30 0x52

# CHECK: tvs %xcc, %g1 + %i2
0x8f 0xd0 0x50 0x1a
0x8f 0xd0 0x50 0x1a

# CHECK: membar 5000
0x81 0x43 0xf3 0x88

# CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore
0x81 0x43 0xe0 0x0f

# CHECK: membar #LoadLoad
0x81 0x43 0xe0 0x01

# CHECK: membar #LoadLoad | #StoreStore
0x81 0x43 0xe0 0x09

# CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync
0x81 0x43 0xe0 0x7f
12 changes: 10 additions & 2 deletions llvm/test/MC/Sparc/sparc-asm-errors.s
@@ -1,8 +1,16 @@
! RUN: not llvm-mc %s -arch=sparc -show-encoding 2>&1 | FileCheck %s
! RUN: not llvm-mc %s -arch=sparcv9 -show-encoding 2>&1 | FileCheck %s
! RUN: not llvm-mc %s -arch=sparc -show-encoding 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V8
! RUN: not llvm-mc %s -arch=sparcv9 -show-encoding 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V9

! Test the lower and upper bounds of 'set'
! CHECK: argument must be between
set -2147483649, %o1
! CHECK: argument must be between
set 4294967296, %o1

! V8: unexpected token
! V9: unknown membar tag
membar #BadTag

! V8: instruction requires a CPU feature not currently enabled
! V9: invalid membar mask number
membar -127
11 changes: 10 additions & 1 deletion llvm/test/MC/Sparc/sparcv9-atomic-instructions.s
@@ -1,8 +1,17 @@
! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s

! CHECK: membar 15 ! encoding: [0x81,0x43,0xe0,0x0f]
! CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore ! encoding: [0x81,0x43,0xe0,0x0f]
membar 15

! CHECK: membar #LoadLoad ! encoding: [0x81,0x43,0xe0,0x01]
membar #LoadLoad

! CHECK: membar #LoadLoad | #StoreStore ! encoding: [0x81,0x43,0xe0,0x09]
membar #LoadLoad | #StoreStore

! CHECK: membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync ! encoding: [0x81,0x43,0xe0,0x7f]
membar #LoadLoad | #StoreLoad | #LoadStore | #StoreStore | #Lookaside | #MemIssue | #Sync

! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16]
cas [%i0], %l6, %o2

Expand Down

0 comments on commit 7761142

Please sign in to comment.