Skip to content

Commit 9d3f125

Browse files
committed
[RISCV] Add common fixups and relocations
%lo(), %hi(), and %pcrel_hi() are supported and test cases have been added to ensure the appropriate fixups and relocations are generated. I've added an instruction format field which is used in RISCVMCCodeEmitter to, for instance, tell whether it should emit a lo12_i fixup or a lo12_s fixup (RISC-V has two 12-bit immediate encodings depending on the instruction type). Differential Revision: https://reviews.llvm.org/D23568 llvm-svn: 314389
1 parent 07f1e2e commit 9d3f125

17 files changed

+842
-43
lines changed

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

+162-20
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//===----------------------------------------------------------------------===//
99

1010
#include "MCTargetDesc/RISCVBaseInfo.h"
11+
#include "MCTargetDesc/RISCVMCExpr.h"
1112
#include "MCTargetDesc/RISCVMCTargetDesc.h"
1213
#include "llvm/ADT/STLExtras.h"
1314
#include "llvm/ADT/StringSwitch.h"
@@ -53,6 +54,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
5354
OperandMatchResultTy parseImmediate(OperandVector &Operands);
5455
OperandMatchResultTy parseRegister(OperandVector &Operands);
5556
OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands);
57+
OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
5658

5759
bool parseOperand(OperandVector &Operands);
5860

@@ -64,6 +66,10 @@ class RISCVAsmParser : public MCTargetAsmParser {
6466
#undef GET_OPERAND_DIAGNOSTIC_TYPES
6567
};
6668

69+
static bool classifySymbolRef(const MCExpr *Expr,
70+
RISCVMCExpr::VariantKind &Kind,
71+
int64_t &Addend);
72+
6773
RISCVAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
6874
const MCInstrInfo &MII, const MCTargetOptions &Options)
6975
: MCTargetAsmParser(Options, STI) {
@@ -121,13 +127,32 @@ struct RISCVOperand : public MCParsedAsmOperand {
121127
bool isImm() const override { return Kind == Immediate; }
122128
bool isMem() const override { return false; }
123129

124-
bool isConstantImm() const {
125-
return isImm() && dyn_cast<MCConstantExpr>(getImm());
126-
}
127-
128-
int64_t getConstantImm() const {
130+
bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const {
129131
const MCExpr *Val = getImm();
130-
return static_cast<const MCConstantExpr *>(Val)->getValue();
132+
bool Ret = false;
133+
if (auto *RE = dyn_cast<RISCVMCExpr>(Val)) {
134+
Ret = RE->evaluateAsConstant(Imm);
135+
VK = RE->getKind();
136+
} else if (auto CE = dyn_cast<MCConstantExpr>(Val)) {
137+
Ret = true;
138+
VK = RISCVMCExpr::VK_RISCV_None;
139+
Imm = CE->getValue();
140+
}
141+
return Ret;
142+
}
143+
144+
// True if operand is a symbol with no modifiers, or a constant with no
145+
// modifiers and isShiftedInt<N-1, 1>(Op).
146+
template <int N> bool isBareSimmNLsb0() const {
147+
int64_t Imm;
148+
RISCVMCExpr::VariantKind VK;
149+
bool IsConstantImm = evaluateConstantImm(Imm, VK);
150+
bool IsValid;
151+
if (!IsConstantImm)
152+
IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm);
153+
else
154+
IsValid = isShiftedInt<N - 1, 1>(Imm);
155+
return IsValid && VK == RISCVMCExpr::VK_RISCV_None;
131156
}
132157

133158
// Predicate methods for AsmOperands defined in RISCVInstrInfo.td
@@ -158,28 +183,49 @@ struct RISCVOperand : public MCParsedAsmOperand {
158183
}
159184

160185
bool isUImm5() const {
161-
return (isConstantImm() && isUInt<5>(getConstantImm()));
186+
int64_t Imm;
187+
RISCVMCExpr::VariantKind VK;
188+
bool IsConstantImm = evaluateConstantImm(Imm, VK);
189+
return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
162190
}
163191

164192
bool isSImm12() const {
165-
return (isConstantImm() && isInt<12>(getConstantImm()));
193+
RISCVMCExpr::VariantKind VK;
194+
int64_t Imm;
195+
bool IsValid;
196+
bool IsConstantImm = evaluateConstantImm(Imm, VK);
197+
if (!IsConstantImm)
198+
IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm);
199+
else
200+
IsValid = isInt<12>(Imm);
201+
return IsValid &&
202+
(VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO);
166203
}
167204

168205
bool isUImm12() const {
169-
return (isConstantImm() && isUInt<12>(getConstantImm()));
206+
int64_t Imm;
207+
RISCVMCExpr::VariantKind VK;
208+
bool IsConstantImm = evaluateConstantImm(Imm, VK);
209+
return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None;
170210
}
171211

172-
bool isSImm13Lsb0() const {
173-
return (isConstantImm() && isShiftedInt<12, 1>(getConstantImm()));
174-
}
212+
bool isSImm13Lsb0() const { return isBareSimmNLsb0<13>(); }
175213

176214
bool isUImm20() const {
177-
return (isConstantImm() && isUInt<20>(getConstantImm()));
215+
RISCVMCExpr::VariantKind VK;
216+
int64_t Imm;
217+
bool IsValid;
218+
bool IsConstantImm = evaluateConstantImm(Imm, VK);
219+
if (!IsConstantImm)
220+
IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm);
221+
else
222+
IsValid = isUInt<20>(Imm);
223+
return IsValid && (VK == RISCVMCExpr::VK_RISCV_None ||
224+
VK == RISCVMCExpr::VK_RISCV_HI ||
225+
VK == RISCVMCExpr::VK_RISCV_PCREL_HI);
178226
}
179227

180-
bool isSImm21Lsb0() const {
181-
return (isConstantImm() && isShiftedInt<20, 1>(getConstantImm()));
182-
}
228+
bool isSImm21Lsb0() const { return isBareSimmNLsb0<21>(); }
183229

184230
/// getStartLoc - Gets location of the first token of this operand
185231
SMLoc getStartLoc() const override { return StartLoc; }
@@ -234,7 +280,7 @@ struct RISCVOperand : public MCParsedAsmOperand {
234280
}
235281

236282
static std::unique_ptr<RISCVOperand> createImm(const MCExpr *Val, SMLoc S,
237-
SMLoc E) {
283+
SMLoc E, MCContext &Ctx) {
238284
auto Op = make_unique<RISCVOperand>(Immediate);
239285
Op->Imm.Val = Val;
240286
Op->StartLoc = S;
@@ -244,8 +290,17 @@ struct RISCVOperand : public MCParsedAsmOperand {
244290

245291
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
246292
assert(Expr && "Expr shouldn't be null!");
247-
if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
248-
Inst.addOperand(MCOperand::createImm(CE->getValue()));
293+
int64_t Imm = 0;
294+
bool IsConstant = false;
295+
if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) {
296+
IsConstant = RE->evaluateAsConstant(Imm);
297+
} else if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
298+
IsConstant = true;
299+
Imm = CE->getValue();
300+
}
301+
302+
if (IsConstant)
303+
Inst.addOperand(MCOperand::createImm(Imm));
249304
else
250305
Inst.addOperand(MCOperand::createExpr(Expr));
251306
}
@@ -411,9 +466,51 @@ OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) {
411466
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
412467
break;
413468
}
469+
case AsmToken::Percent:
470+
return parseOperandWithModifier(Operands);
471+
}
472+
473+
Operands.push_back(RISCVOperand::createImm(Res, S, E, getContext()));
474+
return MatchOperand_Success;
475+
}
476+
477+
OperandMatchResultTy
478+
RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) {
479+
SMLoc S = getLoc();
480+
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
481+
482+
if (getLexer().getKind() != AsmToken::Percent) {
483+
Error(getLoc(), "expected '%' for operand modifier");
484+
return MatchOperand_ParseFail;
485+
}
486+
487+
getParser().Lex(); // Eat '%'
488+
489+
if (getLexer().getKind() != AsmToken::Identifier) {
490+
Error(getLoc(), "expected valid identifier for operand modifier");
491+
return MatchOperand_ParseFail;
492+
}
493+
StringRef Identifier = getParser().getTok().getIdentifier();
494+
RISCVMCExpr::VariantKind VK = RISCVMCExpr::getVariantKindForName(Identifier);
495+
if (VK == RISCVMCExpr::VK_RISCV_Invalid) {
496+
Error(getLoc(), "unrecognized operand modifier");
497+
return MatchOperand_ParseFail;
498+
}
499+
500+
getParser().Lex(); // Eat the identifier
501+
if (getLexer().getKind() != AsmToken::LParen) {
502+
Error(getLoc(), "expected '('");
503+
return MatchOperand_ParseFail;
504+
}
505+
getParser().Lex(); // Eat '('
506+
507+
const MCExpr *SubExpr;
508+
if (getParser().parseParenExpression(SubExpr, E)) {
509+
return MatchOperand_ParseFail;
414510
}
415511

416-
Operands.push_back(RISCVOperand::createImm(Res, S, E));
512+
const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext());
513+
Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, getContext()));
417514
return MatchOperand_Success;
418515
}
419516

@@ -498,6 +595,51 @@ bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info,
498595
return false;
499596
}
500597

598+
bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr,
599+
RISCVMCExpr::VariantKind &Kind,
600+
int64_t &Addend) {
601+
Kind = RISCVMCExpr::VK_RISCV_None;
602+
Addend = 0;
603+
604+
if (const RISCVMCExpr *RE = dyn_cast<RISCVMCExpr>(Expr)) {
605+
Kind = RE->getKind();
606+
Expr = RE->getSubExpr();
607+
}
608+
609+
// It's a simple symbol reference or constant with no addend.
610+
if (isa<MCConstantExpr>(Expr) || isa<MCSymbolRefExpr>(Expr))
611+
return true;
612+
613+
const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr);
614+
if (!BE)
615+
return false;
616+
617+
if (!isa<MCSymbolRefExpr>(BE->getLHS()))
618+
return false;
619+
620+
if (BE->getOpcode() != MCBinaryExpr::Add &&
621+
BE->getOpcode() != MCBinaryExpr::Sub)
622+
return false;
623+
624+
// We are able to support the subtraction of two symbol references
625+
if (BE->getOpcode() == MCBinaryExpr::Sub &&
626+
isa<MCSymbolRefExpr>(BE->getRHS()))
627+
return true;
628+
629+
// See if the addend is is a constant, otherwise there's more going
630+
// on here than we can deal with.
631+
auto AddendExpr = dyn_cast<MCConstantExpr>(BE->getRHS());
632+
if (!AddendExpr)
633+
return false;
634+
635+
Addend = AddendExpr->getValue();
636+
if (BE->getOpcode() == MCBinaryExpr::Sub)
637+
Addend = -Addend;
638+
639+
// It's some symbol reference + a constant addend
640+
return Kind != RISCVMCExpr::VK_RISCV_Invalid;
641+
}
642+
501643
bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
502644

503645
extern "C" void LLVMInitializeRISCVAsmParser() {

llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_llvm_library(LLVMRISCVDesc
22
RISCVAsmBackend.cpp
33
RISCVELFObjectWriter.cpp
44
RISCVMCAsmInfo.cpp
5-
RISCVMCTargetDesc.cpp
65
RISCVMCCodeEmitter.cpp
6+
RISCVMCExpr.cpp
7+
RISCVMCTargetDesc.cpp
78
)

0 commit comments

Comments
 (0)