diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 19160a599c27c..30c9ee34ade1c 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -273,6 +273,8 @@ struct XtensaOperand : public MCParsedAsmOperand { return false; } + bool isimm7_22() const { return isImm(7, 22); } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -538,6 +540,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [0, 32760], first 3 bits " "should be zero"); + case Match_Invalidimm7_22: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [7, 22]"); } report_fatal_error("Unknown match type detected!"); diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp index b949b893953fe..6b355e6363b22 100644 --- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp +++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -168,7 +168,8 @@ static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch, static DecodeStatus decodeCallOperand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { assert(isUInt<18>(Imm) && "Invalid immediate"); - Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Imm << 2))); + Inst.addOperand( + MCOperand::createImm(SignExtend64<20>(Imm << 2) + (Address & 0x3))); return MCDisassembler::Success; } @@ -200,6 +201,16 @@ static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeLoopOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + + assert(isUInt<8>(Imm) && "Invalid immediate"); + if (!tryAddingSymbolicOperand(Imm + 4 + Address, true, Address, 0, 3, Inst, + Decoder)) + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { @@ -326,6 +337,13 @@ static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm, return MCDisassembler::Success; } +static DecodeStatus decodeImm7_22Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm + 7)); + return MCDisassembler::Success; +} + static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { assert(isUInt<12>(Imm) && "Invalid immediate"); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp index 1396eb45801af..ba2744d5facb5 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp @@ -64,7 +64,8 @@ XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, {"fixup_xtensa_l32r_16", 8, 16, MCFixupKindInfo::FKF_IsPCRel | - MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, + {"fixup_xtensa_loop_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}}; if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); @@ -116,6 +117,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, if (Value & 0x3) Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); return (Value & 0xffffc) >> 2; + case Xtensa::fixup_xtensa_loop_8: + Value -= 4; + if (!isUInt<8>(Value)) + Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range"); + return (Value & 0xff); case Xtensa::fixup_xtensa_l32r_16: unsigned Offset = Fixup.getOffset(); if (Offset & 0x3) diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h index 57b114e709a8a..f6b1e58adf073 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h @@ -22,6 +22,7 @@ enum FixupKind { fixup_xtensa_jump_18, fixup_xtensa_call_18, fixup_xtensa_l32r_16, + fixup_xtensa_loop_8, fixup_xtensa_invalid, LastTargetFixupKind, NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp index da7e9098f7544..fc5e1780de2e5 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -90,70 +90,103 @@ void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum, printOperand(MI, OpNum + 1, OS); } -void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum, - raw_ostream &OS) { +void XtensaInstPrinter::printBranchTarget(const MCInst *MI, uint64_t Address, + int OpNum, raw_ostream &O) { const MCOperand &MC = MI->getOperand(OpNum); if (MI->getOperand(OpNum).isImm()) { int64_t Val = MC.getImm() + 4; - OS << ". "; - if (Val > 0) - OS << '+'; - OS << Val; + printPCRelImm(Address, Val, O); } else if (MC.isExpr()) - MC.getExpr()->print(OS, &MAI); + MC.getExpr()->print(O, &MAI); else llvm_unreachable("Invalid operand"); } -void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum, - raw_ostream &OS) { +void XtensaInstPrinter::printLoopTarget(const MCInst *MI, uint64_t Address, + int OpNum, raw_ostream &O) { + const MCOperand &MC = MI->getOperand(OpNum); + if (MI->getOperand(OpNum).isImm()) { + int64_t Val = MC.getImm() + 4; + printPCRelImm(Address, Val, O); + } else if (MC.isExpr()) + MC.getExpr()->print(O, &MAI, true); + else + llvm_unreachable("Invalid operand"); +} + +void XtensaInstPrinter::printJumpTarget(const MCInst *MI, uint64_t Address, + int OpNum, raw_ostream &O) { const MCOperand &MC = MI->getOperand(OpNum); if (MC.isImm()) { int64_t Val = MC.getImm() + 4; - OS << ". "; - if (Val > 0) - OS << '+'; - OS << Val; + printPCRelImm(Address, Val, O); } else if (MC.isExpr()) - MC.getExpr()->print(OS, &MAI); + MC.getExpr()->print(O, &MAI); else llvm_unreachable("Invalid operand"); ; } -void XtensaInstPrinter::printCallOperand(const MCInst *MI, int OpNum, - raw_ostream &OS) { +void XtensaInstPrinter::printCallOperand(const MCInst *MI, uint64_t Address, + int OpNum, raw_ostream &O) { const MCOperand &MC = MI->getOperand(OpNum); if (MC.isImm()) { int64_t Val = MC.getImm() + 4; - OS << ". "; - if (Val > 0) - OS << '+'; - OS << Val; + if (PrintBranchImmAsAddress) { + uint64_t Target = Address; + Target &= ~0x3; + Target += Val & (~0x3); + O << formatHex(Target); + } else { + O << ". "; + if (Val > 0) + O << '+'; + O << Val; + } } else if (MC.isExpr()) - MC.getExpr()->print(OS, &MAI); + MC.getExpr()->print(O, &MAI); else llvm_unreachable("Invalid operand"); } -void XtensaInstPrinter::printL32RTarget(const MCInst *MI, int OpNum, - raw_ostream &O) { +void XtensaInstPrinter::printL32RTarget(const MCInst *MI, uint64_t Address, + int OpNum, raw_ostream &O) { const MCOperand &MC = MI->getOperand(OpNum); if (MC.isImm()) { int64_t Value = MI->getOperand(OpNum).getImm(); - int64_t InstrOff = Value & 0x3; - Value -= InstrOff; - assert((Value >= -262144 && Value <= -4) && - "Invalid argument, value must be in ranges [-262144,-4]"); - Value += ((InstrOff + 0x3) & 0x4) - InstrOff; - O << ". "; - O << Value; + if (PrintBranchImmAsAddress) { + uint64_t Target = (Address + 0x3) & (~0x3); + Value &= ~0x3; + Target += Value; + O << formatHex(Target); + } else { + int64_t InstrOff = Value & 0x3; + Value -= InstrOff; + assert((Value >= -262144 && Value <= -4) && + "Invalid argument, value must be in ranges [-262144,-4]"); + Value += ((InstrOff + 0x3) & 0x4) - InstrOff; + printPCRelImm(Address, Value, O); + } } else if (MC.isExpr()) MC.getExpr()->print(O, &MAI); else llvm_unreachable("Invalid operand"); } +void XtensaInstPrinter::printPCRelImm(uint64_t Address, int64_t Offset, + raw_ostream &O) { + if (PrintBranchImmAsAddress) { + uint64_t Target = Address + Offset; + Target &= 0xffffffff; + O << formatHex(Target); + } else { + O << ". "; + if (Offset > 0) + O << '+'; + O << Offset; + } +} + void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { @@ -404,3 +437,14 @@ void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum, } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 7 && Value <= 22) && + "Invalid argument, value must be in range <7,22>"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h index 630b4dd60108f..e25e36ed61ccf 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -45,10 +45,17 @@ class XtensaInstPrinter : public MCInstPrinter { // Print various types of operand. void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O); - void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O); - void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O); - void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O); - void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O); + void printBranchTarget(const MCInst *MI, uint64_t Address, int OpNum, + raw_ostream &O); + void printLoopTarget(const MCInst *MI, uint64_t Address, int OpNum, + raw_ostream &O); + void printJumpTarget(const MCInst *MI, uint64_t Address, int OpNum, + raw_ostream &O); + void printCallOperand(const MCInst *MI, uint64_t Address, int OpNum, + raw_ostream &O); + void printL32RTarget(const MCInst *MI, uint64_t Address, int OpNum, + raw_ostream &O); + void printPCRelImm(uint64_t Address, int64_t Offset, raw_ostream &O); void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); @@ -69,6 +76,7 @@ class XtensaInstPrinter : public MCInstPrinter { void printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp index e6cdd3d0020fc..8231a8a9a44d4 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -67,6 +67,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -134,6 +138,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter { uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getImm7_22OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // namespace @@ -220,6 +228,23 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding( } } +uint32_t +XtensaMCCodeEmitter::getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNum); + if (MO.isImm()) + return static_cast(MO.getImm()); + + assert((MO.isExpr()) && "Unexpected operand value!"); + + const MCExpr *Expr = MO.getExpr(); + + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(Xtensa::fixup_xtensa_loop_8), MI.getLoc())); + return 0; +} + uint32_t XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum, SmallVectorImpl &Fixups, @@ -554,4 +579,17 @@ XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo, return Res; } + +uint32_t +XtensaMCCodeEmitter::getImm7_22OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t res = static_cast(MO.getImm()); + + res -= 7; + assert(((res & 0xf) == res) && "Unexpected operand value!"); + + return res; +} #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index adaa9a71a905c..792faf811aca9 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -79,6 +79,10 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) { switch (RegNo) { case Xtensa::BREG: return FeatureBits[Xtensa::FeatureBoolean]; + case Xtensa::LBEG: + case Xtensa::LEND: + case Xtensa::LCOUNT: + return FeatureBits[Xtensa::FeatureLoop]; case Xtensa::WINDOWBASE: case Xtensa::WINDOWSTART: return FeatureBits[Xtensa::FeatureWindowed]; diff --git a/llvm/lib/Target/Xtensa/XtensaFeatures.td b/llvm/lib/Target/Xtensa/XtensaFeatures.td index 184828cd253f3..8b2d351dae386 100644 --- a/llvm/lib/Target/Xtensa/XtensaFeatures.td +++ b/llvm/lib/Target/Xtensa/XtensaFeatures.td @@ -22,3 +22,28 @@ def FeatureBoolean : SubtargetFeature<"bool", "HasBoolean", "true", "Enable Xtensa Boolean extension">; def HasBoolean : Predicate<"Subtarget->hasBoolean()">, AssemblerPredicate<(all_of FeatureBoolean)>; + +def FeatureLoop : SubtargetFeature<"loop", "HasLoop", "true", + "Enable Xtensa Loop extension">; +def HasLoop : Predicate<"Subtarget->hasLoop()">, + AssemblerPredicate<(all_of FeatureLoop)>; + +def FeatureSEXT : SubtargetFeature<"sext", "HasSEXT", "true", + "Enable Xtensa Sign Extend option">; +def HasSEXT : Predicate<"Subtarget->hasSEXT()">, + AssemblerPredicate<(all_of FeatureSEXT)>; + +def FeatureCLAMPS : SubtargetFeature<"clamps", "HasCLAMPS", "true", + "Enable Xtensa CLAMPS option">; +def HasCLAMPS : Predicate<"Subtarget->hasCLAMPS()">, + AssemblerPredicate<(all_of FeatureCLAMPS)>; + +def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true", + "Enable Xtensa NSA option">; +def HasNSA : Predicate<"Subtarget->hasNSA()">, + AssemblerPredicate<(all_of FeatureNSA)>; + +def FeatureMINMAX : SubtargetFeature<"minmax", "HasMINMAX", "true", + "Enable Xtensa MINMAX option">; +def HasMINMAX : Predicate<"Subtarget->hasMINMAX()">, + AssemblerPredicate<(all_of FeatureMINMAX)>; diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index d4ee2ca72ad38..9ba87cf6d5878 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -75,8 +75,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setBooleanContents(ZeroOrOneBooleanContent); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, {MVT::i8, MVT::i16}, + Subtarget.hasSEXT() ? Legal : Expand); setOperationAction(ISD::BITCAST, MVT::i32, Expand); setOperationAction(ISD::BITCAST, MVT::f32, Expand); @@ -141,6 +141,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}, MVT::i32, + Subtarget.hasMINMAX() ? Legal : Expand); + // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); // Implement custom stack save and restore diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 2de19f62e14c5..9734e914db335 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -868,6 +868,94 @@ let Constraints = "$dr = $r,@earlyclobber $dr" in { "movt\t$r, $s, $t", []>, Requires<[HasBoolean]>; } +//===----------------------------------------------------------------------===// +// SEXT Instruction +//===----------------------------------------------------------------------===// + +def SEXT : RRR_Inst<0x00, 0x03, 0x02, (outs AR:$r), (ins AR:$s, imm7_22:$imm), + "sext\t$r, $s, $imm", []>, Requires<[HasSEXT]> { + bits<4> imm; + + let t = imm; +} + +def : Pat<(i32 (sext_inreg AR:$s, i8)), (SEXT AR:$s, (i32 7))>; +def : Pat<(i32 (sext_inreg AR:$s, i16)), (SEXT AR:$s, (i32 15))>; + +//===----------------------------------------------------------------------===// +// CLAMPS Instruction +//===----------------------------------------------------------------------===// + +def CLAMPS : RRR_Inst<0x00, 0x03, 0x03, (outs AR:$r), (ins AR:$s, imm7_22:$imm), + "clamps\t$r, $s, $imm", []>, Requires<[HasCLAMPS]> { + bits<4> imm; + + let t = imm; +} + +//===----------------------------------------------------------------------===// +// NSA Instructions +//===----------------------------------------------------------------------===// + +def NSA : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), + "nsa\t$t, $s", []>, Requires<[HasNSA]> { + let r = 0xE; +} + +def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s), + "nsau\t$t, $s", + [(set AR:$t, (ctlz AR:$s))]>, Requires<[HasNSA]> { + let r = 0xF; +} + +//===----------------------------------------------------------------------===// +// MINMAX Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasMINMAX] in { + def MIN : ArithLogic_RRR<0x04, 0x03, "min", smin, 1>; + def MAX : ArithLogic_RRR<0x05, 0x03, "max", smax, 1>; + def MINU : ArithLogic_RRR<0x06, 0x03, "minu", umin, 1>; + def MAXU : ArithLogic_RRR<0x07, 0x03, "maxu", umax, 1>; +} + +//===----------------------------------------------------------------------===// +// Loop Instructions +//===----------------------------------------------------------------------===// + +def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loop\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; + + let r = 0x08; + let t = 0x07; + let imm8 = target; +} + +def : InstAlias<"_loop\t$s, $target", (LOOP AR:$s, ltarget:$target)>; + +def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loopgtz\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; + + let r = 0x0A; + let t = 0x07; + let imm8 = target; +} + +def : InstAlias<"_loopgtz\t$s, $target", (LOOPGTZ AR:$s, ltarget:$target)>; + +def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target), + "loopnez\t$s, $target", []>, Requires<[HasLoop]> { + bits<8> target; + + let r = 0x09; + let t = 0x07; + let imm8 = target; +} + +def : InstAlias<"_loopnez\t$s, $target", (LOOPNEZ AR:$s, ltarget:$target)>; + //===----------------------------------------------------------------------===// // DSP Instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 402e05a5c3dd1..d0f454736e500 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -167,6 +167,14 @@ def b4constu: Immediate; +def imm7_22: Immediate= 7 && Imm <= 22; }], "Imm7_22_AsmOperand"> { + let EncoderMethod = "getImm7_22OpValue"; + let DecoderMethod = "decodeImm7_22Operand"; +} + //===----------------------------------------------------------------------===// // Memory address operands //===----------------------------------------------------------------------===// @@ -214,6 +222,7 @@ def pcrel32call : Operand { let EncoderMethod = "getCallEncoding"; let DecoderMethod = "decodeCallOperand"; let ParserMatchClass = XtensaPCRelTargetAsmOperand; + let OperandType = "OPERAND_PCREL"; } def brtarget : Operand { @@ -221,6 +230,7 @@ def brtarget : Operand { let EncoderMethod = "getBranchTargetEncoding"; let DecoderMethod = "decodeBranchOperand"; let ParserMatchClass = XtensaPCRelTargetAsmOperand; + let OperandType = "OPERAND_PCREL"; } def jumptarget : Operand { @@ -228,6 +238,15 @@ def jumptarget : Operand { let EncoderMethod = "getJumpTargetEncoding"; let DecoderMethod = "decodeJumpOperand"; let ParserMatchClass = XtensaPCRelTargetAsmOperand; + let OperandType = "OPERAND_PCREL"; +} + +def ltarget : Operand { + let PrintMethod = "printLoopTarget"; + let EncoderMethod = "getLoopTargetEncoding"; + let DecoderMethod = "decodeLoopOperand"; + let ParserMatchClass = XtensaPCRelTargetAsmOperand; + let OperandType = "OPERAND_PCREL"; } def L32Rtarget : Operand { @@ -235,4 +254,5 @@ def L32Rtarget : Operand { let EncoderMethod = "getL32RTargetEncoding"; let DecoderMethod = "decodeL32ROperand"; let ParserMatchClass = XtensaPCRelTargetAsmOperand; + let OperandType = "OPERAND_PCREL"; } diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td index 2934018318406..2a40431adc7f0 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td @@ -73,6 +73,11 @@ class SRReg num, string n, list alt = []> : XtensaReg { let AltNames = alt; } +// Loop Option Registers +def LBEG : SRReg<0, "lbeg", ["LBEG", "0"]>; +def LEND : SRReg<1, "lend", ["LEND", "1"]>; +def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>; + // Shift Amount Register def SAR : SRReg<3, "sar", ["SAR","3"]>; @@ -95,8 +100,8 @@ def MR01 : RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>; def MR23 : RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>; def MR : RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>; -def SR : RegisterClass<"Xtensa", [i32], 32, (add SAR, BREG, MR, - WINDOWBASE, WINDOWSTART)>; +def SR : RegisterClass<"Xtensa", [i32], 32, (add + LBEG, LEND, LCOUNT, SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>; //===----------------------------------------------------------------------===// // Boolean registers diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h index 05c0c07e93a96..ef86df20f9e1f 100644 --- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h +++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h @@ -65,13 +65,14 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo { } bool hasDensity() const { return HasDensity; } - bool hasMAC16() const { return HasMAC16; } - bool hasWindowed() const { return HasWindowed; } - bool hasBoolean() const { return HasBoolean; } - + bool hasLoop() const { return HasLoop; } + bool hasSEXT() const { return HasSEXT; } + bool hasCLAMPS() const { return HasCLAMPS; } + bool hasNSA() const { return HasNSA; } + bool hasMINMAX() const { return HasMINMAX; } bool isWindowedABI() const { return hasWindowed(); } // Automatically generated by tblgen. diff --git a/llvm/test/CodeGen/Xtensa/minmax.ll b/llvm/test/CodeGen/Xtensa/minmax.ll new file mode 100644 index 0000000000000..2f95c78170897 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/minmax.ll @@ -0,0 +1,52 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=xtensa --mattr=+minmax -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA %s + +declare i32 @llvm.smin.i32(i32, i32) +declare i32 @llvm.umin.i32(i32, i32) +declare i32 @llvm.smax.i32(i32, i32) +declare i32 @llvm.umax.i32(i32, i32) + +define i32 @test_smin(i32 %x, i32 %y) { +; XTENSA-LABEL: test_smin: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: # %entry +; XTENSA-NEXT: min a2, a2, a3 +; XTENSA-NEXT: ret +entry: + %res = call i32 @llvm.smin.i32(i32 %x, i32 %y) + ret i32 %res +} + +define i32 @test_umin(i32 %x, i32 %y) { +; XTENSA-LABEL: test_umin: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: # %entry +; XTENSA-NEXT: minu a2, a2, a3 +; XTENSA-NEXT: ret +entry: + %res = call i32 @llvm.umin.i32(i32 %x, i32 %y) + ret i32 %res +} + +define i32 @test_smax(i32 %x, i32 %y) { +; XTENSA-LABEL: test_smax: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: # %entry +; XTENSA-NEXT: max a2, a2, a3 +; XTENSA-NEXT: ret +entry: + %res = call i32 @llvm.smax.i32(i32 %x, i32 %y) + ret i32 %res +} + +define i32 @test_umax(i32 %x, i32 %y) { +; XTENSA-LABEL: test_umax: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: # %entry +; XTENSA-NEXT: maxu a2, a2, a3 +; XTENSA-NEXT: ret +entry: + %res = call i32 @llvm.umax.i32(i32 %x, i32 %y) + ret i32 %res +} diff --git a/llvm/test/CodeGen/Xtensa/sext.ll b/llvm/test/CodeGen/Xtensa/sext.ll new file mode 100644 index 0000000000000..36a1c9b32903e --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/sext.ll @@ -0,0 +1,23 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=xtensa --mattr=+sext -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA %s + +define i32 @sext_i8(i8 %a) { +; XTENSA-LABEL: sext_i8: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: +; XTENSA-NEXT: sext a2, a2, 7 +; XTENSA-NEXT: ret + %res = sext i8 %a to i32 + ret i32 %res +} + +define i32 @sext_i16(i16 %a) { +; XTENSA-LABEL: sext_i16: +; XTENSA: .cfi_startproc +; XTENSA-NEXT: # %bb.0: +; XTENSA-NEXT: sext a2, a2, 15 +; XTENSA-NEXT: ret + %res = sext i16 %a to i32 + ret i32 %res +} diff --git a/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s b/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s index e0eac900552ce..9a81ade9fe284 100644 --- a/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s +++ b/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s @@ -1,4 +1,4 @@ -# RUN: not llvm-mc -triple xtensa -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple xtensa --mattr=+loop -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s .align 4 @@ -8,6 +8,8 @@ LBL0: call0 LBL0 # CHECK: :[[@LINE]]:3: error: fixup value must be 4-byte aligned + loop a3, LBL0 # CHECK: :[[@LINE]]:3: error: loop fixup value out of range + .space 1<<8 LBL1: .space 1<<12 diff --git a/llvm/test/MC/Xtensa/Relocations/fixups.s b/llvm/test/MC/Xtensa/Relocations/fixups.s index 0a3a9eeef1159..ba8f663341e45 100644 --- a/llvm/test/MC/Xtensa/Relocations/fixups.s +++ b/llvm/test/MC/Xtensa/Relocations/fixups.s @@ -1,7 +1,7 @@ -# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \ +# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \ # RUN: | FileCheck -check-prefix=CHECK-FIXUP %s -# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \ -# RUN: | llvm-objdump --mattr=+density -d - | FileCheck -check-prefix=CHECK-INSTR %s +# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \ +# RUN: | llvm-objdump --mattr=+density,loop -d - | FileCheck -check-prefix=CHECK-INSTR %s # Checks that fixups that can be resolved within the same object file are @@ -13,43 +13,43 @@ LBL0: beqz.n a2, LBL1 # CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_6 -# CHECK-INSTR: beqz.n a2, . +29 +# CHECK-INSTR: beqz.n a2, 0x29 beq a0, a1, LBL0 -# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_8 -# CHECK-INSTR: beq a0, a1, . -14 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: +# CHECK-INSTR: beq a0, a1, 0x0 beq a0, a1, LBL1 # CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_8 -# CHECK-INSTR: beq a0, a1, . +24 +# CHECK-INSTR: beq a0, a1, 0x29 beqz a2, LBL0 # CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_12 -# CHECK-INSTR: beqz a2, . -20 +# CHECK-INSTR: beqz a2, 0x0 beqz a2, LBL1 # CHECK-FIXUP: fixup A - offset: 0, value: LBL1, kind: fixup_xtensa_branch_12 -# CHECK-INSTR: beqz a2, . +18 +# CHECK-INSTR: beqz a2, 0x29 call0 LBL0 # CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_call_18 -# CHECK-INSTR: call0 . -24 +# CHECK-INSTR: call0 0x0 call0 LBL2 # CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_call_18 -# CHECK-INSTR: call0 . +2068 +# CHECK-INSTR: call0 0x830 j LBL0 # CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_jump_18 -# CHECK-INSTR: j . -32 +# CHECK-INSTR: j 0x0 j LBL2 # CHECK-FIXUP: fixup A - offset: 0, value: LBL2, kind: fixup_xtensa_jump_18 -# CHECK-INSTR: j . +2061 +# CHECK-INSTR: j 0x830 l32r a1, LBL0 # CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_l32r_16 -# CHECK-INSTR: l32r a1, . -38 +# CHECK-INSTR: l32r a1, 0x0 LBL1: @@ -57,3 +57,11 @@ LBL1: .align 4 LBL2: + +loop a3, LBL3 +# CHECK-FIXUP: fixup A - offset: 0, value: LBL3, kind: fixup_xtensa_loop_8 +# CHECK-INSTR: loop a3, 0x8fb + +.fill 200 + +LBL3: diff --git a/llvm/test/MC/Xtensa/Relocations/relocations.s b/llvm/test/MC/Xtensa/Relocations/relocations.s index 339f6cb44bfcf..7937d5d729870 100644 --- a/llvm/test/MC/Xtensa/Relocations/relocations.s +++ b/llvm/test/MC/Xtensa/Relocations/relocations.s @@ -1,6 +1,6 @@ -# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \ +# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \ # RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s -# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \ +# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \ # RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s # Check prefixes: @@ -183,3 +183,12 @@ l32r a6, func # RELOC: R_XTENSA_SLOT0_OP # INSTR: l32r a6, func # FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_l32r_16 + +loop a3, LBL +# RELOC: R_XTENSA_SLOT0_OP +# INSTR: loop a3, LBL +# FIXUP: fixup A - offset: 0, value: LBL, kind: fixup_xtensa_loop_8 + +.fill 200 + +LBL: diff --git a/llvm/test/MC/Xtensa/loop.s b/llvm/test/MC/Xtensa/loop.s new file mode 100644 index 0000000000000..cdcb23f276f7b --- /dev/null +++ b/llvm/test/MC/Xtensa/loop.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+loop \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 + +# Instruction format BRI8 +# CHECK-INST: loop a3, LBL +# CHECK: encoding: [0x76,0x83,A] +loop a3, LBL + +# Instruction format BRI8 +# CHECK-INST: loopnez a3, LBL +# CHECK: encoding: [0x76,0x93,A] +loopnez a3, LBL + +# Instruction format BRI8 +# CHECK-INST: loopgtz a3, LBL +# CHECK: encoding: [0x76,0xa3,A] +loopgtz a3, LBL + +# CHECK-INST: xsr a3, lbeg +# CHECK: # encoding: [0x30,0x00,0x61] +xsr a3, lbeg + +# CHECK-INST: xsr a3, lend +# CHECK: # encoding: [0x30,0x01,0x61] +xsr a3, lend + +# CHECK-INST: xsr a3, lcount +# CHECK: # encoding: [0x30,0x02,0x61] +xsr a3, lcount + +.fill 200 + +LBL: diff --git a/llvm/test/MC/Xtensa/minmax.s b/llvm/test/MC/Xtensa/minmax.s new file mode 100644 index 0000000000000..4ee5849ff7bf1 --- /dev/null +++ b/llvm/test/MC/Xtensa/minmax.s @@ -0,0 +1,24 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+minmax \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 + +# Instruction format RRR +# CHECK-INST: max a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x53] +max a3, a4, a5 + +# Instruction format RRR +# CHECK-INST: maxu a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x73] +maxu a3, a4, a5 + +# Instruction format RRR +# CHECK-INST: min a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x43] +min a3, a4, a5 + +# Instruction format RRR +# CHECK-INST: minu a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x63] +minu a3, a4, a5 diff --git a/llvm/test/MC/Xtensa/nsau.s b/llvm/test/MC/Xtensa/nsau.s new file mode 100644 index 0000000000000..791485b1ed751 --- /dev/null +++ b/llvm/test/MC/Xtensa/nsau.s @@ -0,0 +1,14 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+nsa \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 + +# Instruction format RRR +# CHECK-INST: nsa a3, a4 +# CHECK: encoding: [0x30,0xe4,0x40] +nsa a3, a4 + +# Instruction format RRR +# CHECK-INST: nsau a3, a4 +# CHECK: encoding: [0x30,0xf4,0x40] +nsau a3, a4 diff --git a/llvm/test/MC/Xtensa/sext.s b/llvm/test/MC/Xtensa/sext.s new file mode 100644 index 0000000000000..11efe614a1103 --- /dev/null +++ b/llvm/test/MC/Xtensa/sext.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+sext \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + +.align 4 + +# Instruction format RRR +# CHECK-INST: sext a3, a4, 7 +# CHECK: encoding: [0x00,0x34,0x23] +sext a3, a4, 7 diff --git a/llvm/test/MC/Xtensa/sext_invalid.s b/llvm/test/MC/Xtensa/sext_invalid.s new file mode 100644 index 0000000000000..c4aa48c67b645 --- /dev/null +++ b/llvm/test/MC/Xtensa/sext_invalid.s @@ -0,0 +1,9 @@ +# RUN: not llvm-mc -triple xtensa --mattr=+sext %s 2>&1 | FileCheck %s + +.align 4 + +# Out of range immediates + +# imm7_22 +sext a3, a4, 6 +# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [7, 22]