Skip to content

Commit

Permalink
[AArch64][SVE] Asm: Support for INC/DEC (scalar) instructions.
Browse files Browse the repository at this point in the history
Increment/decrement scalar register by (scaled) element count given by
predicate pattern, e.g. 'incw x0, all, mul brson#4'.

Reviewers: rengolin, fhahn, SjoerdMeijer, samparker, javed.absar

Reviewed By: SjoerdMeijer

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



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@334838 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
sdesmalen-arm committed Jun 15, 2018
1 parent bd0b6b0 commit df60d71
Show file tree
Hide file tree
Showing 21 changed files with 1,663 additions and 12 deletions.
9 changes: 9 additions & 0 deletions lib/Target/AArch64/AArch64SVEInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,15 @@ let Predicates = [HasSVE] in {
def ADDVL_XXI : sve_int_arith_vl<0b0, "addvl">;
def ADDPL_XXI : sve_int_arith_vl<0b1, "addpl">;

defm INCB_XPiI : sve_int_pred_pattern_a<0b000, "incb">;
defm DECB_XPiI : sve_int_pred_pattern_a<0b001, "decb">;
defm INCH_XPiI : sve_int_pred_pattern_a<0b010, "inch">;
defm DECH_XPiI : sve_int_pred_pattern_a<0b011, "dech">;
defm INCW_XPiI : sve_int_pred_pattern_a<0b100, "incw">;
defm DECW_XPiI : sve_int_pred_pattern_a<0b101, "decw">;
defm INCD_XPiI : sve_int_pred_pattern_a<0b110, "incd">;
defm DECD_XPiI : sve_int_pred_pattern_a<0b111, "decd">;

defm INDEX_RR : sve_int_index_rr<"index">;
defm INDEX_IR : sve_int_index_ir<"index">;
defm INDEX_RI : sve_int_index_ri<"index">;
Expand Down
43 changes: 31 additions & 12 deletions lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
bool parseRegister(OperandVector &Operands);
bool parseSymbolicImmVal(const MCExpr *&ImmVal);
bool parseNeonVectorList(OperandVector &Operands);
bool parseOptionalMulVl(OperandVector &Operands);
bool parseOptionalMulOperand(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, bool isCondCode,
bool invertCondCode);

Expand Down Expand Up @@ -3199,27 +3199,45 @@ AArch64AsmParser::tryParseGPROperand(OperandVector &Operands) {
return MatchOperand_Success;
}

bool AArch64AsmParser::parseOptionalMulVl(OperandVector &Operands) {
bool AArch64AsmParser::parseOptionalMulOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();

// Some SVE instructions have a decoration after the immediate, i.e.
// "mul vl". We parse them here and add tokens, which must be present in the
// asm string in the tablegen instruction.
bool NextIsVL = Parser.getLexer().peekTok().getString().equals_lower("vl");
bool NextIsHash = Parser.getLexer().peekTok().is(AsmToken::Hash);
if (!Parser.getTok().getString().equals_lower("mul") ||
!Parser.getLexer().peekTok().getString().equals_lower("vl"))
!(NextIsVL || NextIsHash))
return true;

SMLoc S = getLoc();
Operands.push_back(
AArch64Operand::CreateToken("mul", false, S, getContext()));
AArch64Operand::CreateToken("mul", false, getLoc(), getContext()));
Parser.Lex(); // Eat the "mul"

S = getLoc();
Operands.push_back(
AArch64Operand::CreateToken("vl", false, S, getContext()));
Parser.Lex(); // Eat the "vl"
if (NextIsVL) {
Operands.push_back(
AArch64Operand::CreateToken("vl", false, getLoc(), getContext()));
Parser.Lex(); // Eat the "vl"
return false;
}

return false;
if (NextIsHash) {
Parser.Lex(); // Eat the #
SMLoc S = getLoc();

// Parse immediate operand.
const MCExpr *ImmVal;
if (!Parser.parseExpression(ImmVal))
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal)) {
Operands.push_back(AArch64Operand::CreateImm(
MCConstantExpr::create(MCE->getValue(), getContext()), S, getLoc(),
getContext()));
return MatchOperand_Success;
}
}

return Error(getLoc(), "expected 'vl' or '#<imm>'");
}

/// parseOperand - Parse a arm instruction operand. For now this parses the
Expand Down Expand Up @@ -3275,8 +3293,9 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
if (!parseRegister(Operands))
return false;

// See if this is a "mul vl" decoration used by SVE instructions.
if (!parseOptionalMulVl(Operands))
// See if this is a "mul vl" decoration or "mul #<int>" operand used
// by SVE instructions.
if (!parseOptionalMulOperand(Operands))
return false;

// This could be an optional "shift" or "extend" operand.
Expand Down
9 changes: 9 additions & 0 deletions lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ static DecodeStatus DecodeSImm(llvm::MCInst &Inst, uint64_t Imm,
template <int ElementWidth>
static DecodeStatus DecodeImm8OptLsl(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder);
static DecodeStatus DecodeSVEIncDecImm(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder);

static bool Check(DecodeStatus &Out, DecodeStatus In) {
switch (In) {
Expand Down Expand Up @@ -1791,3 +1793,10 @@ static DecodeStatus DecodeImm8OptLsl(MCInst &Inst, unsigned Imm,
Inst.addOperand(MCOperand::createImm(Shift));
return Success;
}

// Decode uimm4 ranged from 1-16.
static DecodeStatus DecodeSVEIncDecImm(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
Inst.addOperand(MCOperand::createImm(Imm + 1));
return Success;
}
13 changes: 13 additions & 0 deletions lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
uint32_t getImm8OptLsl(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
uint32_t getSVEIncDecImm(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;

unsigned fixMOVZ(const MCInst &MI, unsigned EncodedValue,
const MCSubtargetInfo &STI) const;
Expand Down Expand Up @@ -531,6 +534,16 @@ AArch64MCCodeEmitter::getImm8OptLsl(const MCInst &MI, unsigned OpIdx,
return (Immediate & 0xff) | (ShiftVal == 0 ? 0 : (1 << ShiftVal));
}

uint32_t
AArch64MCCodeEmitter::getSVEIncDecImm(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpIdx);
assert(MO.isImm() && "Expected an immediate value!");
// Normalize 1-16 range to 0-15.
return MO.getImm() - 1;
}

/// getMoveVecShifterOpValue - Return the encoded value for the vector move
/// shifter (MSL).
uint32_t AArch64MCCodeEmitter::getMoveVecShifterOpValue(
Expand Down
43 changes: 43 additions & 0 deletions lib/Target/AArch64/SVEInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ def sve_fpimm_zero_one
: SVEExactFPImmOperand<"ZeroOne", "AArch64ExactFPImm::zero",
"AArch64ExactFPImm::one">;

def sve_incdec_imm : Operand<i32>, ImmLeaf<i32, [{
return (((uint32_t)Imm) > 0) && (((uint32_t)Imm) < 17);
}]> {
let ParserMatchClass = Imm1_16Operand;
let EncoderMethod = "getSVEIncDecImm";
let DecoderMethod = "DecodeSVEIncDecImm";
}

//===----------------------------------------------------------------------===//
// SVE PTrue - These are used extensively throughout the pattern matching so
// it's important we define them first.
Expand Down Expand Up @@ -272,6 +280,41 @@ let Predicates = [HasSVE] in {
defm PTRUES : sve_int_ptrue<0b001, "ptrues">;
}


//===----------------------------------------------------------------------===//
// SVE Element Count Group
//===----------------------------------------------------------------------===//

class sve_int_pred_pattern_a<bits<3> opc, string asm>
: I<(outs GPR64:$Rdn), (ins GPR64:$_Rdn, sve_pred_enum:$pattern, sve_incdec_imm:$imm4),
asm, "\t$Rdn, $pattern, mul $imm4",
"",
[]>, Sched<[]> {
bits<5> Rdn;
bits<5> pattern;
bits<4> imm4;
let Inst{31-24} = 0b00000100;
let Inst{23-22} = opc{2-1};
let Inst{21-20} = 0b11;
let Inst{19-16} = imm4;
let Inst{15-11} = 0b11100;
let Inst{10} = opc{0};
let Inst{9-5} = pattern;
let Inst{4-0} = Rdn;

let Constraints = "$Rdn = $_Rdn";
}

multiclass sve_int_pred_pattern_a<bits<3> opc, string asm> {
def NAME : sve_int_pred_pattern_a<opc, asm>;

def : InstAlias<asm # "\t$Rdn, $pattern",
(!cast<Instruction>(NAME) GPR64:$Rdn, sve_pred_enum:$pattern, 1), 1>;
def : InstAlias<asm # "\t$Rdn",
(!cast<Instruction>(NAME) GPR64:$Rdn, 0b11111, 1), 2>;
}


//===----------------------------------------------------------------------===//
// SVE Permute - Cross Lane Group
//===----------------------------------------------------------------------===//
Expand Down
57 changes: 57 additions & 0 deletions test/MC/AArch64/SVE/decb-diagnostics.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve 2>&1 < %s| FileCheck %s

// ------------------------------------------------------------------------- //
// Invalid result register

decb w0
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand
// CHECK-NEXT: decb w0
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb sp
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand
// CHECK-NEXT: decb sp
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:


// ------------------------------------------------------------------------- //
// Immediate not compatible with encode/decode function.

decb x0, all, mul #-1
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [1, 16]
// CHECK-NEXT: decb x0, all, mul #-1
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb x0, all, mul #0
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [1, 16]
// CHECK-NEXT: decb x0, all, mul #0
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb x0, all, mul #17
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [1, 16]
// CHECK-NEXT: decb x0, all, mul #17
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:


// ------------------------------------------------------------------------- //
// Invalid predicate patterns

decb x0, vl512
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid predicate pattern
// CHECK-NEXT: decb x0, vl512
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb x0, vl9
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid predicate pattern
// CHECK-NEXT: decb x0, vl9
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb x0, #-1
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid predicate pattern
// CHECK-NEXT: decb x0, #-1
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

decb x0, #32
// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid predicate pattern
// CHECK-NEXT: decb x0, #32
// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
128 changes: 128 additions & 0 deletions test/MC/AArch64/SVE/decb.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve < %s \
// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \
// RUN: | llvm-objdump -d -mattr=+sve - | FileCheck %s --check-prefix=CHECK-INST
// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \
// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN

decb x0
// CHECK-INST: decb x0
// CHECK-ENCODING: [0xe0,0xe7,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: e0 e7 30 04 <unknown>

decb x0, all
// CHECK-INST: decb x0
// CHECK-ENCODING: [0xe0,0xe7,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: e0 e7 30 04 <unknown>

decb x0, all, mul #1
// CHECK-INST: decb x0
// CHECK-ENCODING: [0xe0,0xe7,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: e0 e7 30 04 <unknown>

decb x0, all, mul #16
// CHECK-INST: decb x0, all, mul #16
// CHECK-ENCODING: [0xe0,0xe7,0x3f,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: e0 e7 3f 04 <unknown>

decb x0, pow2
// CHECK-INST: decb x0, pow2
// CHECK-ENCODING: [0x00,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 00 e4 30 04 <unknown>

decb x0, vl1
// CHECK-INST: decb x0, vl1
// CHECK-ENCODING: [0x20,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 20 e4 30 04 <unknown>

decb x0, vl2
// CHECK-INST: decb x0, vl2
// CHECK-ENCODING: [0x40,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 40 e4 30 04 <unknown>

decb x0, vl3
// CHECK-INST: decb x0, vl3
// CHECK-ENCODING: [0x60,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 60 e4 30 04 <unknown>

decb x0, vl4
// CHECK-INST: decb x0, vl4
// CHECK-ENCODING: [0x80,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 80 e4 30 04 <unknown>

decb x0, vl5
// CHECK-INST: decb x0, vl5
// CHECK-ENCODING: [0xa0,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: a0 e4 30 04 <unknown>

decb x0, vl6
// CHECK-INST: decb x0, vl6
// CHECK-ENCODING: [0xc0,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: c0 e4 30 04 <unknown>

decb x0, vl7
// CHECK-INST: decb x0, vl7
// CHECK-ENCODING: [0xe0,0xe4,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: e0 e4 30 04 <unknown>

decb x0, vl8
// CHECK-INST: decb x0, vl8
// CHECK-ENCODING: [0x00,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 00 e5 30 04 <unknown>

decb x0, vl16
// CHECK-INST: decb x0, vl16
// CHECK-ENCODING: [0x20,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 20 e5 30 04 <unknown>

decb x0, vl32
// CHECK-INST: decb x0, vl32
// CHECK-ENCODING: [0x40,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 40 e5 30 04 <unknown>

decb x0, vl64
// CHECK-INST: decb x0, vl64
// CHECK-ENCODING: [0x60,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 60 e5 30 04 <unknown>

decb x0, vl128
// CHECK-INST: decb x0, vl128
// CHECK-ENCODING: [0x80,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 80 e5 30 04 <unknown>

decb x0, vl256
// CHECK-INST: decb x0, vl256
// CHECK-ENCODING: [0xa0,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: a0 e5 30 04 <unknown>

decb x0, #14
// CHECK-INST: decb x0, #14
// CHECK-ENCODING: [0xc0,0xe5,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: c0 e5 30 04 <unknown>

decb x0, #28
// CHECK-INST: decb x0, #28
// CHECK-ENCODING: [0x80,0xe7,0x30,0x04]
// CHECK-ERROR: instruction requires: sve
// CHECK-UNKNOWN: 80 e7 30 04 <unknown>
Loading

0 comments on commit df60d71

Please sign in to comment.