[llvm] [RISCV][GlobalISel] Select G_GLOBAL_VALUE (PR #70091)

Michael Maitland via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 24 14:58:33 PDT 2023


https://github.com/michaelmaitland updated https://github.com/llvm/llvm-project/pull/70091

>From a296eb27b2b5a2012c7f5ead2f2b9fb80511f496 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Tue, 24 Oct 2023 11:50:29 -0700
Subject: [PATCH 1/4] [RISCV][GlobalISel] Select G_GLOBAL_VALUE

G_GLOBAL_VALUE should be lowered into an absolute address if `-codemodel=small`
is used or into a PC-relative if `-codemodel=medium` is used.

PR #68380 tried to create special instructions to do this, but I don't
see why we need to do that.
---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 66 +++++++++++++++++++
 .../instruction-select/global-value.mir       | 38 +++++++++++
 2 files changed, 104 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index a7f18c04a190790..43da613a65dd60e 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -63,6 +63,8 @@ class RISCVInstructionSelector : public InstructionSelector {
   bool selectCopy(MachineInstr &MI, MachineRegisterInfo &MRI) const;
   bool selectConstant(MachineInstr &MI, MachineIRBuilder &MIB,
                       MachineRegisterInfo &MRI) const;
+  bool selectGlobalValue(MachineInstr &MI, MachineIRBuilder &MIB,
+                         MachineRegisterInfo &MRI) const;
   bool selectSExtInreg(MachineInstr &MI, MachineIRBuilder &MIB) const;
   bool selectSelect(MachineInstr &MI, MachineIRBuilder &MIB,
                     MachineRegisterInfo &MRI) const;
@@ -95,6 +97,7 @@ class RISCVInstructionSelector : public InstructionSelector {
   const RISCVInstrInfo &TII;
   const RISCVRegisterInfo &TRI;
   const RISCVRegisterBankInfo &RBI;
+  const RISCVTargetMachine &TM;
 
   // FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel
   // uses "STI." in the code generated by TableGen. We need to unify the name of
@@ -120,6 +123,7 @@ RISCVInstructionSelector::RISCVInstructionSelector(
     const RISCVTargetMachine &TM, const RISCVSubtarget &STI,
     const RISCVRegisterBankInfo &RBI)
     : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI),
+      TM(TM),
 
 #define GET_GLOBALISEL_PREDICATES_INIT
 #include "RISCVGenGlobalISel.inc"
@@ -302,6 +306,8 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
     return selectCopy(MI, MRI);
   case TargetOpcode::G_CONSTANT:
     return selectConstant(MI, MIB, MRI);
+  case TargetOpcode::G_GLOBAL_VALUE:
+    return selectGlobalValue(MI, MIB, MRI);
   case TargetOpcode::G_BRCOND: {
     // TODO: Fold with G_ICMP.
     auto Bcc =
@@ -483,6 +489,66 @@ bool RISCVInstructionSelector::selectConstant(MachineInstr &MI,
   return true;
 }
 
+bool RISCVInstructionSelector::selectGlobalValue(
+    MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
+  assert(MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
+         "Expected G_GLOBAL_VALUE");
+  auto GV = MI.getOperand(1).getGlobal();
+  if (GV->isThreadLocal()) {
+    // TODO: implement this case.
+    return false;
+  }
+
+  switch (TM.getCodeModel()) {
+  default:
+    report_fatal_error("Unsupported code model for lowering");
+  case CodeModel::Small: {
+    // Must lie within a single 2 GiB address range and must lie between
+    // absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi
+    // (lui %hi(sym)) %lo(sym)).
+    Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+    MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI)
+                               .addDef(AddrHiDest)
+                               .addGlobalAddress(GV, RISCVII::MO_HI);
+    if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
+      return false;
+
+    Register DstReg = MI.getOperand(0).getReg();
+    MachineInstr *Result = MIB.buildInstr(RISCV::ADDI)
+                               .addDef(DstReg)
+                               .addReg(AddrHiDest)
+                               .addGlobalAddress(GV, 0, RISCVII::MO_LO);
+    if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
+      return false;
+
+    MI.eraseFromParent();
+    return true;
+  }
+  case CodeModel::Medium: {
+    // Must lie within *any* 2GiB range. The generates (addi (auipc
+    // %pcrel_hi(sym)) %pcrel_lo(auipc)).
+    Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+    MachineInstr *AddrHi = MIB.buildInstr(RISCV::AUIPC)
+                               .addDef(AddrHiDest)
+                               .addGlobalAddress(GV, RISCVII::MO_PCREL_HI);
+    if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
+      return false;
+
+    Register DstReg = MI.getOperand(0).getReg();
+    MachineInstr *Result = MIB.buildInstr(RISCV::ADDI)
+                               .addDef(DstReg)
+                               .addReg(AddrHiDest)
+                               .addGlobalAddress(GV, 0, RISCVII::MO_PCREL_LO);
+    if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
+      return false;
+
+    MI.eraseFromParent();
+    return true;
+  }
+  }
+  return false;
+}
+
 bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,
                                                MachineIRBuilder &MIB) const {
   if (!STI.isRV64())
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
new file mode 100644
index 000000000000000..0f986a82b14cf6f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
@@ -0,0 +1,38 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=small \
+# RUN:   %s -o - | FileCheck --check-prefix=RV64-SMALL %s
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=medium \
+# RUN:   %s -o - | FileCheck --check-prefix=RV64-MED %s
+
+--- |
+  @x = global i32 0, align 4
+  define ptr @global_addr() {
+  entry:
+    ret ptr @x
+  }
+...
+---
+name:            global_addr
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gprb, preferred-register: '' }
+body:             |
+  bb.1.entry:
+    ; RV64-SMALL-LABEL: name: global_addr
+    ; RV64-SMALL: [[LUI:%[0-9]+]]:gpr = LUI @x + 4
+    ; RV64-SMALL-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @x
+    ; RV64-SMALL-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-SMALL-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-MED-LABEL: name: global_addr
+    ; RV64-MED: [[AUIPC:%[0-9]+]]:gpr = AUIPC @x + 6
+    ; RV64-MED-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[AUIPC]], target-flags(riscv-pcrel-lo) @x
+    ; RV64-MED-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-MED-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = G_GLOBAL_VALUE @x
+    $x10 = COPY %0(p0)
+    PseudoRET implicit $x10
+...
+

>From e81d9cff26029dbabf7f5ce209229f4d2efe8cf3 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Tue, 24 Oct 2023 12:56:11 -0700
Subject: [PATCH 2/4] [GISel] Add support for reportGISelFailure in target
 selector

---
 .../include/llvm/CodeGen/GlobalISel/InstructionSelector.h | 8 ++++++++
 llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp         | 2 ++
 llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp  | 7 +++++--
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
index 1662136cfa94afb..8331cb58a0991a4 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
@@ -31,6 +31,14 @@ class InstructionSelector : public GIMatchTableExecutor {
   ///     for I in all mutated/inserted instructions:
   ///       !isPreISelGenericOpcode(I.getOpcode())
   virtual bool select(MachineInstr &I) = 0;
+
+  void setTargetPassConfig(const TargetPassConfig *T) { TPC = T; }
+
+  void setRemarkEmitter(MachineOptimizationRemarkEmitter *M) { MORE = M; }
+
+protected:
+  const TargetPassConfig *TPC = nullptr;
+  MachineOptimizationRemarkEmitter *MORE = nullptr;
 };
 } // namespace llvm
 
diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
index 75f1fbc3b2d1b3c..baea773cf528e92 100644
--- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp
@@ -90,6 +90,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
 
   const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
   InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
+  ISel->setTargetPassConfig(&TPC);
 
   CodeGenOptLevel OldOptLevel = OptLevel;
   auto RestoreOptLevel = make_scope_exit([=]() { OptLevel = OldOptLevel; });
@@ -109,6 +110,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
 
   // An optimization remark emitter. Used to report failures.
   MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
+  ISel->setRemarkEmitter(&MORE);
 
   // FIXME: There are many other MF/MFI fields we need to initialize.
 
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 43da613a65dd60e..34d2eba499feb63 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -500,8 +500,11 @@ bool RISCVInstructionSelector::selectGlobalValue(
   }
 
   switch (TM.getCodeModel()) {
-  default:
-    report_fatal_error("Unsupported code model for lowering");
+  default: {
+    reportGISelFailure(const_cast<MachineFunction &>(*MF), *TPC, *MORE,
+                       getName(), "Unsupported code model for lowering", MI);
+    return false;
+  }
   case CodeModel::Small: {
     // Must lie within a single 2 GiB address range and must lie between
     // absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi

>From 96ce233fb29a30ea1b0882b3e54995c784295229 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Tue, 24 Oct 2023 13:17:33 -0700
Subject: [PATCH 3/4] Add support for PIE/PIC

---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 35 ++++++++++++-------
 .../instruction-select/global-value.mir       | 33 +++++++++++++++--
 2 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 34d2eba499feb63..60a7791fcf45215 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -528,20 +528,29 @@ bool RISCVInstructionSelector::selectGlobalValue(
     return true;
   }
   case CodeModel::Medium: {
-    // Must lie within *any* 2GiB range. The generates (addi (auipc
-    // %pcrel_hi(sym)) %pcrel_lo(auipc)).
-    Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
-    MachineInstr *AddrHi = MIB.buildInstr(RISCV::AUIPC)
-                               .addDef(AddrHiDest)
-                               .addGlobalAddress(GV, RISCVII::MO_PCREL_HI);
-    if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
-      return false;
-
     Register DstReg = MI.getOperand(0).getReg();
-    MachineInstr *Result = MIB.buildInstr(RISCV::ADDI)
-                               .addDef(DstReg)
-                               .addReg(AddrHiDest)
-                               .addGlobalAddress(GV, 0, RISCVII::MO_PCREL_LO);
+    MachineInstr *Result = nullptr;
+
+    // Emit LGA/LLA instead of the sequence it expands to because the pcrel_lo
+    // relocation needs to reference a label that points to the auipc
+    // instruction itself, not the global. This cannot be done inside the
+    // instruction selector.
+    if (GV->hasExternalWeakLinkage())
+      // An extern weak symbol may be undefined, i.e. have value 0, which may
+      // not be within 2GiB of PC, so use GOT-indirect addressing to access the
+      // symbol. This generates the pattern (PseudoLGA sym), which expands to
+      // (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))).
+      Result = MIB.buildInstr(RISCV::PseudoLGA)
+                   .addDef(DstReg)
+                   .addGlobalAddress(GV, 0);
+    else
+      // Generate a sequence for accessing addresses within any 2GiB range
+      // within the address space. This generates the pattern (PseudoLLA sym),
+      // which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
+      Result = MIB.buildInstr(RISCV::PseudoLLA)
+                   .addDef(DstReg)
+                   .addGlobalAddress(GV, 0);
+
     if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
       return false;
 
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
index 0f986a82b14cf6f..9e725e0764289ee 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
@@ -10,6 +10,11 @@
   entry:
     ret ptr @x
   }
+  @y = external global i32, align 4
+  define ptr @extern_global_addr() {
+  entry:
+    ret ptr @y
+  }
 ...
 ---
 name:            global_addr
@@ -27,12 +32,34 @@ body:             |
     ; RV64-SMALL-NEXT: PseudoRET implicit $x10
     ;
     ; RV64-MED-LABEL: name: global_addr
-    ; RV64-MED: [[AUIPC:%[0-9]+]]:gpr = AUIPC @x + 6
-    ; RV64-MED-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[AUIPC]], target-flags(riscv-pcrel-lo) @x
-    ; RV64-MED-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-MED: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @x
+    ; RV64-MED-NEXT: $x10 = COPY [[PseudoLLA]]
     ; RV64-MED-NEXT: PseudoRET implicit $x10
     %0:gprb(p0) = G_GLOBAL_VALUE @x
     $x10 = COPY %0(p0)
     PseudoRET implicit $x10
 ...
+---
+name:            extern_global_addr
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gprb, preferred-register: '' }
+body:             |
+  bb.1.entry:
+    ; RV64-SMALL-LABEL: name: extern_global_addr
+    ; RV64-SMALL: [[LUI:%[0-9]+]]:gpr = LUI @y + 4
+    ; RV64-SMALL-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @y
+    ; RV64-SMALL-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-SMALL-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-MED-LABEL: name: extern_global_addr
+    ; RV64-MED: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @y
+    ; RV64-MED-NEXT: $x10 = COPY [[PseudoLLA]]
+    ; RV64-MED-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = G_GLOBAL_VALUE @y
+    $x10 = COPY %0(p0)
+    PseudoRET implicit $x10
+...
 

>From 7f2db7d46e45956faf4652dc0cd01281c6b8e652 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Tue, 24 Oct 2023 14:37:34 -0700
Subject: [PATCH 4/4] Really handle PIE, dso_local, and tagged globals

---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  |  90 ++++++++++----
 .../instruction-select/global-value.mir       | 116 +++++++++++++++---
 2 files changed, 168 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 60a7791fcf45215..fa142a4dea68d6e 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -493,7 +493,8 @@ bool RISCVInstructionSelector::selectGlobalValue(
     MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
   assert(MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
          "Expected G_GLOBAL_VALUE");
-  auto GV = MI.getOperand(1).getGlobal();
+
+  auto *GV = MI.getOperand(1).getGlobal();
   if (GV->isThreadLocal()) {
     // TODO: implement this case.
     return false;
@@ -506,21 +507,58 @@ bool RISCVInstructionSelector::selectGlobalValue(
     return false;
   }
   case CodeModel::Small: {
-    // Must lie within a single 2 GiB address range and must lie between
-    // absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi
-    // (lui %hi(sym)) %lo(sym)).
-    Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
-    MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI)
-                               .addDef(AddrHiDest)
-                               .addGlobalAddress(GV, RISCVII::MO_HI);
-    if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
-      return false;
+    Register DefReg = MI.getOperand(0).getReg();
+    const LLT DefTy = MRI.getType(DefReg);
+    MachineInstr *Result = nullptr;
+
+    // When HWASAN is used and tagging of global variables is enabled
+    // they should be accessed via the GOT, since the tagged address of a global
+    // is incompatible with existing code models. This also applies to non-pic
+    // mode.
+    if (TM.isPositionIndependent() && GV->isDSOLocal() &&
+        !Subtarget->allowTaggedGlobals()) {
+      // Use PC-relative addressing to access the symbol. This generates the
+      // pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym))
+      // %pcrel_lo(auipc)).
+      Result = MIB.buildInstr(RISCV::PseudoLLA)
+                   .addDef(DefReg)
+                   .addGlobalAddress(GV, 0);
+    } else if (Subtarget->allowTaggedGlobals() ||
+               (TM.isPositionIndependent() && !GV->isDSOLocal())) {
+      // Use PC-relative addressing to access the GOT for this symbol, then
+      // load the address from the GOT. This generates the pattern (PseudoLGA
+      // sym), which expands to (ld (addi (auipc %got_pcrel_hi(sym))
+      // %pcrel_lo(auipc))).
+      MachineFunction &MF = *MI.getParent()->getParent();
+      MachineMemOperand *MemOp =
+          MI.getParent()->getParent()->getMachineMemOperand(
+              MachinePointerInfo::getGOT(MF),
+              MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
+                  MachineMemOperand::MOInvariant,
+              DefTy, Align(DefTy.getSizeInBits() / 8));
+
+      Result = MIB.buildInstr(RISCV::PseudoLGA)
+                   .addDef(DefReg)
+                   .addGlobalAddress(GV, 0)
+                   .addMemOperand(MemOp);
+    } else {
+      // Must lie within a single 2 GiB address range and must lie between
+      // absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi
+      // (lui %hi(sym)) %lo(sym)).
+      Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+      MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI)
+                                 .addDef(AddrHiDest)
+                                 .addGlobalAddress(GV, RISCVII::MO_HI);
+
+      if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
+        return false;
+
+      Result = MIB.buildInstr(RISCV::ADDI)
+                   .addDef(DefReg)
+                   .addReg(AddrHiDest)
+                   .addGlobalAddress(GV, 0, RISCVII::MO_LO);
+    }
 
-    Register DstReg = MI.getOperand(0).getReg();
-    MachineInstr *Result = MIB.buildInstr(RISCV::ADDI)
-                               .addDef(DstReg)
-                               .addReg(AddrHiDest)
-                               .addGlobalAddress(GV, 0, RISCVII::MO_LO);
     if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
       return false;
 
@@ -528,28 +566,38 @@ bool RISCVInstructionSelector::selectGlobalValue(
     return true;
   }
   case CodeModel::Medium: {
-    Register DstReg = MI.getOperand(0).getReg();
+    Register DefReg = MI.getOperand(0).getReg();
+    const LLT DefTy = MRI.getType(DefReg);
     MachineInstr *Result = nullptr;
 
     // Emit LGA/LLA instead of the sequence it expands to because the pcrel_lo
     // relocation needs to reference a label that points to the auipc
     // instruction itself, not the global. This cannot be done inside the
     // instruction selector.
-    if (GV->hasExternalWeakLinkage())
+    if (GV->hasExternalWeakLinkage()) {
       // An extern weak symbol may be undefined, i.e. have value 0, which may
       // not be within 2GiB of PC, so use GOT-indirect addressing to access the
       // symbol. This generates the pattern (PseudoLGA sym), which expands to
       // (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))).
+      MachineFunction &MF = *MI.getParent()->getParent();
+      MachineMemOperand *MemOp = MF.getMachineMemOperand(
+        MachinePointerInfo::getGOT(MF),
+        MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
+            MachineMemOperand::MOInvariant,
+        DefTy, Align(DefTy.getSizeInBits() / 8));
+
       Result = MIB.buildInstr(RISCV::PseudoLGA)
-                   .addDef(DstReg)
-                   .addGlobalAddress(GV, 0);
-    else
+                   .addDef(DefReg)
+                   .addGlobalAddress(GV, 0)
+                   .addMemOperand(MemOp);
+    } else {
       // Generate a sequence for accessing addresses within any 2GiB range
       // within the address space. This generates the pattern (PseudoLLA sym),
       // which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
       Result = MIB.buildInstr(RISCV::PseudoLLA)
-                   .addDef(DstReg)
+                   .addDef(DefReg)
                    .addGlobalAddress(GV, 0);
+    }
 
     if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
       return false;
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
index 9e725e0764289ee..07329eb0453919e 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/global-value.mir
@@ -1,6 +1,15 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
 # RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=small \
-# RUN:   %s -o - | FileCheck --check-prefix=RV64-SMALL %s
+# RUN:   %s -o - | FileCheck --check-prefix=RV64-SMALL-NOPIE-NOTAG %s
+
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=small \
+# RUN:   -mattr=+tagged-globals %s -o - | FileCheck --check-prefix=RV64-SMALL-TAGGED %s
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=small \
+# RUN:   -relocation-model=pic %s -o - | FileCheck --check-prefix=RV64-SMALL-PIE %s
+
+# RUN: llc -mtriple=riscv64 -mattr=+tagged-globals -run-pass=instruction-select -code-model=small \
+# RUN:   -relocation-model=pic %s -o - | FileCheck --check-prefix=RV64-SMALL-PIEANDLOCAL %s
+
 # RUN: llc -mtriple=riscv64 -run-pass=instruction-select -code-model=medium \
 # RUN:   %s -o - | FileCheck --check-prefix=RV64-MED %s
 
@@ -10,11 +19,16 @@
   entry:
     ret ptr @x
   }
-  @y = external global i32, align 4
-  define ptr @extern_global_addr() {
+  @y = extern_weak global i32, align 4
+  define ptr @extern_weak_global_addr() {
   entry:
     ret ptr @y
   }
+  @z = dso_local global i32 0, align 4
+  define ptr @local_global_addr() {
+  entry:
+    ret ptr @z
+  }
 ...
 ---
 name:            global_addr
@@ -25,11 +39,26 @@ registers:
   - { id: 0, class: gprb, preferred-register: '' }
 body:             |
   bb.1.entry:
-    ; RV64-SMALL-LABEL: name: global_addr
-    ; RV64-SMALL: [[LUI:%[0-9]+]]:gpr = LUI @x + 4
-    ; RV64-SMALL-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @x
-    ; RV64-SMALL-NEXT: $x10 = COPY [[ADDI]]
-    ; RV64-SMALL-NEXT: PseudoRET implicit $x10
+    ; RV64-SMALL-NOPIE-NOTAG-LABEL: name: global_addr
+    ; RV64-SMALL-NOPIE-NOTAG: [[LUI:%[0-9]+]]:gpr = LUI @x + 4
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @x
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-TAGGED-LABEL: name: global_addr
+    ; RV64-SMALL-TAGGED: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @x :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-TAGGED-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-TAGGED-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIE-LABEL: name: global_addr
+    ; RV64-SMALL-PIE: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @x :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-PIE-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-PIE-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIEANDLOCAL-LABEL: name: global_addr
+    ; RV64-SMALL-PIEANDLOCAL: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @x :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: PseudoRET implicit $x10
     ;
     ; RV64-MED-LABEL: name: global_addr
     ; RV64-MED: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @x
@@ -40,7 +69,7 @@ body:             |
     PseudoRET implicit $x10
 ...
 ---
-name:            extern_global_addr
+name:            extern_weak_global_addr
 legalized:       true
 regBankSelected: true
 tracksRegLiveness: true
@@ -48,18 +77,71 @@ registers:
   - { id: 0, class: gprb, preferred-register: '' }
 body:             |
   bb.1.entry:
-    ; RV64-SMALL-LABEL: name: extern_global_addr
-    ; RV64-SMALL: [[LUI:%[0-9]+]]:gpr = LUI @y + 4
-    ; RV64-SMALL-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @y
-    ; RV64-SMALL-NEXT: $x10 = COPY [[ADDI]]
-    ; RV64-SMALL-NEXT: PseudoRET implicit $x10
+    ; RV64-SMALL-NOPIE-NOTAG-LABEL: name: extern_weak_global_addr
+    ; RV64-SMALL-NOPIE-NOTAG: [[LUI:%[0-9]+]]:gpr = LUI @y + 4
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @y
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: PseudoRET implicit $x10
     ;
-    ; RV64-MED-LABEL: name: extern_global_addr
-    ; RV64-MED: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @y
-    ; RV64-MED-NEXT: $x10 = COPY [[PseudoLLA]]
+    ; RV64-SMALL-TAGGED-LABEL: name: extern_weak_global_addr
+    ; RV64-SMALL-TAGGED: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @y :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-TAGGED-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-TAGGED-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIE-LABEL: name: extern_weak_global_addr
+    ; RV64-SMALL-PIE: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @y :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-PIE-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-PIE-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIEANDLOCAL-LABEL: name: extern_weak_global_addr
+    ; RV64-SMALL-PIEANDLOCAL: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @y :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-MED-LABEL: name: extern_weak_global_addr
+    ; RV64-MED: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @y :: (dereferenceable invariant load (p0) from got)
+    ; RV64-MED-NEXT: $x10 = COPY [[PseudoLGA]]
     ; RV64-MED-NEXT: PseudoRET implicit $x10
     %0:gprb(p0) = G_GLOBAL_VALUE @y
     $x10 = COPY %0(p0)
     PseudoRET implicit $x10
 ...
+---
+name:            local_global_addr
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gprb, preferred-register: '' }
+body:             |
+  bb.1.entry:
+    ; RV64-SMALL-NOPIE-NOTAG-LABEL: name: local_global_addr
+    ; RV64-SMALL-NOPIE-NOTAG: [[LUI:%[0-9]+]]:gpr = LUI @z + 4
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI [[LUI]], target-flags(riscv-lo) @z
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: $x10 = COPY [[ADDI]]
+    ; RV64-SMALL-NOPIE-NOTAG-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-TAGGED-LABEL: name: local_global_addr
+    ; RV64-SMALL-TAGGED: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @z :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-TAGGED-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-TAGGED-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIE-LABEL: name: local_global_addr
+    ; RV64-SMALL-PIE: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @z
+    ; RV64-SMALL-PIE-NEXT: $x10 = COPY [[PseudoLLA]]
+    ; RV64-SMALL-PIE-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-SMALL-PIEANDLOCAL-LABEL: name: local_global_addr
+    ; RV64-SMALL-PIEANDLOCAL: [[PseudoLGA:%[0-9]+]]:gpr = PseudoLGA @z :: (dereferenceable invariant load (p0) from got)
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: $x10 = COPY [[PseudoLGA]]
+    ; RV64-SMALL-PIEANDLOCAL-NEXT: PseudoRET implicit $x10
+    ;
+    ; RV64-MED-LABEL: name: local_global_addr
+    ; RV64-MED: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA @z
+    ; RV64-MED-NEXT: $x10 = COPY [[PseudoLLA]]
+    ; RV64-MED-NEXT: PseudoRET implicit $x10
+    %0:gprb(p0) = G_GLOBAL_VALUE @z
+    $x10 = COPY %0(p0)
+    PseudoRET implicit $x10
+...
 



More information about the llvm-commits mailing list