Skip to content

[PowerPC] Add error for incorrect use of memory operands #114277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 12, 2024
Merged
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
27 changes: 25 additions & 2 deletions llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -184,6 +185,7 @@ struct PPCOperand : public MCParsedAsmOperand {

struct ImmOp {
int64_t Val;
bool IsMemOpBase;
};

struct ExprOp {
Expand Down Expand Up @@ -244,6 +246,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;
Expand Down Expand Up @@ -696,9 +701,11 @@ struct PPCOperand : public MCParsedAsmOperand {
}

static std::unique_ptr<PPCOperand> CreateImm(int64_t Val, SMLoc S, SMLoc E,
bool IsPPC64) {
bool IsPPC64,
bool IsMemOpBase = false) {
auto Op = std::make_unique<PPCOperand>(Immediate);
Op->Imm.Val = Val;
Op->Imm.IsMemOpBase = IsMemOpBase;
Op->StartLoc = S;
Op->EndLoc = E;
Op->IsPPC64 = IsPPC64;
Expand Down Expand Up @@ -1252,14 +1259,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<const PPCOperand &>(*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<const PPCInstrInfo *>(&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);
Expand Down Expand Up @@ -1617,7 +1639,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;
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/PowerPC/PPCInstr64Bit.td
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
16 changes: 11 additions & 5 deletions llvm/lib/Target/PowerPC/PPCInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class I<bits<6> 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 = "";

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -250,7 +255,7 @@ class DForm_base<bits<6> opcode, dag OOL, dag IOL, string asmstr,

class DForm_1<bits<6> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: DForm_base<opcode, OOL, IOL, asmstr, itin, pattern> {
: DForm_base<opcode, OOL, IOL, asmstr, itin, pattern>, MemriOp {
}

class DForm_2<bits<6> opcode, dag OOL, dag IOL, string asmstr,
Expand Down Expand Up @@ -295,6 +300,7 @@ class DForm_4_zero<bits<6> opcode, dag OOL, dag IOL, string asmstr,
let RST = 0;
let RA = 0;
let D = 0;
let MemriOp = 0;
}

class DForm_4_fixedreg_zero<bits<6> opcode, bits<5> R, dag OOL, dag IOL,
Expand Down Expand Up @@ -372,7 +378,7 @@ class DForm_6_ext<bits<6> opcode, dag OOL, dag IOL, string asmstr,
// 1.7.5 DS-Form
class DSForm_1<bits<6> opcode, bits<2> xo, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
: I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
bits<5> RST;
bits<5> RA;
bits<14> D;
Expand Down Expand Up @@ -404,7 +410,7 @@ class DXForm<bits<6> 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<bits<6> opcode, bits<3> xo, dag OOL, dag IOL,
string asmstr, InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
: I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
bits<6> XT;
bits<5> RA;
bits<12> DQ;
Expand All @@ -421,7 +427,7 @@ class DQ_RD6_RS5_DQ12<bits<6> opcode, bits<3> xo, dag OOL, dag IOL,
class DQForm_RTp5_RA17_MEM<bits<6> opcode, bits<4> xo, dag OOL, dag IOL,
string asmstr, InstrItinClass itin,
list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
: I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
bits<5> RTp;
bits<5> RA;
bits<12> DQ;
Expand Down Expand Up @@ -1246,7 +1252,7 @@ class XX2_RD6_DCMX7_RS6<bits<6> opcode, bits<4> xo1, bits<3> xo2,

class XForm_XD6_RA5_RB5<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmstr, InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
: I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
bits<5> RA;
bits<6> D;
bits<5> RB;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,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,
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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))]>;
Expand Down Expand Up @@ -3466,6 +3466,10 @@ class PPCAsmPseudo<string asm, dag iops>
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
Expand Down Expand Up @@ -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)>;
Expand Down
26 changes: 15 additions & 11 deletions llvm/lib/Target/PowerPC/PPCInstrP10.td
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ class PI<bits<6> 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
Expand Down Expand Up @@ -183,7 +187,7 @@ multiclass VXForm_VTB5_RCr<bits<10> xo, bits<5> R, dag OOL, dag IOL,

class MLS_DForm_R_SI34_RTA5_MEM<bits<6> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> 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;
Expand Down Expand Up @@ -257,7 +261,7 @@ multiclass MLS_DForm_R_SI34_RTA5_p<bits<6> opcode, dag OOL, dag IOL,

class 8LS_DForm_R_SI34_RTA5_MEM<bits<6> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> 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;
Expand All @@ -281,7 +285,7 @@ class 8LS_DForm_R_SI34_RTA5_MEM<bits<6> opcode, dag OOL, dag IOL, string asmstr,
class 8LS_DForm_R_SI34_XT6_RA5_MEM<bits<5> opcode, dag OOL, dag IOL,
string asmstr, InstrItinClass itin,
list<dag> 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;
Expand Down Expand Up @@ -585,7 +589,7 @@ multiclass MLS_DForm_R_SI34_RTA5_MEM_p<bits<6> opcode, dag OOL, dag IOL,
isPCRel;
let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in {
def nopc : MLS_DForm_R_SI34_RTA5_MEM<opcode, OOL, IOL, asmstr, itin, []>;
let RA = 0 in
let RA = 0, MemriOp = 0 in
def onlypc : MLS_DForm_R_SI34_RTA5_MEM<opcode, OOL, PCRelOnly_IOL,
asmstr_pcext, itin, []>, isPCRel;
}
Expand All @@ -602,7 +606,7 @@ multiclass 8LS_DForm_R_SI34_RTA5_MEM_p<bits<6> opcode, dag OOL, dag IOL,
isPCRel;
let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in {
def nopc : 8LS_DForm_R_SI34_RTA5_MEM<opcode, OOL, IOL, asmstr, itin, []>;
let RA = 0 in
let RA = 0, MemriOp = 0 in
def onlypc : 8LS_DForm_R_SI34_RTA5_MEM<opcode, OOL, PCRelOnly_IOL,
asmstr_pcext, itin, []>, isPCRel;
}
Expand All @@ -619,7 +623,7 @@ multiclass 8LS_DForm_R_SI34_XT6_RA5_MEM_p<bits<5> opcode, dag OOL, dag IOL,
isPCRel;
let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in {
def nopc : 8LS_DForm_R_SI34_XT6_RA5_MEM<opcode, OOL, IOL, asmstr, itin, []>;
let RA = 0 in
let RA = 0, MemriOp = 0 in
def onlypc : 8LS_DForm_R_SI34_XT6_RA5_MEM<opcode, OOL, PCRelOnly_IOL,
asmstr_pcext, itin, []>, isPCRel;
}
Expand Down Expand Up @@ -847,7 +851,7 @@ let Predicates = [PrefixInstrs, HasP10Vector] in {

class DQForm_XTp5_RA17_MEM<bits<6> opcode, bits<4> xo, dag OOL, dag IOL,
string asmstr, InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
: I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
bits<5> XTp;
bits<5> RA;
bits<12> DQ;
Expand Down Expand Up @@ -879,7 +883,7 @@ class XForm_XTp5_XAB5<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,

class 8LS_DForm_R_XTp5_SI34_MEM<bits<6> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> 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;
Expand Down Expand Up @@ -910,7 +914,7 @@ multiclass 8LS_DForm_R_XTp5_SI34_MEM_p<bits<6> opcode, dag OOL,
isPCRel;
let isAsmParserOnly = 1, hasNoSchedulingInfo = 1 in {
def nopc : 8LS_DForm_R_XTp5_SI34_MEM<opcode, OOL, IOL, asmstr, itin, []>;
let RA = 0 in
let RA = 0, MemriOp = 0 in
def onlypc : 8LS_DForm_R_XTp5_SI34_MEM<opcode, OOL, PCRelOnly_IOL,
asmstr_pcext, itin, []>, isPCRel;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/PowerPC/PPCInstrSPE.td
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class EVXForm_4<bits<8> xo, dag OOL, dag IOL, string asmstr,

class EVXForm_D<bits<11> xo, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern> :
I<4, OOL, IOL, asmstr, itin> {
I<4, OOL, IOL, asmstr, itin>, MemriOp {
bits<5> RT;
bits<5> RA;
bits<5> D;
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/PowerPC/2007-01-31-InlineAsmAddrMode.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ define void @test1() {
entry:
%Out = alloca %struct.A, align 4 ; <ptr> [#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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

15 changes: 15 additions & 0 deletions llvm/test/MC/PowerPC/ppc64-errors.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading