diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -51,9 +51,16 @@ namespace { struct RISCVOperand; +struct ParserOptionsSet { + bool IsPicEnabled; +}; + class RISCVAsmParser : public MCTargetAsmParser { SmallVector FeatureBitStack; + SmallVector ParserOptionsStack; + ParserOptionsSet ParserOptions; + SMLoc getLoc() const { return getParser().getTok().getLoc(); } bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); } bool isRV32E() const { return getSTI().hasFeature(RISCV::FeatureRV32E); } @@ -170,10 +177,15 @@ } void pushFeatureBits() { + assert(FeatureBitStack.size() == ParserOptionsStack.size() && + "These two stacks must be kept synchronized"); FeatureBitStack.push_back(getSTI().getFeatureBits()); + ParserOptionsStack.push_back(ParserOptions); } bool popFeatureBits() { + assert(FeatureBitStack.size() == ParserOptionsStack.size() && + "These two stacks must be kept synchronized"); if (FeatureBitStack.empty()) return true; @@ -181,8 +193,11 @@ copySTI().setFeatureBits(FeatureBits); setAvailableFeatures(ComputeAvailableFeatures(FeatureBits)); + ParserOptions = ParserOptionsStack.pop_back_val(); + return false; } + public: enum RISCVMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, @@ -216,6 +231,9 @@ "doesn't support the D instruction set extension (ignoring " "target-abi)\n"; } + + const MCObjectFileInfo *MOFI = Parser.getContext().getObjectFileInfo(); + ParserOptions.IsPicEnabled = MOFI->isPositionIndependent(); } }; @@ -1668,6 +1686,30 @@ return false; } + if (Option == "pic") { + getTargetStreamer().emitDirectiveOptionPIC(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + ParserOptions.IsPicEnabled = true; + return false; + } + + if (Option == "nopic") { + getTargetStreamer().emitDirectiveOptionNoPIC(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + ParserOptions.IsPicEnabled = false; + return false; + } + if (Option == "relax") { getTargetStreamer().emitDirectiveOptionRelax(); @@ -1931,8 +1973,7 @@ const MCExpr *Symbol = Inst.getOperand(1).getExpr(); unsigned SecondOpcode; RISCVMCExpr::VariantKind VKHi; - // FIXME: Should check .option (no)pic when implemented - if (getContext().getObjectFileInfo()->isPositionIndependent()) { + if (ParserOptions.IsPicEnabled) { SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW; VKHi = RISCVMCExpr::VK_RISCV_GOT_HI; } else { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -97,6 +97,8 @@ void emitDirectiveOptionPush() override; void emitDirectiveOptionPop() override; + void emitDirectiveOptionPIC() override; + void emitDirectiveOptionNoPIC() override; void emitDirectiveOptionRVC() override; void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -66,6 +66,8 @@ void RISCVTargetELFStreamer::emitDirectiveOptionPush() {} void RISCVTargetELFStreamer::emitDirectiveOptionPop() {} +void RISCVTargetELFStreamer::emitDirectiveOptionPIC() {} +void RISCVTargetELFStreamer::emitDirectiveOptionNoPIC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -21,6 +21,8 @@ virtual void emitDirectiveOptionPush() = 0; virtual void emitDirectiveOptionPop() = 0; + virtual void emitDirectiveOptionPIC() = 0; + virtual void emitDirectiveOptionNoPIC() = 0; virtual void emitDirectiveOptionRVC() = 0; virtual void emitDirectiveOptionNoRVC() = 0; virtual void emitDirectiveOptionRelax() = 0; @@ -49,6 +51,8 @@ void emitDirectiveOptionPush() override; void emitDirectiveOptionPop() override; + void emitDirectiveOptionPIC() override; + void emitDirectiveOptionNoPIC() override; void emitDirectiveOptionRVC() override; void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -61,6 +61,14 @@ OS << "\t.option\tpop\n"; } +void RISCVTargetAsmStreamer::emitDirectiveOptionPIC() { + OS << "\t.option\tpic\n"; +} + +void RISCVTargetAsmStreamer::emitDirectiveOptionNoPIC() { + OS << "\t.option\tnopic\n"; +} + void RISCVTargetAsmStreamer::emitDirectiveOptionRVC() { OS << "\t.option\trvc\n"; } diff --git a/llvm/test/CodeGen/RISCV/option-nopic.ll b/llvm/test/CodeGen/RISCV/option-nopic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/option-nopic.ll @@ -0,0 +1,18 @@ +; RUN: llc -mtriple=riscv32 -filetype=obj --relocation-model=pic < %s\ +; RUN: | llvm-objdump --triple=riscv32 --mattr=+c -d -M no-aliases -\ +; RUN: | FileCheck -check-prefix=CHECK %s + +; This test demonstrates that .option nopic has no effect on codegen when +; emitting an ELF directly. + +@symbol = global i32 zeroinitializer + +define i32 @get_symbol() nounwind { +; CHECK-LABEL: : +; CHECK: auipc a0, 0 +; CHECK: lw a0, 0(a0) +; CHECK: lw a0, 0(a0) + tail call void asm sideeffect ".option nopic", ""() + %v = load i32, i32* @symbol + ret i32 %v +} diff --git a/llvm/test/CodeGen/RISCV/option-pic.ll b/llvm/test/CodeGen/RISCV/option-pic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/option-pic.ll @@ -0,0 +1,17 @@ +; RUN: llc -mtriple=riscv32 -filetype=obj < %s\ +; RUN: | llvm-objdump --triple=riscv32 --mattr=+c -d -M no-aliases -\ +; RUN: | FileCheck -check-prefix=CHECK %s + +; This test demonstrates that .option pic has no effect on codegen when +; emitting an ELF directly. + +@symbol = global i32 zeroinitializer + +define i32 @get_symbol() nounwind { +; CHECK-LABEL: : +; CHECK: lui a0, 0 +; CHECK: lw a0, 0(a0) + tail call void asm sideeffect ".option pic", ""() + %v = load i32, i32* @symbol + ret i32 %v +} diff --git a/llvm/test/MC/RISCV/option-nopic.s b/llvm/test/MC/RISCV/option-nopic.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/option-nopic.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc -triple riscv32 -mattr=-relax -riscv-no-aliases < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv32 -mattr=-relax -riscv-no-aliases \ +# RUN: -position-independent < %s | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -position-independent < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv64 -mattr=-relax -riscv-no-aliases < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv64 -mattr=-relax -riscv-no-aliases \ +# RUN: -position-independent < %s | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -position-independent < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +.option nopic +# CHECK-INST: .option nopic + +la s0, symbol +# CHECK-INST: auipc s0, %pcrel_hi(symbol) +# CHECK-INST: addi s0, s0, %pcrel_lo(.Lpcrel_hi0) +# CHECK-RELOC: R_RISCV_PCREL_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi0 0x0 + diff --git a/llvm/test/MC/RISCV/option-pic.s b/llvm/test/MC/RISCV/option-pic.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/option-pic.s @@ -0,0 +1,28 @@ +# RUN: llvm-mc -triple riscv32 -mattr=-relax -riscv-no-aliases < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv32 -mattr=-relax -riscv-no-aliases \ +# RUN: -position-independent < %s | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv32 -position-independent < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv64 -mattr=-relax -riscv-no-aliases < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +# RUN: llvm-mc -triple riscv64 -mattr=-relax -riscv-no-aliases \ +# RUN: -position-independent < %s | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple riscv64 -position-independent < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=CHECK-RELOC %s + +.option pic +# CHECK-INST: .option pic + +la s0, symbol +# CHECK-INST: auipc s0, %got_pcrel_hi(symbol) +# CHECK-INST: l{{[wd]}} s0, %pcrel_lo(.Lpcrel_hi0)(s0) +# CHECK-RELOC: R_RISCV_GOT_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi0 0x0 diff --git a/llvm/test/MC/RISCV/option-pushpop.s b/llvm/test/MC/RISCV/option-pushpop.s --- a/llvm/test/MC/RISCV/option-pushpop.s +++ b/llvm/test/MC/RISCV/option-pushpop.s @@ -72,3 +72,45 @@ # CHECK-BYTES: 13 04 c1 3f # CHECK-ALIAS: addi s0, sp, 1020 addi s0, sp, 1020 + +.option push # Push pic=false +# CHECK-INST: .option push + +.option pic +# CHECK-INST: .option pic + +la s0, symbol +# CHECK-INST: auipc s0, %got_pcrel_hi(symbol) +# CHECK-INST: l{{[wd]}} s0, %pcrel_lo(.Lpcrel_hi0)(s0) +# CHECK-RELOC: R_RISCV_GOT_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi0 0x0 + +.option push # Push pic=true +# CHECK-INST: .option push + +.option nopic +# CHECK-INST: .option nopic + +la s0, symbol +# CHECK-INST: auipc s0, %pcrel_hi(symbol) +# CHECK-INST: addi s0, s0, %pcrel_lo(.Lpcrel_hi1) +# CHECK-RELOC: R_RISCV_PCREL_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi1 0x0 + +.option pop # Push pic=true +# CHECK-INST: .option pop + +la s0, symbol +# CHECK-INST: auipc s0, %got_pcrel_hi(symbol) +# CHECK-INST: l{{[wd]}} s0, %pcrel_lo(.Lpcrel_hi2)(s0) +# CHECK-RELOC: R_RISCV_GOT_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi2 0x0 + +.option pop # Push pic=false +# CHECK-INST: .option pop + +la s0, symbol +# CHECK-INST: auipc s0, %pcrel_hi(symbol) +# CHECK-INST: addi s0, s0, %pcrel_lo(.Lpcrel_hi3) +# CHECK-RELOC: R_RISCV_PCREL_HI20 symbol 0x0 +# CHECK-RELOC: R_RISCV_PCREL_LO12_I .Lpcrel_hi3 0x0