diff --git a/lld/test/ELF/ppc64-local-exec-tls.s b/lld/test/ELF/ppc64-local-exec-tls.s index 51dcb1a7395a1..f5cb683b9fcfc 100644 --- a/lld/test/ELF/ppc64-local-exec-tls.s +++ b/lld/test/ELF/ppc64-local-exec-tls.s @@ -62,7 +62,7 @@ test_ds: addi 2, 2, .TOC.-.Lfunc_gep3@l .Lfunc_lep3: .localentry test_ds, .Lfunc_lep3-.Lfunc_gep3 - ld 3, b@tprel, 13 + ld 3, b@tprel(13) blr test_lo_ds: @@ -71,7 +71,7 @@ test_lo_ds: addi 2, 2, .TOC.-.Lfunc_gep4@l .Lfunc_lep4: .localentry test_lo_ds, .Lfunc_lep4-.Lfunc_gep4 - ld 3, b@tprel@l, 13 + ld 3, b@tprel@l(13) blr test_highest_a: diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index abb6bd31c9c59..52cc8f82f50b6 100644 --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -8,6 +8,7 @@ #include "MCTargetDesc/PPCMCExpr.h" #include "MCTargetDesc/PPCMCTargetDesc.h" +#include "PPCInstrInfo.h" #include "PPCTargetStreamer.h" #include "TargetInfo/PowerPCTargetInfo.h" #include "llvm/ADT/STLExtras.h" @@ -182,6 +183,7 @@ struct PPCOperand : public MCParsedAsmOperand { struct ImmOp { int64_t Val; + bool IsMemOpBase; }; struct ExprOp { @@ -242,6 +244,9 @@ struct PPCOperand : public MCParsedAsmOperand { /// isPPC64 - True if this operand is for an instruction in 64-bit mode. bool isPPC64() const { return IsPPC64; } + /// isMemOpBase - True if this operand is the base of a memory operand. + bool isMemOpBase() const { return Kind == Immediate && Imm.IsMemOpBase; } + int64_t getImm() const { assert(Kind == Immediate && "Invalid access!"); return Imm.Val; @@ -694,9 +699,11 @@ struct PPCOperand : public MCParsedAsmOperand { } static std::unique_ptr CreateImm(int64_t Val, SMLoc S, SMLoc E, - bool IsPPC64) { + bool IsPPC64, + bool IsMemOpBase = false) { auto Op = std::make_unique(Immediate); Op->Imm.Val = Val; + Op->Imm.IsMemOpBase = IsMemOpBase; Op->StartLoc = S; Op->EndLoc = E; Op->IsPPC64 = IsPPC64; @@ -1250,14 +1257,29 @@ void PPCAsmParser::processInstruction(MCInst &Inst, static std::string PPCMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS, unsigned VariantID = 0); +// Check that the register+immediate memory operand is in the right position and +// is expected by the instruction. Returns true if the memory operand syntax is +// valid; otherwise, returns false. +static bool validateMemOp(const OperandVector &Operands, bool isMemriOp) { + for (size_t idx = 0; idx < Operands.size(); ++idx) { + const PPCOperand &Op = static_cast(*Operands[idx]); + if (Op.isMemOpBase() != (idx == 3 && isMemriOp)) + return false; + } + return true; +} + bool PPCAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; + const PPCInstrInfo *TII = static_cast(&MII); switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { case Match_Success: + if (!validateMemOp(Operands, TII->isMemriOp(Inst.getOpcode()))) + return Error(IDLoc, "invalid operand for instruction"); // Post-process instructions (typically extended mnemonics) processInstruction(Inst, Operands); Inst.setLoc(IDLoc); @@ -1615,7 +1637,8 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) { E = Parser.getTok().getLoc(); if (parseToken(AsmToken::RParen, "missing ')'")) return true; - Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64())); + Operands.push_back( + PPCOperand::CreateImm(IntVal, S, E, isPPC64(), /*IsMemOpBase=*/true)); } return false; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h index 16777725990aa..579ee5e8facb6 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h @@ -171,7 +171,9 @@ enum { /// This instruction produced a sign extended result. SExt32To64 = 0x1 << (NewDef_Shift + 2), /// This instruction produced a zero extended result. - ZExt32To64 = 0x1 << (NewDef_Shift + 3) + ZExt32To64 = 0x1 << (NewDef_Shift + 3), + /// This instruction takes a register+immediate memory operand. + MemriOp = 0x1 << (NewDef_Shift + 4) }; } // end namespace PPCII diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td index 68419068e52a6..bcac0de55d9d3 100644 --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -777,7 +777,7 @@ def ADDIS8 : DForm_2<15, (outs g8rc:$RST), (ins g8rc_nox0:$RA, s17imm64:$D), def LA8 : DForm_2<14, (outs g8rc:$RST), (ins g8rc_nox0:$RA, s16imm64:$D), "la $RST, $D($RA)", IIC_IntGeneral, [(set i64:$RST, (add i64:$RA, - (PPClo tglobaladdr:$D, 0)))]>; + (PPClo tglobaladdr:$D, 0)))]>, MemriOp; let Defs = [CARRY] in { def SUBFIC8: DForm_2< 8, (outs g8rc:$RST), (ins g8rc:$RA, s16imm64:$D), diff --git a/llvm/lib/Target/PowerPC/PPCInstrFormats.td b/llvm/lib/Target/PowerPC/PPCInstrFormats.td index 5389f42a325ce..2ced3fe80ea99 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrFormats.td +++ b/llvm/lib/Target/PowerPC/PPCInstrFormats.td @@ -55,6 +55,10 @@ class I opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin> bits<1> ZExt32To64 = 0; let TSFlags{9} = ZExt32To64; + // Indicate that this instruction takes a register+immediate memory operand. + bits<1> MemriOp = 0; + let TSFlags{10} = MemriOp; + // Fields used for relation models. string BaseName = ""; @@ -82,6 +86,7 @@ class PPC970_Unit_BRU { bits<3> PPC970_Unit = 7; } class XFormMemOp { bits<1> XFormMemOp = 1; } class SExt32To64 { bits<1> SExt32To64 = 1; } class ZExt32To64 { bits<1> ZExt32To64 = 1; } +class MemriOp { bits<1> MemriOp = 1; } // Two joined instructions; used to emit two adjacent instructions as one. // The itinerary from the first instruction is used for scheduling and @@ -250,7 +255,7 @@ class DForm_base opcode, dag OOL, dag IOL, string asmstr, class DForm_1 opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : DForm_base { + : DForm_base, MemriOp { } class DForm_2 opcode, dag OOL, dag IOL, string asmstr, @@ -295,6 +300,7 @@ class DForm_4_zero opcode, dag OOL, dag IOL, string asmstr, let RST = 0; let RA = 0; let D = 0; + let MemriOp = 0; } class DForm_4_fixedreg_zero opcode, bits<5> R, dag OOL, dag IOL, @@ -372,7 +378,7 @@ class DForm_6_ext opcode, dag OOL, dag IOL, string asmstr, // 1.7.5 DS-Form class DSForm_1 opcode, bits<2> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : I { + : I, MemriOp { bits<5> RST; bits<5> RA; bits<14> D; @@ -404,7 +410,7 @@ class DXForm opcode, bits<5> xo, dag OOL, dag IOL, string asmstr, // DQ-Form: [PO T RA DQ TX XO] or [PO S RA DQ SX XO] class DQ_RD6_RS5_DQ12 opcode, bits<3> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : I { + : I, MemriOp { bits<6> XT; bits<5> RA; bits<12> DQ; @@ -421,7 +427,7 @@ class DQ_RD6_RS5_DQ12 opcode, bits<3> xo, dag OOL, dag IOL, class DQForm_RTp5_RA17_MEM opcode, bits<4> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : I { + : I, MemriOp { bits<5> RTp; bits<5> RA; bits<12> DQ; @@ -1246,7 +1252,7 @@ class XX2_RD6_DCMX7_RS6 opcode, bits<4> xo1, bits<3> xo2, class XForm_XD6_RA5_RB5 opcode, bits<10> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : I { + : I, MemriOp { bits<5> RA; bits<6> D; bits<5> RB; diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h index c2abf2f942746..cd8ecc2dcfac8 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -286,6 +286,9 @@ class PPCInstrInfo : public PPCGenInstrInfo { bool isZExt32To64(unsigned Opcode) const { return get(Opcode).TSFlags & PPCII::ZExt32To64; } + bool isMemriOp(unsigned Opcode) const { + return get(Opcode).TSFlags & PPCII::MemriOp; + } static bool isSameClassPhysRegCopy(unsigned Opcode) { unsigned CopyOpcodes[] = {PPC::OR, PPC::OR8, PPC::FMR, diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td index b4a5e41c0107a..1d8a372fe7632 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -2303,7 +2303,7 @@ let isCodeGenOnly = 1 in def LA : DForm_2<14, (outs gprc:$RST), (ins gprc_nor0:$RA, s16imm:$D), "la $RST, $D($RA)", IIC_IntGeneral, [(set i32:$RST, (add i32:$RA, - (PPClo tglobaladdr:$D, 0)))]>; + (PPClo tglobaladdr:$D, 0)))]>, MemriOp; def MULLI : DForm_2< 7, (outs gprc:$RST), (ins gprc:$RA, s16imm:$D), "mulli $RST, $RA, $D", IIC_IntMulLI, [(set i32:$RST, (mul i32:$RA, imm32SExt16:$D))]>; @@ -3466,6 +3466,10 @@ class PPCAsmPseudo let isAsmParserOnly = 1; let isPseudo = 1; let hasNoSchedulingInfo = 1; + + // Indicate that this instruction takes a register+immediate memory operand. + bits<1> MemriOp = 0; + let TSFlags{10} = MemriOp; } // Prefixed instructions may require access to the above defs at a later @@ -4714,7 +4718,7 @@ def : InstAlias<"tlbilxva $RA, $RB", (TLBILX 3, gprc:$RA, gprc:$RB)>, Requires<[IsBookE]>; def : InstAlias<"tlbilxva $RB", (TLBILX 3, R0, gprc:$RB)>, Requires<[IsBookE]>; -def LAx : PPCAsmPseudo<"la $rA, $addr", (ins gprc:$rA, memri:$addr)>; +def LAx : PPCAsmPseudo<"la $rA, $addr", (ins gprc:$rA, memri:$addr)>, MemriOp; def SUBI : PPCAsmPseudo<"subi $rA, $rB, $imm", (ins gprc:$rA, gprc:$rB, s16imm:$imm)>; diff --git a/llvm/lib/Target/PowerPC/PPCInstrP10.td b/llvm/lib/Target/PowerPC/PPCInstrP10.td index c4b8597b1df9f..9e3b38fe02dd0 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrP10.td +++ b/llvm/lib/Target/PowerPC/PPCInstrP10.td @@ -138,6 +138,10 @@ class PI pref, bits<6> opcode, dag OOL, dag IOL, string asmstr, bits<1> Prefixed = 1; // This is a prefixed instruction. let TSFlags{7} = Prefixed; + // Indicate that this instruction takes a register+immediate memory operand. + bits<1> MemriOp = 0; + let TSFlags{10} = MemriOp; + // For cases where multiple instruction definitions really represent the // same underlying instruction but with one definition for 64-bit arguments // and one for 32-bit arguments, this bit breaks the degeneracy between @@ -183,7 +187,7 @@ multiclass VXForm_VTB5_RCr xo, bits<5> R, dag OOL, dag IOL, class MLS_DForm_R_SI34_RTA5_MEM opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : PI<1, opcode, OOL, IOL, asmstr, itin> { + : PI<1, opcode, OOL, IOL, asmstr, itin>, MemriOp { bits<5> RST; bits<5> RA; bits<34> D; @@ -257,7 +261,7 @@ multiclass MLS_DForm_R_SI34_RTA5_p opcode, dag OOL, dag IOL, class 8LS_DForm_R_SI34_RTA5_MEM opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : PI<1, opcode, OOL, IOL, asmstr, itin> { + : PI<1, opcode, OOL, IOL, asmstr, itin>, MemriOp { bits<5> RST; bits<5> RA; bits<34> D; @@ -281,7 +285,7 @@ class 8LS_DForm_R_SI34_RTA5_MEM opcode, dag OOL, dag IOL, string asmstr, class 8LS_DForm_R_SI34_XT6_RA5_MEM opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : PI<1, { opcode, ? }, OOL, IOL, asmstr, itin> { + : PI<1, { opcode, ? }, OOL, IOL, asmstr, itin>, MemriOp { bits<6> XST; bits<5> RA; bits<34> D; @@ -585,7 +589,7 @@ multiclass MLS_DForm_R_SI34_RTA5_MEM_p opcode, dag OOL, dag IOL, isPCRel; let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in { def nopc : MLS_DForm_R_SI34_RTA5_MEM; - let RA = 0 in + let RA = 0, MemriOp = 0 in def onlypc : MLS_DForm_R_SI34_RTA5_MEM, isPCRel; } @@ -602,7 +606,7 @@ multiclass 8LS_DForm_R_SI34_RTA5_MEM_p opcode, dag OOL, dag IOL, isPCRel; let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in { def nopc : 8LS_DForm_R_SI34_RTA5_MEM; - let RA = 0 in + let RA = 0, MemriOp = 0 in def onlypc : 8LS_DForm_R_SI34_RTA5_MEM, isPCRel; } @@ -619,7 +623,7 @@ multiclass 8LS_DForm_R_SI34_XT6_RA5_MEM_p opcode, dag OOL, dag IOL, isPCRel; let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in { def nopc : 8LS_DForm_R_SI34_XT6_RA5_MEM; - let RA = 0 in + let RA = 0, MemriOp = 0 in def onlypc : 8LS_DForm_R_SI34_XT6_RA5_MEM, isPCRel; } @@ -847,7 +851,7 @@ let Predicates = [PrefixInstrs, HasP10Vector] in { class DQForm_XTp5_RA17_MEM opcode, bits<4> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : I { + : I, MemriOp { bits<5> XTp; bits<5> RA; bits<12> DQ; @@ -879,7 +883,7 @@ class XForm_XTp5_XAB5 opcode, bits<10> xo, dag OOL, dag IOL, class 8LS_DForm_R_XTp5_SI34_MEM opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> - : PI<1, opcode, OOL, IOL, asmstr, itin> { + : PI<1, opcode, OOL, IOL, asmstr, itin>, MemriOp { bits<5> XTp; bits<5> RA; bits<34> D; @@ -910,7 +914,7 @@ multiclass 8LS_DForm_R_XTp5_SI34_MEM_p opcode, dag OOL, isPCRel; let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in { def nopc : 8LS_DForm_R_XTp5_SI34_MEM; - let RA = 0 in + let RA = 0, MemriOp = 0 in def onlypc : 8LS_DForm_R_XTp5_SI34_MEM, isPCRel; } @@ -2506,7 +2510,7 @@ let Predicates = [IsISA3_1, PrefixInstrs], isAsmParserOnly = 1, hasNoSchedulingI let Interpretation64Bit = 1 in { def PLA8 : MLS_DForm_SI34_RT5<14, (outs g8rc:$RT), (ins g8rc_nox0:$RA, s34imm:$SI), - "pla $RT, ${SI} ${RA}", IIC_IntSimple, []>; + "pla $RT, ${SI} ${RA}", IIC_IntSimple, []>, MemriOp; def PLA8pc : MLS_DForm_SI34_RT5<14, (outs g8rc:$RT), (ins s34imm_pcrel:$SI), "pla $RT, $SI", IIC_IntSimple, []>, isPCRel; @@ -2517,7 +2521,7 @@ let Predicates = [IsISA3_1, PrefixInstrs], isAsmParserOnly = 1, hasNoSchedulingI def PLA : MLS_DForm_SI34_RT5<14, (outs gprc:$RT), (ins gprc_nor0:$RA, s34imm:$SI), - "pla $RT, ${SI} ${RA}", IIC_IntSimple, []>; + "pla $RT, ${SI} ${RA}", IIC_IntSimple, []>, MemriOp; def PLApc : MLS_DForm_SI34_RT5<14, (outs gprc:$RT), (ins s34imm_pcrel:$SI), "pla $RT, $SI", IIC_IntSimple, []>, isPCRel; diff --git a/llvm/lib/Target/PowerPC/PPCInstrSPE.td b/llvm/lib/Target/PowerPC/PPCInstrSPE.td index 5adfbad6ca118..e91cae349e082 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrSPE.td +++ b/llvm/lib/Target/PowerPC/PPCInstrSPE.td @@ -114,7 +114,7 @@ class EVXForm_4 xo, dag OOL, dag IOL, string asmstr, class EVXForm_D xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> : - I<4, OOL, IOL, asmstr, itin> { + I<4, OOL, IOL, asmstr, itin>, MemriOp { bits<5> RT; bits<5> RA; bits<5> D; diff --git a/llvm/test/CodeGen/PowerPC/2007-01-31-InlineAsmAddrMode.ll b/llvm/test/CodeGen/PowerPC/2007-01-31-InlineAsmAddrMode.ll index 24db84c0fb86e..8dff7c9ecd1e3 100644 --- a/llvm/test/CodeGen/PowerPC/2007-01-31-InlineAsmAddrMode.ll +++ b/llvm/test/CodeGen/PowerPC/2007-01-31-InlineAsmAddrMode.ll @@ -11,7 +11,7 @@ define void @test1() { entry: %Out = alloca %struct.A, align 4 ; [#uses=1] %tmp2 = getelementptr %struct.A, ptr %Out, i32 0, i32 1 - %tmp5 = call i32 asm "lwbrx $0, $1", "=r,m"(ptr %tmp2 ) + %tmp5 = call i32 asm "lbz $0, $1", "=r,m"(ptr %tmp2 ) ret void } diff --git a/llvm/test/CodeGen/PowerPC/2009-07-16-InlineAsm-M-Operand.ll b/llvm/test/CodeGen/PowerPC/2009-07-16-InlineAsm-M-Operand.ll index 76468f63ee741..537a7ae78a5a2 100644 --- a/llvm/test/CodeGen/PowerPC/2009-07-16-InlineAsm-M-Operand.ll +++ b/llvm/test/CodeGen/PowerPC/2009-07-16-InlineAsm-M-Operand.ll @@ -10,7 +10,7 @@ define void @memory_asm_operand(i32 %a) { ; "m" operand will be represented as: ; INLINEASM fake $0, 10, %R2, 20, -4, %R1 ; It is difficult to find the flag operand (20) when starting from %R1 - call i32 asm "lbzx $0, $1", "=r,m" (i32 %a) + call i32 asm "lbz $0, $1", "=r,m" (i32 %a) ret void } diff --git a/llvm/test/MC/PowerPC/ppc64-errors.s b/llvm/test/MC/PowerPC/ppc64-errors.s index 1c03dc084acdf..17905a396885a 100644 --- a/llvm/test/MC/PowerPC/ppc64-errors.s +++ b/llvm/test/MC/PowerPC/ppc64-errors.s @@ -143,3 +143,18 @@ # CHECK: error: invalid operand for instruction # CHECK-NEXT: lwarx 1, 2, 3, a lwarx 1, 2, 3, a + +# Instruction requires memory operand +# CHECK: error: invalid operand for instruction +# CHECK-NEXT: la 3, 3, 10 + la 3, 3, 10 + +# Instruction doesn't support memory operands +# CHECK: error: invalid operand for instruction +# CHECK-NEXT: addi 3, 10(3) + addi 3, 10(3) + +# Invalid memory operand position +# CHECK: error: invalid operand for instruction +# CHECK-NEXT: la 0(3), 3 + la 0(3), 3