[llvm] [RFC][RISCV] Support the large code model. (PR #70308)

Jim Lin via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 26 01:51:46 PDT 2023


https://github.com/tclin914 created https://github.com/llvm/llvm-project/pull/70308

Implement large code model for GlobalAddressSDNode, BlockAddressSDNode and ExternalSymbolSDNode.

See discussion on
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/388.

co-authored by: Kuan-Lin Chen <rufus at andestech.com>

>From 5cd0e500f7ba7490bf3b854f2a2c9299bd131d9d Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen <rufus at andestech.com>
Date: Thu, 17 Sep 2020 17:09:13 +0800
Subject: [PATCH] [RFC][RISCV] Support the large code model.

Implement large code model for GlobalAddressSDNode, BlockAddressSDNode
and ExternalSymbolSDNode.

See discussion on
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/388.

co-authored by: Kuan-Lin Chen <rufus at andestech.com>
---
 llvm/lib/Target/RISCV/CMakeLists.txt          |   1 +
 llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp     |  35 ++
 .../Target/RISCV/RISCVConstantPoolValue.cpp   | 114 ++++
 .../lib/Target/RISCV/RISCVConstantPoolValue.h | 147 +++++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  76 ++-
 .../Target/RISCV/RISCVTargetObjectFile.cpp    |   2 +-
 llvm/test/CodeGen/RISCV/calls.ll              | 524 +++++++++++++++++
 llvm/test/CodeGen/RISCV/codemodel-lowering.ll | 161 +++++
 .../test/CodeGen/RISCV/fold-addi-loadstore.ll | 198 +++++++
 .../RISCV/inline-asm-mem-constraint.ll        | 553 ++++++++++++++++++
 10 files changed, 1798 insertions(+), 13 deletions(-)
 create mode 100644 llvm/lib/Target/RISCV/RISCVConstantPoolValue.cpp
 create mode 100644 llvm/lib/Target/RISCV/RISCVConstantPoolValue.h

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 4d5fa79389ea68b..b6ed0b86e39e9ba 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -29,6 +29,7 @@ add_public_tablegen_target(RISCVCommonTableGen)
 add_llvm_target(RISCVCodeGen
   RISCVAsmPrinter.cpp
   RISCVCodeGenPrepare.cpp
+  RISCVConstantPoolValue.cpp
   RISCVDeadRegisterDefinitions.cpp
   RISCVMakeCompressible.cpp
   RISCVExpandAtomicPseudoInsts.cpp
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index 0fd514fa87cd2f9..6308d1f574b4d03 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -16,6 +16,7 @@
 #include "MCTargetDesc/RISCVMCExpr.h"
 #include "MCTargetDesc/RISCVTargetStreamer.h"
 #include "RISCV.h"
+#include "RISCVConstantPoolValue.h"
 #include "RISCVMachineFunctionInfo.h"
 #include "RISCVTargetMachine.h"
 #include "TargetInfo/RISCVTargetInfo.h"
@@ -75,6 +76,8 @@ class RISCVAsmPrinter : public AsmPrinter {
 
   void emitInstruction(const MachineInstr *MI) override;
 
+  void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
+
   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                        const char *ExtraCode, raw_ostream &OS) override;
   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
@@ -981,3 +984,35 @@ bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
   }
   return false;
 }
+
+static MCSymbolRefExpr::VariantKind
+getModifierVariantKind(RISCVCP::RISCVCPModifier Modifier) {
+  switch (Modifier) {
+  case RISCVCP::None:
+    return MCSymbolRefExpr::VK_None;
+  }
+  llvm_unreachable("Invalid RISCVCPModifier!");
+}
+
+void RISCVAsmPrinter::emitMachineConstantPoolValue(
+    MachineConstantPoolValue *MCPV) {
+  auto *RCPV = static_cast<RISCVConstantPoolValue *>(MCPV);
+  MCSymbol *MCSym;
+
+  if (RCPV->isGlobalValue()) {
+    auto GV = cast<RISCVConstantPoolConstant>(RCPV)->getGlobalValue();
+    MCSym = getSymbol(GV);
+  } else if (RCPV->isBlockAddress()) {
+    auto BA = cast<RISCVConstantPoolConstant>(RCPV)->getBlockAddress();
+    MCSym = GetBlockAddressSymbol(BA);
+  } else {
+    assert(RCPV->isExtSymbol() && "unrecognized constant pool value");
+    auto Sym = cast<RISCVConstantPoolSymbol>(RCPV)->getSymbol();
+    MCSym = GetExternalSymbolSymbol(Sym);
+  }
+
+  const MCExpr *Expr = MCSymbolRefExpr::create(
+      MCSym, getModifierVariantKind(RCPV->getModifier()), OutContext);
+  uint64_t Size = getDataLayout().getTypeAllocSize(RCPV->getType());
+  OutStreamer->emitValue(Expr, Size);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVConstantPoolValue.cpp b/llvm/lib/Target/RISCV/RISCVConstantPoolValue.cpp
new file mode 100644
index 000000000000000..398dfbd9bb65948
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVConstantPoolValue.cpp
@@ -0,0 +1,114 @@
+//===------- RISCVConstantPoolValue.cpp - RISC-V constantpool value -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the RISC-V specific constantpool value class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVConstantPoolValue.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+RISCVConstantPoolValue::RISCVConstantPoolValue(
+    LLVMContext &C, RISCVCP::RISCVCPKind Kind,
+    RISCVCP::RISCVCPModifier Modifier)
+    : MachineConstantPoolValue((Type *)Type::getInt64Ty(C)), Kind(Kind),
+      Modifier(Modifier) {}
+
+RISCVConstantPoolValue::RISCVConstantPoolValue(
+    Type *Ty, RISCVCP::RISCVCPKind Kind, RISCVCP::RISCVCPModifier Modifier)
+    : MachineConstantPoolValue(Ty), Kind(Kind), Modifier(Modifier) {}
+
+int RISCVConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP,
+                                                      Align Alignment) {
+  llvm_unreachable("Shouldn't be calling this directly!");
+}
+
+StringRef RISCVConstantPoolValue::getModifierText() const {
+  switch (Modifier) {
+  case RISCVCP::None:
+    return "";
+  }
+  llvm_unreachable("Unknown modifier!");
+}
+
+void RISCVConstantPoolValue::print(raw_ostream &O) const {
+  if (hasModifier())
+    O << "@" << getModifierText();
+}
+
+RISCVConstantPoolConstant::RISCVConstantPoolConstant(Type *Ty,
+                                                     const Constant *GV,
+                                                     RISCVCP::RISCVCPKind Kind)
+    : RISCVConstantPoolValue(Ty, Kind, RISCVCP::None), CVal(GV) {}
+
+RISCVConstantPoolConstant *
+RISCVConstantPoolConstant::Create(const GlobalValue *GV,
+                                  RISCVCP::RISCVCPKind Kind) {
+  return new RISCVConstantPoolConstant(GV->getType(), GV, Kind);
+}
+
+RISCVConstantPoolConstant *
+RISCVConstantPoolConstant::Create(const Constant *C,
+                                  RISCVCP::RISCVCPKind Kind) {
+  return new RISCVConstantPoolConstant(C->getType(), C, Kind);
+}
+
+int RISCVConstantPoolConstant::getExistingMachineCPValue(
+    MachineConstantPool *CP, Align Alignment) {
+  return getExistingMachineCPValueImpl<RISCVConstantPoolConstant>(CP,
+                                                                  Alignment);
+}
+
+void RISCVConstantPoolConstant::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+  ID.AddPointer(CVal);
+}
+
+void RISCVConstantPoolConstant::print(raw_ostream &O) const {
+  O << CVal->getName();
+  RISCVConstantPoolValue::print(O);
+}
+
+const GlobalValue *RISCVConstantPoolConstant::getGlobalValue() const {
+  return dyn_cast_or_null<GlobalValue>(CVal);
+}
+
+const BlockAddress *RISCVConstantPoolConstant::getBlockAddress() const {
+  return dyn_cast_or_null<BlockAddress>(CVal);
+}
+
+RISCVConstantPoolSymbol::RISCVConstantPoolSymbol(
+    LLVMContext &C, StringRef s, RISCVCP::RISCVCPModifier Modifier)
+    : RISCVConstantPoolValue(C, RISCVCP::ExtSymbol, Modifier), S(s) {}
+
+RISCVConstantPoolSymbol *
+RISCVConstantPoolSymbol::Create(LLVMContext &C, StringRef s,
+                                RISCVCP::RISCVCPModifier Modifier) {
+  return new RISCVConstantPoolSymbol(C, s, Modifier);
+}
+
+int RISCVConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP,
+                                                       Align Alignment) {
+  return getExistingMachineCPValueImpl<RISCVConstantPoolSymbol>(CP, Alignment);
+}
+
+void RISCVConstantPoolSymbol::addSelectionDAGCSEId(FoldingSetNodeID &ID) {
+  ID.AddString(S);
+}
+
+void RISCVConstantPoolSymbol::print(raw_ostream &O) const {
+  O << S;
+  RISCVConstantPoolValue::print(O);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVConstantPoolValue.h b/llvm/lib/Target/RISCV/RISCVConstantPoolValue.h
new file mode 100644
index 000000000000000..8edd95e9a065fd7
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVConstantPoolValue.h
@@ -0,0 +1,147 @@
+//===--- RISCVConstantPoolValue.h - RISC-V constantpool value ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the RISC-V specific constantpool value class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_RISCVCONSTANTPOOLVALUE_H
+#define LLVM_LIB_TARGET_RISCV_RISCVCONSTANTPOOLVALUE_H
+
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+
+class LLVMContext;
+class GlobalValue;
+class BlockAddress;
+
+namespace RISCVCP {
+
+enum RISCVCPKind { ExtSymbol, GlobalValue, BlockAddress };
+
+enum RISCVCPModifier {
+  None,
+};
+} // end namespace RISCVCP
+
+/// A RISCV-specific constant pool value.
+class RISCVConstantPoolValue : public MachineConstantPoolValue {
+  RISCVCP::RISCVCPKind Kind;
+  RISCVCP::RISCVCPModifier Modifier;
+
+protected:
+  RISCVConstantPoolValue(LLVMContext &C, RISCVCP::RISCVCPKind Kind,
+                         RISCVCP::RISCVCPModifier Modifier);
+
+  RISCVConstantPoolValue(Type *Ty, RISCVCP::RISCVCPKind Kind,
+                         RISCVCP::RISCVCPModifier Modifier);
+
+  template <typename Derived>
+  int getExistingMachineCPValueImpl(MachineConstantPool *CP, Align Alignment) {
+    const std::vector<MachineConstantPoolEntry> &Constants = CP->getConstants();
+    for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
+      if (Constants[i].isMachineConstantPoolEntry() &&
+          Constants[i].getAlign() >= Alignment) {
+        auto *CPV = static_cast<RISCVConstantPoolValue *>(
+            Constants[i].Val.MachineCPVal);
+        if (Derived *APC = dyn_cast<Derived>(CPV))
+          if (cast<Derived>(this)->equals(APC))
+            return i;
+      }
+    }
+
+    return -1;
+  }
+
+public:
+  ~RISCVConstantPoolValue() = default;
+
+  RISCVCP::RISCVCPModifier getModifier() const { return Modifier; }
+  StringRef getModifierText() const;
+  bool hasModifier() const { return Modifier != RISCVCP::None; }
+
+  bool isExtSymbol() const { return Kind == RISCVCP::ExtSymbol; }
+  bool isGlobalValue() const { return Kind == RISCVCP::GlobalValue; }
+  bool isBlockAddress() const { return Kind == RISCVCP::BlockAddress; }
+
+  int getExistingMachineCPValue(MachineConstantPool *CP,
+                                Align Alignment) override;
+
+  void addSelectionDAGCSEId(FoldingSetNodeID &ID) override {}
+
+  bool equals(const RISCVConstantPoolValue *A) const {
+    return this->Modifier == A->Modifier;
+  }
+
+  void print(raw_ostream &O) const override;
+};
+
+class RISCVConstantPoolConstant : public RISCVConstantPoolValue {
+  const Constant *CVal;
+
+  RISCVConstantPoolConstant(Type *Ty, const Constant *GV,
+                            RISCVCP::RISCVCPKind Kind);
+
+public:
+  static RISCVConstantPoolConstant *Create(const GlobalValue *GV,
+                                           RISCVCP::RISCVCPKind Kind);
+  static RISCVConstantPoolConstant *Create(const Constant *C,
+                                           RISCVCP::RISCVCPKind Kind);
+
+  const GlobalValue *getGlobalValue() const;
+  const BlockAddress *getBlockAddress() const;
+
+  int getExistingMachineCPValue(MachineConstantPool *CP,
+                                Align Alignment) override;
+
+  void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+  void print(raw_ostream &O) const override;
+
+  bool equals(const RISCVConstantPoolConstant *A) const {
+    return CVal == A->CVal && RISCVConstantPoolValue::equals(A);
+  }
+
+  static bool classof(const RISCVConstantPoolValue *RCPV) {
+    return RCPV->isGlobalValue() || RCPV->isBlockAddress();
+  }
+};
+
+class RISCVConstantPoolSymbol : public RISCVConstantPoolValue {
+  const std::string S;
+
+  RISCVConstantPoolSymbol(LLVMContext &C, StringRef s,
+                          RISCVCP::RISCVCPModifier Modifier);
+
+public:
+  static RISCVConstantPoolSymbol *Create(LLVMContext &C, StringRef s,
+                                         RISCVCP ::RISCVCPModifier Modifier);
+
+  std::string getSymbol() const { return S; }
+
+  int getExistingMachineCPValue(MachineConstantPool *CP,
+                                Align Alignment) override;
+
+  void addSelectionDAGCSEId(FoldingSetNodeID &ID) override;
+
+  void print(raw_ostream &O) const override;
+
+  bool equals(const RISCVConstantPoolSymbol *A) const {
+    return S == A->S && RISCVConstantPoolValue::equals(A);
+  }
+  static bool classof(const RISCVConstantPoolValue *RCPV) {
+    return RCPV->isExtSymbol();
+  }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index beb371063f89b2d..e523995a909f599 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -14,6 +14,7 @@
 #include "RISCVISelLowering.h"
 #include "MCTargetDesc/RISCVMatInt.h"
 #include "RISCV.h"
+#include "RISCVConstantPoolValue.h"
 #include "RISCVMachineFunctionInfo.h"
 #include "RISCVRegisterInfo.h"
 #include "RISCVSubtarget.h"
@@ -6431,6 +6432,44 @@ static SDValue getTargetNode(JumpTableSDNode *N, const SDLoc &DL, EVT Ty,
   return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
 }
 
+static SDValue getTargetNode(ExternalSymbolSDNode *N, SDLoc DL, EVT Ty,
+                             SelectionDAG &DAG, unsigned Flags) {
+  llvm_unreachable("Unexpected node type.");
+}
+
+template <class NodeTy>
+static SDValue getLargeAddr(NodeTy *N, SDLoc DL, EVT Ty, SelectionDAG &DAG) {
+  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N)) {
+    RISCVConstantPoolConstant *CPV =
+        RISCVConstantPoolConstant::Create(G->getGlobal(), RISCVCP::GlobalValue);
+    SDValue CPAddr = DAG.getTargetConstantPool(CPV, Ty, Align(8));
+    SDValue LC = DAG.getNode(RISCVISD::LLA, DL, Ty, CPAddr);
+    return DAG.getLoad(
+        Ty, DL, DAG.getEntryNode(), LC,
+        MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+  } else if (BlockAddressSDNode *B = dyn_cast<BlockAddressSDNode>(N)) {
+    RISCVConstantPoolConstant *CPV = RISCVConstantPoolConstant::Create(
+        B->getBlockAddress(), RISCVCP::BlockAddress);
+    SDValue CPAddr = DAG.getTargetConstantPool(CPV, Ty, Align(8));
+    SDValue LC = DAG.getNode(RISCVISD::LLA, DL, Ty, CPAddr);
+    return DAG.getLoad(
+        Ty, DL, DAG.getEntryNode(), LC,
+        MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+  } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(N)) {
+    RISCVConstantPoolSymbol *CPV = RISCVConstantPoolSymbol::Create(
+        *DAG.getContext(), S->getSymbol(), RISCVCP::None);
+    SDValue CPAddr = DAG.getTargetConstantPool(CPV, Ty, Align(8));
+    SDValue LC = DAG.getNode(RISCVISD::LLA, DL, Ty, CPAddr);
+    return DAG.getLoad(
+        Ty, DL, DAG.getEntryNode(), LC,
+        MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+  } else {
+    // Using pc-relative mode for other node type.
+    SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
+    return DAG.getNode(RISCVISD::LLA, DL, Ty, Addr);
+  }
+}
+
 template <class NodeTy>
 SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
                                      bool IsLocal, bool IsExternWeak) const {
@@ -6499,6 +6538,9 @@ SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
     // expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
     return DAG.getNode(RISCVISD::LLA, DL, Ty, Addr);
   }
+  case CodeModel::Large: {
+    return getLargeAddr(N, DL, Ty, DAG);
+  }
   }
 }
 
@@ -17489,22 +17531,32 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
   // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
   // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
   // split it and then direct call can be matched by PseudoCALL.
-  if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
-    const GlobalValue *GV = S->getGlobal();
+  if (getTargetMachine().getCodeModel() == CodeModel::Large) {
+    if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
+      Callee = getLargeAddr(S, DL, getPointerTy(DAG.getDataLayout()), DAG);
+    } else if (ExternalSymbolSDNode *S =
+                   dyn_cast<ExternalSymbolSDNode>(Callee)) {
+      Callee = getLargeAddr(S, DL, getPointerTy(DAG.getDataLayout()), DAG);
+    }
+  } else {
+    if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
+      const GlobalValue *GV = S->getGlobal();
+      unsigned OpFlags = RISCVII::MO_CALL;
 
-    unsigned OpFlags = RISCVII::MO_CALL;
-    if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV))
-      OpFlags = RISCVII::MO_PLT;
+      if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV))
+        OpFlags = RISCVII::MO_PLT;
 
-    Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags);
-  } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
-    unsigned OpFlags = RISCVII::MO_CALL;
+      Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags);
+    } else if (ExternalSymbolSDNode *S =
+                   dyn_cast<ExternalSymbolSDNode>(Callee)) {
+      unsigned OpFlags = RISCVII::MO_CALL;
 
-    if (!getTargetMachine().shouldAssumeDSOLocal(*MF.getFunction().getParent(),
-                                                 nullptr))
-      OpFlags = RISCVII::MO_PLT;
+      if (!getTargetMachine().shouldAssumeDSOLocal(
+              *MF.getFunction().getParent(), nullptr))
+        OpFlags = RISCVII::MO_PLT;
 
-    Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
+      Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
+    }
   }
 
   // The first call operand is the chain and the second is the target address.
diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
index 7c9e57e6eef3ced..ea9ab37ae415ce6 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
@@ -114,7 +114,7 @@ bool RISCVELFTargetObjectFile::isConstantInSmallSection(
 MCSection *RISCVELFTargetObjectFile::getSectionForConstant(
     const DataLayout &DL, SectionKind Kind, const Constant *C,
     Align &Alignment) const {
-  if (isConstantInSmallSection(DL, C))
+  if (C && isConstantInSmallSection(DL, C))
     return SmallDataSection;
 
   // Otherwise, we work the same as ELF.
diff --git a/llvm/test/CodeGen/RISCV/calls.ll b/llvm/test/CodeGen/RISCV/calls.ll
index e3459875362d45d..509daaa2970cd20 100644
--- a/llvm/test/CodeGen/RISCV/calls.ll
+++ b/llvm/test/CodeGen/RISCV/calls.ll
@@ -3,6 +3,14 @@
 ; RUN:   | FileCheck -check-prefix=RV32I %s
 ; RUN: llc -relocation-model=pic -mtriple=riscv32 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV32I-PIC %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -code-model=small -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I-SMALL %s
+; RUN: llc -code-model=medium -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I-MEDIUM %s
+; RUN: llc -code-model=large -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I-LARGE %s
 
 declare i32 @external_function(i32)
 
@@ -24,6 +32,45 @@ define i32 @test_call_external(i32 %a) nounwind {
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_external:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    call external_function at plt
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_external:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    call external_function at plt
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_external:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    call external_function at plt
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_external:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:  .Lpcrel_hi0:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI0_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi0)(a1)
+; RV64I-LARGE-NEXT:    jalr a1
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 @external_function(i32 %a)
   ret i32 %1
 }
@@ -48,6 +95,45 @@ define i32 @test_call_dso_local(i32 %a) nounwind {
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_dso_local:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    call dso_local_function
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_dso_local:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    call dso_local_function
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_dso_local:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    call dso_local_function
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_dso_local:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:  .Lpcrel_hi1:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI1_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi1)(a1)
+; RV64I-LARGE-NEXT:    jalr a1
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 @dso_local_function(i32 %a)
   ret i32 %1
 }
@@ -62,6 +148,26 @@ define i32 @defined_function(i32 %a) nounwind {
 ; RV32I-PIC:       # %bb.0:
 ; RV32I-PIC-NEXT:    addi a0, a0, 1
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: defined_function:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addiw a0, a0, 1
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: defined_function:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addiw a0, a0, 1
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: defined_function:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addiw a0, a0, 1
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: defined_function:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addiw a0, a0, 1
+; RV64I-LARGE-NEXT:    ret
   %1 = add i32 %a, 1
   ret i32 %1
 }
@@ -84,6 +190,45 @@ define i32 @test_call_defined(i32 %a) nounwind {
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_defined:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    call defined_function at plt
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_defined:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    call defined_function at plt
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_defined:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    call defined_function at plt
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_defined:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:  .Lpcrel_hi2:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI3_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi2)(a1)
+; RV64I-LARGE-NEXT:    jalr a1
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 @defined_function(i32 %a)
   ret i32 %1
 }
@@ -110,6 +255,50 @@ define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_indirect:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    mv a2, a0
+; RV64I-NEXT:    mv a0, a1
+; RV64I-NEXT:    jalr a2
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_indirect:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    mv a2, a0
+; RV64I-SMALL-NEXT:    mv a0, a1
+; RV64I-SMALL-NEXT:    jalr a2
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_indirect:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    mv a2, a0
+; RV64I-MEDIUM-NEXT:    mv a0, a1
+; RV64I-MEDIUM-NEXT:    jalr a2
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_indirect:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    mv a2, a0
+; RV64I-LARGE-NEXT:    mv a0, a1
+; RV64I-LARGE-NEXT:    jalr a2
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 %a(i32 %b)
   ret i32 %1
 }
@@ -150,6 +339,74 @@ define i32 @test_call_indirect_no_t0(ptr %a, i32 %b, i32 %c, i32 %d, i32 %e, i32
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_indirect_no_t0:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    mv t1, a0
+; RV64I-NEXT:    mv a0, a1
+; RV64I-NEXT:    mv a1, a2
+; RV64I-NEXT:    mv a2, a3
+; RV64I-NEXT:    mv a3, a4
+; RV64I-NEXT:    mv a4, a5
+; RV64I-NEXT:    mv a5, a6
+; RV64I-NEXT:    mv a6, a7
+; RV64I-NEXT:    jalr t1
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_indirect_no_t0:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    mv t1, a0
+; RV64I-SMALL-NEXT:    mv a0, a1
+; RV64I-SMALL-NEXT:    mv a1, a2
+; RV64I-SMALL-NEXT:    mv a2, a3
+; RV64I-SMALL-NEXT:    mv a3, a4
+; RV64I-SMALL-NEXT:    mv a4, a5
+; RV64I-SMALL-NEXT:    mv a5, a6
+; RV64I-SMALL-NEXT:    mv a6, a7
+; RV64I-SMALL-NEXT:    jalr t1
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_indirect_no_t0:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    mv t1, a0
+; RV64I-MEDIUM-NEXT:    mv a0, a1
+; RV64I-MEDIUM-NEXT:    mv a1, a2
+; RV64I-MEDIUM-NEXT:    mv a2, a3
+; RV64I-MEDIUM-NEXT:    mv a3, a4
+; RV64I-MEDIUM-NEXT:    mv a4, a5
+; RV64I-MEDIUM-NEXT:    mv a5, a6
+; RV64I-MEDIUM-NEXT:    mv a6, a7
+; RV64I-MEDIUM-NEXT:    jalr t1
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_indirect_no_t0:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    mv t1, a0
+; RV64I-LARGE-NEXT:    mv a0, a1
+; RV64I-LARGE-NEXT:    mv a1, a2
+; RV64I-LARGE-NEXT:    mv a2, a3
+; RV64I-LARGE-NEXT:    mv a3, a4
+; RV64I-LARGE-NEXT:    mv a4, a5
+; RV64I-LARGE-NEXT:    mv a5, a6
+; RV64I-LARGE-NEXT:    mv a6, a7
+; RV64I-LARGE-NEXT:    jalr t1
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 %a(i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
   ret i32 %1
 }
@@ -167,6 +424,26 @@ define fastcc i32 @fastcc_function(i32 %a, i32 %b) nounwind {
 ; RV32I-PIC:       # %bb.0:
 ; RV32I-PIC-NEXT:    add a0, a0, a1
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: fastcc_function:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addw a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: fastcc_function:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addw a0, a0, a1
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: fastcc_function:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addw a0, a0, a1
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: fastcc_function:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addw a0, a0, a1
+; RV64I-LARGE-NEXT:    ret
  %1 = add i32 %a, %b
  ret i32 %1
 }
@@ -197,6 +474,62 @@ define i32 @test_call_fastcc(i32 %a, i32 %b) nounwind {
 ; RV32I-PIC-NEXT:    lw s0, 8(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_fastcc:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    mv s0, a0
+; RV64I-NEXT:    call fastcc_function at plt
+; RV64I-NEXT:    mv a0, s0
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_fastcc:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    mv s0, a0
+; RV64I-SMALL-NEXT:    call fastcc_function at plt
+; RV64I-SMALL-NEXT:    mv a0, s0
+; RV64I-SMALL-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_fastcc:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    mv s0, a0
+; RV64I-MEDIUM-NEXT:    call fastcc_function at plt
+; RV64I-MEDIUM-NEXT:    mv a0, s0
+; RV64I-MEDIUM-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_fastcc:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    mv s0, a0
+; RV64I-LARGE-NEXT:  .Lpcrel_hi3:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
+; RV64I-LARGE-NEXT:    ld a2, %pcrel_lo(.Lpcrel_hi3)(a0)
+; RV64I-LARGE-NEXT:    mv a0, s0
+; RV64I-LARGE-NEXT:    jalr a2
+; RV64I-LARGE-NEXT:    mv a0, s0
+; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
   %1 = call fastcc i32 @fastcc_function(i32 %a, i32 %b)
   ret i32 %a
 }
@@ -247,6 +580,98 @@ define i32 @test_call_external_many_args(i32 %a) nounwind {
 ; RV32I-PIC-NEXT:    lw s0, 8(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_external_many_args:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -32
+; RV64I-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    mv s0, a0
+; RV64I-NEXT:    sd a0, 8(sp)
+; RV64I-NEXT:    sd a0, 0(sp)
+; RV64I-NEXT:    mv a1, a0
+; RV64I-NEXT:    mv a2, a0
+; RV64I-NEXT:    mv a3, a0
+; RV64I-NEXT:    mv a4, a0
+; RV64I-NEXT:    mv a5, a0
+; RV64I-NEXT:    mv a6, a0
+; RV64I-NEXT:    mv a7, a0
+; RV64I-NEXT:    call external_many_args at plt
+; RV64I-NEXT:    mv a0, s0
+; RV64I-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 32
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_external_many_args:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -32
+; RV64I-SMALL-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    mv s0, a0
+; RV64I-SMALL-NEXT:    sd a0, 8(sp)
+; RV64I-SMALL-NEXT:    sd a0, 0(sp)
+; RV64I-SMALL-NEXT:    mv a1, a0
+; RV64I-SMALL-NEXT:    mv a2, a0
+; RV64I-SMALL-NEXT:    mv a3, a0
+; RV64I-SMALL-NEXT:    mv a4, a0
+; RV64I-SMALL-NEXT:    mv a5, a0
+; RV64I-SMALL-NEXT:    mv a6, a0
+; RV64I-SMALL-NEXT:    mv a7, a0
+; RV64I-SMALL-NEXT:    call external_many_args at plt
+; RV64I-SMALL-NEXT:    mv a0, s0
+; RV64I-SMALL-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 32
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_external_many_args:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -32
+; RV64I-MEDIUM-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    mv s0, a0
+; RV64I-MEDIUM-NEXT:    sd a0, 8(sp)
+; RV64I-MEDIUM-NEXT:    sd a0, 0(sp)
+; RV64I-MEDIUM-NEXT:    mv a1, a0
+; RV64I-MEDIUM-NEXT:    mv a2, a0
+; RV64I-MEDIUM-NEXT:    mv a3, a0
+; RV64I-MEDIUM-NEXT:    mv a4, a0
+; RV64I-MEDIUM-NEXT:    mv a5, a0
+; RV64I-MEDIUM-NEXT:    mv a6, a0
+; RV64I-MEDIUM-NEXT:    mv a7, a0
+; RV64I-MEDIUM-NEXT:    call external_many_args at plt
+; RV64I-MEDIUM-NEXT:    mv a0, s0
+; RV64I-MEDIUM-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 32
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_external_many_args:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -32
+; RV64I-LARGE-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    mv s0, a0
+; RV64I-LARGE-NEXT:  .Lpcrel_hi4:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
+; RV64I-LARGE-NEXT:    ld t1, %pcrel_lo(.Lpcrel_hi4)(a0)
+; RV64I-LARGE-NEXT:    sd s0, 8(sp)
+; RV64I-LARGE-NEXT:    sd s0, 0(sp)
+; RV64I-LARGE-NEXT:    mv a0, s0
+; RV64I-LARGE-NEXT:    mv a1, s0
+; RV64I-LARGE-NEXT:    mv a2, s0
+; RV64I-LARGE-NEXT:    mv a3, s0
+; RV64I-LARGE-NEXT:    mv a4, s0
+; RV64I-LARGE-NEXT:    mv a5, s0
+; RV64I-LARGE-NEXT:    mv a6, s0
+; RV64I-LARGE-NEXT:    mv a7, s0
+; RV64I-LARGE-NEXT:    jalr t1
+; RV64I-LARGE-NEXT:    mv a0, s0
+; RV64I-LARGE-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 32
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 @external_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
                                     i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
   ret i32 %a
@@ -264,6 +689,30 @@ define i32 @defined_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 %
 ; RV32I-PIC-NEXT:    lw a0, 4(sp)
 ; RV32I-PIC-NEXT:    addi a0, a0, 1
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: defined_many_args:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    lw a0, 8(sp)
+; RV64I-NEXT:    addiw a0, a0, 1
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: defined_many_args:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    lw a0, 8(sp)
+; RV64I-SMALL-NEXT:    addiw a0, a0, 1
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: defined_many_args:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    lw a0, 8(sp)
+; RV64I-MEDIUM-NEXT:    addiw a0, a0, 1
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: defined_many_args:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    lw a0, 8(sp)
+; RV64I-LARGE-NEXT:    addiw a0, a0, 1
+; RV64I-LARGE-NEXT:    ret
   %added = add i32 %j, 1
   ret i32 %added
 }
@@ -304,6 +753,81 @@ define i32 @test_call_defined_many_args(i32 %a) nounwind {
 ; RV32I-PIC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; RV32I-PIC-NEXT:    addi sp, sp, 16
 ; RV32I-PIC-NEXT:    ret
+;
+; RV64I-LABEL: test_call_defined_many_args:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -32
+; RV64I-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    sd a0, 8(sp)
+; RV64I-NEXT:    sd a0, 0(sp)
+; RV64I-NEXT:    mv a1, a0
+; RV64I-NEXT:    mv a2, a0
+; RV64I-NEXT:    mv a3, a0
+; RV64I-NEXT:    mv a4, a0
+; RV64I-NEXT:    mv a5, a0
+; RV64I-NEXT:    mv a6, a0
+; RV64I-NEXT:    mv a7, a0
+; RV64I-NEXT:    call defined_many_args at plt
+; RV64I-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 32
+; RV64I-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: test_call_defined_many_args:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    addi sp, sp, -32
+; RV64I-SMALL-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-SMALL-NEXT:    sd a0, 8(sp)
+; RV64I-SMALL-NEXT:    sd a0, 0(sp)
+; RV64I-SMALL-NEXT:    mv a1, a0
+; RV64I-SMALL-NEXT:    mv a2, a0
+; RV64I-SMALL-NEXT:    mv a3, a0
+; RV64I-SMALL-NEXT:    mv a4, a0
+; RV64I-SMALL-NEXT:    mv a5, a0
+; RV64I-SMALL-NEXT:    mv a6, a0
+; RV64I-SMALL-NEXT:    mv a7, a0
+; RV64I-SMALL-NEXT:    call defined_many_args at plt
+; RV64I-SMALL-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-SMALL-NEXT:    addi sp, sp, 32
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: test_call_defined_many_args:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -32
+; RV64I-MEDIUM-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-MEDIUM-NEXT:    sd a0, 8(sp)
+; RV64I-MEDIUM-NEXT:    sd a0, 0(sp)
+; RV64I-MEDIUM-NEXT:    mv a1, a0
+; RV64I-MEDIUM-NEXT:    mv a2, a0
+; RV64I-MEDIUM-NEXT:    mv a3, a0
+; RV64I-MEDIUM-NEXT:    mv a4, a0
+; RV64I-MEDIUM-NEXT:    mv a5, a0
+; RV64I-MEDIUM-NEXT:    mv a6, a0
+; RV64I-MEDIUM-NEXT:    mv a7, a0
+; RV64I-MEDIUM-NEXT:    call defined_many_args at plt
+; RV64I-MEDIUM-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 32
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: test_call_defined_many_args:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi sp, sp, -32
+; RV64I-LARGE-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:  .Lpcrel_hi5:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI10_0)
+; RV64I-LARGE-NEXT:    ld t1, %pcrel_lo(.Lpcrel_hi5)(a1)
+; RV64I-LARGE-NEXT:    sd a0, 8(sp)
+; RV64I-LARGE-NEXT:    sd a0, 0(sp)
+; RV64I-LARGE-NEXT:    mv a1, a0
+; RV64I-LARGE-NEXT:    mv a2, a0
+; RV64I-LARGE-NEXT:    mv a3, a0
+; RV64I-LARGE-NEXT:    mv a4, a0
+; RV64I-LARGE-NEXT:    mv a5, a0
+; RV64I-LARGE-NEXT:    mv a6, a0
+; RV64I-LARGE-NEXT:    mv a7, a0
+; RV64I-LARGE-NEXT:    jalr t1
+; RV64I-LARGE-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 32
+; RV64I-LARGE-NEXT:    ret
   %1 = call i32 @defined_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
                                    i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
   ret i32 %1
diff --git a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll
index 617155b31976187..4c8d8f772b60a3e 100644
--- a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll
+++ b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll
@@ -3,6 +3,12 @@
 ; RUN:   | FileCheck %s -check-prefix=RV32I-SMALL
 ; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi=ilp32f -code-model=medium -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV32I-MEDIUM
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=small -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I-SMALL
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=medium -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I-MEDIUM
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64f -code-model=large -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I-LARGE
 
 ; Check lowering of globals
 @G = global i32 0
@@ -20,6 +26,27 @@ define i32 @lower_global(i32 %a) nounwind {
 ; RV32I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(G)
 ; RV32I-MEDIUM-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi0)(a0)
 ; RV32I-MEDIUM-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: lower_global:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    lui a0, %hi(G)
+; RV64I-SMALL-NEXT:    lw a0, %lo(G)(a0)
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: lower_global:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:  .Lpcrel_hi0:
+; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(G)
+; RV64I-MEDIUM-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: lower_global:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi0:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI0_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
   %1 = load volatile i32, ptr @G
   ret i32 %1
 }
@@ -43,6 +70,30 @@ define void @lower_blockaddress() nounwind {
 ; RV32I-MEDIUM-NEXT:    li a1, 1
 ; RV32I-MEDIUM-NEXT:    sw a1, %pcrel_lo(.Lpcrel_hi1)(a0)
 ; RV32I-MEDIUM-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: lower_blockaddress:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    lui a0, %hi(addr)
+; RV64I-SMALL-NEXT:    li a1, 1
+; RV64I-SMALL-NEXT:    sd a1, %lo(addr)(a0)
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: lower_blockaddress:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:  .Lpcrel_hi1:
+; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(addr)
+; RV64I-MEDIUM-NEXT:    li a1, 1
+; RV64I-MEDIUM-NEXT:    sd a1, %pcrel_lo(.Lpcrel_hi1)(a0)
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: lower_blockaddress:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi1:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI1_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi1)(a0)
+; RV64I-LARGE-NEXT:    li a1, 1
+; RV64I-LARGE-NEXT:    sd a1, 0(a0)
+; RV64I-LARGE-NEXT:    ret
   store volatile ptr blockaddress(@lower_blockaddress, %block), ptr @addr
   ret void
 
@@ -95,6 +146,71 @@ define signext i32 @lower_blockaddress_displ(i32 signext %w) nounwind {
 ; RV32I-MEDIUM-NEXT:    li a0, 3
 ; RV32I-MEDIUM-NEXT:    addi sp, sp, 16
 ; RV32I-MEDIUM-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: lower_blockaddress_displ:
+; RV64I-SMALL:       # %bb.0: # %entry
+; RV64I-SMALL-NEXT:    addi sp, sp, -16
+; RV64I-SMALL-NEXT:    lui a1, %hi(.Ltmp0)
+; RV64I-SMALL-NEXT:    addi a1, a1, %lo(.Ltmp0)
+; RV64I-SMALL-NEXT:    li a2, 101
+; RV64I-SMALL-NEXT:    sd a1, 8(sp)
+; RV64I-SMALL-NEXT:    blt a0, a2, .LBB2_3
+; RV64I-SMALL-NEXT:  # %bb.1: # %if.then
+; RV64I-SMALL-NEXT:    ld a0, 8(sp)
+; RV64I-SMALL-NEXT:    jr a0
+; RV64I-SMALL-NEXT:  .Ltmp0: # Block address taken
+; RV64I-SMALL-NEXT:  .LBB2_2: # %return
+; RV64I-SMALL-NEXT:    li a0, 4
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+; RV64I-SMALL-NEXT:  .LBB2_3: # %return.clone
+; RV64I-SMALL-NEXT:    li a0, 3
+; RV64I-SMALL-NEXT:    addi sp, sp, 16
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: lower_blockaddress_displ:
+; RV64I-MEDIUM:       # %bb.0: # %entry
+; RV64I-MEDIUM-NEXT:    addi sp, sp, -16
+; RV64I-MEDIUM-NEXT:  .Lpcrel_hi2:
+; RV64I-MEDIUM-NEXT:    auipc a1, %pcrel_hi(.Ltmp0)
+; RV64I-MEDIUM-NEXT:    addi a1, a1, %pcrel_lo(.Lpcrel_hi2)
+; RV64I-MEDIUM-NEXT:    li a2, 101
+; RV64I-MEDIUM-NEXT:    sd a1, 8(sp)
+; RV64I-MEDIUM-NEXT:    blt a0, a2, .LBB2_3
+; RV64I-MEDIUM-NEXT:  # %bb.1: # %if.then
+; RV64I-MEDIUM-NEXT:    ld a0, 8(sp)
+; RV64I-MEDIUM-NEXT:    jr a0
+; RV64I-MEDIUM-NEXT:  .Ltmp0: # Block address taken
+; RV64I-MEDIUM-NEXT:  .LBB2_2: # %return
+; RV64I-MEDIUM-NEXT:    li a0, 4
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+; RV64I-MEDIUM-NEXT:  .LBB2_3: # %return.clone
+; RV64I-MEDIUM-NEXT:    li a0, 3
+; RV64I-MEDIUM-NEXT:    addi sp, sp, 16
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: lower_blockaddress_displ:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    addi sp, sp, -16
+; RV64I-LARGE-NEXT:  .Lpcrel_hi2:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI2_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi2)(a1)
+; RV64I-LARGE-NEXT:    li a2, 101
+; RV64I-LARGE-NEXT:    sd a1, 8(sp)
+; RV64I-LARGE-NEXT:    blt a0, a2, .LBB2_3
+; RV64I-LARGE-NEXT:  # %bb.1: # %if.then
+; RV64I-LARGE-NEXT:    ld a0, 8(sp)
+; RV64I-LARGE-NEXT:    jr a0
+; RV64I-LARGE-NEXT:  .Ltmp0: # Block address taken
+; RV64I-LARGE-NEXT:  .LBB2_2: # %return
+; RV64I-LARGE-NEXT:    li a0, 4
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB2_3: # %return.clone
+; RV64I-LARGE-NEXT:    li a0, 3
+; RV64I-LARGE-NEXT:    addi sp, sp, 16
+; RV64I-LARGE-NEXT:    ret
 entry:
   %x = alloca ptr, align 8
   store ptr blockaddress(@lower_blockaddress_displ, %test_block), ptr %x, align 8
@@ -136,6 +252,29 @@ define float @lower_constantpool(float %a) nounwind {
 ; RV32I-MEDIUM-NEXT:    flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0)
 ; RV32I-MEDIUM-NEXT:    fadd.s fa0, fa0, fa5
 ; RV32I-MEDIUM-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: lower_constantpool:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    lui a0, %hi(.LCPI3_0)
+; RV64I-SMALL-NEXT:    flw fa5, %lo(.LCPI3_0)(a0)
+; RV64I-SMALL-NEXT:    fadd.s fa0, fa0, fa5
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: lower_constantpool:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:  .Lpcrel_hi3:
+; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
+; RV64I-MEDIUM-NEXT:    flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0)
+; RV64I-MEDIUM-NEXT:    fadd.s fa0, fa0, fa5
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: lower_constantpool:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi3:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
+; RV64I-LARGE-NEXT:    flw fa5, %pcrel_lo(.Lpcrel_hi3)(a0)
+; RV64I-LARGE-NEXT:    fadd.s fa0, fa0, fa5
+; RV64I-LARGE-NEXT:    ret
   %1 = fadd float %a, 1.000244140625
   ret float %1
 }
@@ -157,6 +296,28 @@ define i32 @lower_extern_weak(i32 %a) nounwind {
 ; RV32I-MEDIUM-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi4)(a0)
 ; RV32I-MEDIUM-NEXT:    lw a0, 0(a0)
 ; RV32I-MEDIUM-NEXT:    ret
+;
+; RV64I-SMALL-LABEL: lower_extern_weak:
+; RV64I-SMALL:       # %bb.0:
+; RV64I-SMALL-NEXT:    lui a0, %hi(W)
+; RV64I-SMALL-NEXT:    lw a0, %lo(W)(a0)
+; RV64I-SMALL-NEXT:    ret
+;
+; RV64I-MEDIUM-LABEL: lower_extern_weak:
+; RV64I-MEDIUM:       # %bb.0:
+; RV64I-MEDIUM-NEXT:  .Lpcrel_hi4:
+; RV64I-MEDIUM-NEXT:    auipc a0, %got_pcrel_hi(W)
+; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi4)(a0)
+; RV64I-MEDIUM-NEXT:    lw a0, 0(a0)
+; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: lower_extern_weak:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi4:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI4_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi4)(a0)
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
   %1 = load volatile i32, ptr @W
   ret i32 %1
 }
diff --git a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
index 321857b2104eb51..4a6e43c7d2be6a0 100644
--- a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
+++ b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
@@ -7,6 +7,8 @@
 ; RUN:   -riscv-enable-sink-fold | FileCheck -check-prefix=RV64I %s
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs -code-model=medium < %s \
 ; RUN:   -riscv-enable-sink-fold | FileCheck -check-prefix=RV64I-MEDIUM %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs -code-model=large < %s \
+; RUN:   -riscv-enable-sink-fold | FileCheck -check-prefix=RV64I-LARGE %s
 
 ; We can often fold an ADDI into the offset of load/store instructions:
 ;   (load (addi base, off1), off2) -> (load base, off1+off2)
@@ -51,6 +53,14 @@ define dso_local i64 @load_g_0() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_0)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_0:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi0:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI0_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_0
   ret i64 %0
@@ -86,6 +96,14 @@ define dso_local i64 @load_g_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_1)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi1)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_1:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi1:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI1_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi1)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_1
   ret i64 %0
@@ -121,6 +139,14 @@ define dso_local i64 @load_g_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_2)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi2)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_2:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi2:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI2_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi2)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_2
   ret i64 %0
@@ -156,6 +182,14 @@ define dso_local i64 @load_g_4() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_4)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi3)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_4:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi3:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi3)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_4
   ret i64 %0
@@ -190,6 +224,14 @@ define dso_local i64 @load_g_8() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_8)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi4)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_8:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi4:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI4_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi4)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_8
   ret i64 %0
@@ -224,6 +266,14 @@ define dso_local i64 @load_g_16() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_16)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi5)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_g_16:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi5:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI5_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi5)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @g_16
   ret i64 %0
@@ -259,6 +309,14 @@ define dso_local void @store_g_4() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_4)
 ; RV64I-MEDIUM-NEXT:    sd zero, %pcrel_lo(.Lpcrel_hi6)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: store_g_4:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi6:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI6_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi6)(a0)
+; RV64I-LARGE-NEXT:    sd zero, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
    store i64 0, ptr @g_4
    ret void
@@ -293,6 +351,14 @@ define dso_local void @store_g_8() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(g_8)
 ; RV64I-MEDIUM-NEXT:    sd zero, %pcrel_lo(.Lpcrel_hi7)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: store_g_8:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi7:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi7)(a0)
+; RV64I-LARGE-NEXT:    sd zero, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
    store i64 0, ptr @g_8
    ret void
@@ -337,6 +403,16 @@ define dso_local void @inc_g_i32() nounwind {
 ; RV64I-MEDIUM-NEXT:    addi a1, a1, 1
 ; RV64I-MEDIUM-NEXT:    sw a1, %pcrel_lo(.Lpcrel_hi8)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: inc_g_i32:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi8:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi8)(a0)
+; RV64I-LARGE-NEXT:    lw a1, 0(a0)
+; RV64I-LARGE-NEXT:    addi a1, a1, 1
+; RV64I-LARGE-NEXT:    sw a1, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i32, ptr @g_4_i32
   %inc = add i32 %0, 1
@@ -377,6 +453,14 @@ define dso_local i32 @load_ga() local_unnamed_addr #0 {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(ga+4)
 ; RV64I-MEDIUM-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi9)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_ga:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi9:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI9_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi9)(a0)
+; RV64I-LARGE-NEXT:    lw a0, 4(a0)
+; RV64I-LARGE-NEXT:    ret
   %1 = load i32, ptr getelementptr inbounds ([2 x i32], ptr @ga, i32 0, i32 1), align 4
   ret i32 %1
 }
@@ -416,6 +500,14 @@ define dso_local i64 @load_ga_8() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(ga_8+8)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi10)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_ga_8:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi10:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI10_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi10)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 8(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr getelementptr inbounds ([2 x i64], ptr @ga_8, i32 0, i32 1)
   ret i64 %0
@@ -450,6 +542,14 @@ define dso_local i64 @load_ga_16() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(ga_16+8)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi11)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_ga_16:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi11:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI11_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi11)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 8(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr getelementptr inbounds ([2 x i64], ptr @ga_16, i32 0, i32 1)
   ret i64 %0
@@ -490,6 +590,16 @@ define dso_local ptr @load_ba_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(.Ltmp0)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi12)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_ba_1:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp0: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi12:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI12_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi12)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 label:
@@ -531,6 +641,16 @@ define dso_local ptr @load_ba_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    auipc a0, %pcrel_hi(.Ltmp1+8)
 ; RV64I-MEDIUM-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi13)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_ba_2:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp1: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi13:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI13_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi13)(a0)
+; RV64I-LARGE-NEXT:    ld a0, 8(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 label:
@@ -575,6 +695,13 @@ define dso_local i64 @load_tl_4() nounwind {
 ; RV64I-MEDIUM-NEXT:    add a0, a0, tp, %tprel_add(tl_4)
 ; RV64I-MEDIUM-NEXT:    ld a0, %tprel_lo(tl_4)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_tl_4:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    lui a0, %tprel_hi(tl_4)
+; RV64I-LARGE-NEXT:    add a0, a0, tp, %tprel_add(tl_4)
+; RV64I-LARGE-NEXT:    ld a0, %tprel_lo(tl_4)(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @tl_4
   ret i64 %0
@@ -610,6 +737,13 @@ define dso_local i64 @load_tl_8() nounwind {
 ; RV64I-MEDIUM-NEXT:    add a0, a0, tp, %tprel_add(tl_8)
 ; RV64I-MEDIUM-NEXT:    ld a0, %tprel_lo(tl_8)(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_tl_8:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    lui a0, %tprel_hi(tl_8)
+; RV64I-LARGE-NEXT:    add a0, a0, tp, %tprel_add(tl_8)
+; RV64I-LARGE-NEXT:    ld a0, %tprel_lo(tl_8)(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr @tl_8
   ret i64 %0
@@ -637,6 +771,11 @@ define dso_local i64 @load_const_ok() nounwind {
 ; RV64I-MEDIUM:       # %bb.0: # %entry
 ; RV64I-MEDIUM-NEXT:    ld a0, 2040(zero)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_const_ok:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    ld a0, 2040(zero)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr inttoptr (i32 2040 to ptr)
   ret i64 %0
@@ -666,6 +805,11 @@ define dso_local i64 @load_cost_overflow() nounwind {
 ; RV64I-MEDIUM:       # %bb.0: # %entry
 ; RV64I-MEDIUM-NEXT:    ld a0, 2044(zero)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_cost_overflow:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    ld a0, 2044(zero)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i64, ptr inttoptr (i64 2044 to ptr)
   ret i64 %0
@@ -695,6 +839,12 @@ define dso_local i32 @load_const_medium() nounwind {
 ; RV64I-MEDIUM-NEXT:    lui a0, 1
 ; RV64I-MEDIUM-NEXT:    lw a0, -16(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_const_medium:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    lui a0, 1
+; RV64I-LARGE-NEXT:    lw a0, -16(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i32, ptr inttoptr (i64 4080 to ptr)
   ret i32 %0
@@ -729,6 +879,13 @@ define dso_local i32 @load_const_large() nounwind {
 ; RV64I-MEDIUM-NEXT:    addiw a0, a0, -2048
 ; RV64I-MEDIUM-NEXT:    lw a0, 0(a0)
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: load_const_large:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    lui a0, 524288
+; RV64I-LARGE-NEXT:    addiw a0, a0, -2048
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    ret
 entry:
   %0 = load i32, ptr inttoptr (i64 2147481600 to ptr)
   ret i32 %0
@@ -938,6 +1095,47 @@ define i64 @fold_addi_from_different_bb(i64 %k, i64 %n, ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    ld s3, 8(sp) # 8-byte Folded Reload
 ; RV64I-MEDIUM-NEXT:    addi sp, sp, 48
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: fold_addi_from_different_bb:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:    addi sp, sp, -48
+; RV64I-LARGE-NEXT:    sd ra, 40(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s0, 32(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s1, 24(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s2, 16(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s3, 8(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    sd s4, 0(sp) # 8-byte Folded Spill
+; RV64I-LARGE-NEXT:    blez a1, .LBB20_3
+; RV64I-LARGE-NEXT:  # %bb.1: # %for.body.lr.ph
+; RV64I-LARGE-NEXT:    mv s0, a2
+; RV64I-LARGE-NEXT:    mv s1, a1
+; RV64I-LARGE-NEXT:  .Lpcrel_hi14:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI20_0)
+; RV64I-LARGE-NEXT:    ld s3, %pcrel_lo(.Lpcrel_hi14)(a1)
+; RV64I-LARGE-NEXT:    li s2, 0
+; RV64I-LARGE-NEXT:    slli a0, a0, 4
+; RV64I-LARGE-NEXT:    add s4, a2, a0
+; RV64I-LARGE-NEXT:  .LBB20_2: # %for.body
+; RV64I-LARGE-NEXT:    # =>This Inner Loop Header: Depth=1
+; RV64I-LARGE-NEXT:    mv a0, s0
+; RV64I-LARGE-NEXT:    jalr s3
+; RV64I-LARGE-NEXT:    ld a0, 8(s4)
+; RV64I-LARGE-NEXT:    addi s1, s1, -1
+; RV64I-LARGE-NEXT:    add s2, a0, s2
+; RV64I-LARGE-NEXT:    bnez s1, .LBB20_2
+; RV64I-LARGE-NEXT:    j .LBB20_4
+; RV64I-LARGE-NEXT:  .LBB20_3:
+; RV64I-LARGE-NEXT:    li s2, 0
+; RV64I-LARGE-NEXT:  .LBB20_4: # %for.cond.cleanup
+; RV64I-LARGE-NEXT:    mv a0, s2
+; RV64I-LARGE-NEXT:    ld ra, 40(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s0, 32(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s1, 24(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s2, 16(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s3, 8(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    ld s4, 0(sp) # 8-byte Folded Reload
+; RV64I-LARGE-NEXT:    addi sp, sp, 48
+; RV64I-LARGE-NEXT:    ret
 entry:
   %cmp4 = icmp sgt i64 %n, 0
   br i1 %cmp4, label %for.body.lr.ph, label %for.cond.cleanup
diff --git a/llvm/test/CodeGen/RISCV/inline-asm-mem-constraint.ll b/llvm/test/CodeGen/RISCV/inline-asm-mem-constraint.ll
index eb0e0287d48d7be..0dc4e884cbb104f 100644
--- a/llvm/test/CodeGen/RISCV/inline-asm-mem-constraint.ll
+++ b/llvm/test/CodeGen/RISCV/inline-asm-mem-constraint.ll
@@ -7,6 +7,8 @@
 ; RUN:   | FileCheck -check-prefixes=RV32I-MEDIUM %s
 ; RUN: llc -mtriple=riscv64 -code-model=medium -verify-machineinstrs -no-integrated-as < %s \
 ; RUN:   | FileCheck -check-prefixes=RV64I-MEDIUM %s
+; RUN: llc -mtriple=riscv64 -code-model=large -verify-machineinstrs -no-integrated-as < %s \
+; RUN:   | FileCheck -check-prefixes=RV64I-LARGE %s
 
 @eg = external global [4000 x i32], align 4
 @ewg = extern_weak global [4000 x i32], align 4
@@ -35,6 +37,12 @@ define void @constraint_m_1(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    #APP
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm sideeffect "", "=*m"(ptr elementtype(i32) %a)
   ret void
 }
@@ -67,6 +75,13 @@ define i32 @constraint_m_2(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lw a0, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   %1 = tail call i32 asm "lw $0, $1", "=r,*m"(ptr elementtype(i32) %a)
   ret i32 %1
 }
@@ -99,6 +114,13 @@ define i32 @constraint_m_with_offset(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lw a0, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_offset:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw a0, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   %1 = getelementptr i32, ptr %a, i32 1
   %2 = tail call i32 asm "lw $0, $1", "=r,*m"(ptr elementtype(i32) %1)
   ret i32 %2
@@ -140,6 +162,16 @@ define void @constraint_m_with_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi0:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) @eg)
   ret void
 }
@@ -182,6 +214,16 @@ define void @constraint_m_with_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi1:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI4_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi1)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 1))
   ret void
 }
@@ -224,6 +266,19 @@ define void @constraint_m_with_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi2:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI5_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi2)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 2000))
   ret void
 }
@@ -264,6 +319,16 @@ define void @constraint_m_with_extern_weak_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_extern_weak_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi3:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI6_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi3)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) @ewg)
   ret void
 }
@@ -306,6 +371,16 @@ define void @constraint_m_with_extern_weak_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_extern_weak_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi4:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi4)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 1))
   ret void
 }
@@ -354,6 +429,19 @@ define void @constraint_m_with_extern_weak_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_extern_weak_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi5:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi5)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 2000))
   ret void
 }
@@ -402,6 +490,18 @@ define void @constraint_m_with_local_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_local_1:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp0: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi6:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI9_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi6)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -456,6 +556,18 @@ define void @constraint_m_with_local_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_local_2:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp1: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi7:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI10_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi7)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -510,6 +622,18 @@ define void @constraint_m_with_local_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 2000(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_local_3:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp2: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi8:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI11_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi8)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 2000(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -554,6 +678,16 @@ define void @constraint_m_with_multi_operands() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0); sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_multi_operands:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi9:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI12_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi9)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0); sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0; sw zero, $1", "=*m,=*m"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg)
   ret void
 }
@@ -606,6 +740,19 @@ define void @constraint_m_with_multi_asm() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_multi_asm:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi10:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI13_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi10)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) @eg)
   call void asm "sw zero, $0", "=*m"(ptr elementtype(i32) @eg)
   ret void
@@ -675,6 +822,23 @@ define i32 @constraint_m_with_callbr_multi_operands(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_callbr_multi_operands:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi11:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI14_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi11)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); sw zero, 0(a1); beqz a0, .LBB14_2
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB14_2: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; sw zero, $1; beqz $2, $3", "=*m,=*m,r,!i"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg, i32 %a) to label %normal [label %fail]
 
@@ -765,6 +929,27 @@ define i32 @constraint_m_with_multi_callbr_asm(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_m_with_multi_callbr_asm:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi12:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI15_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi12)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB15_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal0
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB15_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.2: # %normal1
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB15_3: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; beqz $1, $2", "=*m,r,!i"(ptr elementtype(i32) @eg, i32 %a) to label %normal0 [label %fail]
 
@@ -802,6 +987,12 @@ define void @constraint_o_1(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    #APP
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm sideeffect "", "=*o"(ptr elementtype(i32) %a)
   ret void
 }
@@ -834,6 +1025,13 @@ define i32 @constraint_o_2(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lw a0, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   %1 = tail call i32 asm "lw $0, $1", "=r,*o"(ptr elementtype(i32) %a)
   ret i32 %1
 }
@@ -866,6 +1064,13 @@ define i32 @constraint_o_with_offset(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lw a0, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_offset:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw a0, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   %1 = getelementptr i32, ptr %a, i32 1
   %2 = tail call i32 asm "lw $0, $1", "=r,*o"(ptr elementtype(i32) %1)
   ret i32 %2
@@ -907,6 +1112,16 @@ define void @constraint_o_with_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi13:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI19_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi13)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) @eg)
   ret void
 }
@@ -949,6 +1164,16 @@ define void @constraint_o_with_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi14:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI20_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi14)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 1))
   ret void
 }
@@ -991,6 +1216,19 @@ define void @constraint_o_with_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi15:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI21_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi15)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 2000))
   ret void
 }
@@ -1031,6 +1269,16 @@ define void @constraint_o_with_extern_weak_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_extern_weak_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi16:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI22_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi16)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) @ewg)
   ret void
 }
@@ -1073,6 +1321,16 @@ define void @constraint_o_with_extern_weak_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_extern_weak_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi17:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI23_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi17)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 1))
   ret void
 }
@@ -1121,6 +1379,19 @@ define void @constraint_o_with_extern_weak_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_extern_weak_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi18:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI24_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi18)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 2000))
   ret void
 }
@@ -1161,6 +1432,16 @@ define void @constraint_o_with_multi_operands() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0) \n sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_multi_operands:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi19:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI25_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi19)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0) \n sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0 \n sw zero, $1", "=*o,=*o"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg)
   ret void
 }
@@ -1213,6 +1494,19 @@ define void @constraint_o_with_multi_asm() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_multi_asm:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi20:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI26_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi20)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) @eg)
   call void asm "sw zero, $0", "=*o"(ptr elementtype(i32) @eg)
   ret void
@@ -1282,6 +1576,23 @@ define i32 @constraint_o_with_callbr_multi_operands(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_callbr_multi_operands:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi21:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI27_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi21)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); sw zero, 0(a1); beqz a0, .LBB27_2
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB27_2: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; sw zero, $1; beqz $2, $3", "=*m,=*m,r,!i"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg, i32 %a) to label %normal [label %fail]
 
@@ -1372,6 +1683,27 @@ define i32 @constraint_o_with_multi_callbr_asm(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_multi_callbr_asm:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi22:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI28_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi22)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB28_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal0
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB28_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.2: # %normal1
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB28_3: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; beqz $1, $2", "=*o,r,!i"(ptr elementtype(i32) @eg, i32 %a) to label %normal0 [label %fail]
 
@@ -1429,6 +1761,18 @@ define void @constraint_o_with_local_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_local_1:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp3: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi23:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI29_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi23)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -1483,6 +1827,18 @@ define void @constraint_o_with_local_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 4(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_local_2:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp4: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi24:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI30_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi24)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 4(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -1537,6 +1893,18 @@ define void @constraint_o_with_local_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 2000(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_o_with_local_3:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp5: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi25:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI31_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi25)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 2000(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -1585,6 +1953,16 @@ define void @constraint_A(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lb s1, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sb s0, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lb s1, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   tail call void asm sideeffect "sb s0, $0", "*A"(ptr elementtype(i8) %a)
   tail call void asm sideeffect "lb s1, $0", "*A"(ptr elementtype(i8) %a)
   ret void
@@ -1622,6 +2000,14 @@ define i32 @constraint_A_with_offset(ptr %a) nounwind {
 ; RV64I-MEDIUM-NEXT:    lw a0, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_offset:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:    addi a0, a0, 4
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw a0, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   %1 = getelementptr i32, ptr %a, i32 1
   %2 = tail call i32 asm "lw $0, $1", "=r,*A"(ptr elementtype(i32) %1)
   ret i32 %2
@@ -1665,6 +2051,16 @@ define void @constraint_A_with_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi26:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI34_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi26)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) @eg)
   ret void
 }
@@ -1707,6 +2103,17 @@ define void @constraint_A_with_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi27:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI35_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi27)(a0)
+; RV64I-LARGE-NEXT:    addi a0, a0, 4
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 1))
   ret void
 }
@@ -1749,6 +2156,19 @@ define void @constraint_A_with_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi28:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI36_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi28)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @eg, i32 0, i32 2000))
   ret void
 }
@@ -1791,6 +2211,16 @@ define void @constraint_A_with_extern_weak_global_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_extern_weak_global_1:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi29:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI37_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi29)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) @ewg)
   ret void
 }
@@ -1835,6 +2265,17 @@ define void @constraint_A_with_extern_weak_global_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_extern_weak_global_2:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi30:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI38_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi30)(a0)
+; RV64I-LARGE-NEXT:    addi a0, a0, 4
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 1))
   ret void
 }
@@ -1883,6 +2324,19 @@ define void @constraint_A_with_extern_weak_global_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_extern_weak_global_3:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi31:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI39_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi31)(a0)
+; RV64I-LARGE-NEXT:    lui a1, 2
+; RV64I-LARGE-NEXT:    addiw a1, a1, -192
+; RV64I-LARGE-NEXT:    add a0, a0, a1
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) getelementptr ([400000 x i32], ptr @ewg, i32 0, i32 2000))
   ret void
 }
@@ -1925,6 +2379,16 @@ define void @constraint_A_with_multi_operands() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0) \n sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_multi_operands:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi32:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI40_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi32)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0) \n sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0 \n sw zero, $1", "=*A,=*A"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg)
   ret void
 }
@@ -1979,6 +2443,19 @@ define void @constraint_A_with_multi_asm() nounwind {
 ; RV64I-MEDIUM-NEXT:    sw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_multi_asm:
+; RV64I-LARGE:       # %bb.0:
+; RV64I-LARGE-NEXT:  .Lpcrel_hi33:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI41_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi33)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) @eg)
   call void asm "sw zero, $0", "=*A"(ptr elementtype(i32) @eg)
   ret void
@@ -2050,6 +2527,23 @@ define i32 @constraint_A_with_callbr_multi_operands(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_callbr_multi_operands:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi34:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI42_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi34)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); sw zero, 0(a1); beqz a0, .LBB42_2
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB42_2: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; sw zero, $1; beqz $2, $3", "*A,*A,r,!i"(ptr elementtype(i32) @eg, ptr elementtype(i32) @eg, i32 %a) to label %normal [label %fail]
 
@@ -2142,6 +2636,27 @@ define i32 @constraint_A_with_multi_callbr_asm(i32 %a) {
 ; RV64I-MEDIUM-NEXT:    # Label of block must be emitted
 ; RV64I-MEDIUM-NEXT:    li a0, 1
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_multi_callbr_asm:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Lpcrel_hi35:
+; RV64I-LARGE-NEXT:    auipc a1, %pcrel_hi(.LCPI43_0)
+; RV64I-LARGE-NEXT:    ld a1, %pcrel_lo(.Lpcrel_hi35)(a1)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB43_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.1: # %normal0
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    sw zero, 0(a1); beqz a0, .LBB43_3
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:  # %bb.2: # %normal1
+; RV64I-LARGE-NEXT:    li a0, 0
+; RV64I-LARGE-NEXT:    ret
+; RV64I-LARGE-NEXT:  .LBB43_3: # Block address taken
+; RV64I-LARGE-NEXT:    # %fail
+; RV64I-LARGE-NEXT:    # Label of block must be emitted
+; RV64I-LARGE-NEXT:    li a0, 1
+; RV64I-LARGE-NEXT:    ret
 entry:
   callbr void asm "sw zero, $0; beqz $1, $2", "=*A,r,!i"(ptr elementtype(i32) @eg, i32 %a) to label %normal0 [label %fail]
 
@@ -2201,6 +2716,18 @@ define void @constraint_A_with_local_1() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_local_1:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp6: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi36:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI44_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi36)(a0)
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -2255,6 +2782,19 @@ define void @constraint_A_with_local_2() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_local_2:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp7: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi37:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI45_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi37)(a0)
+; RV64I-LARGE-NEXT:    addi a0, a0, 4
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 
@@ -2309,6 +2849,19 @@ define void @constraint_A_with_local_3() nounwind {
 ; RV64I-MEDIUM-NEXT:    lw zero, 0(a0)
 ; RV64I-MEDIUM-NEXT:    #NO_APP
 ; RV64I-MEDIUM-NEXT:    ret
+;
+; RV64I-LARGE-LABEL: constraint_A_with_local_3:
+; RV64I-LARGE:       # %bb.0: # %entry
+; RV64I-LARGE-NEXT:  .Ltmp8: # Block address taken
+; RV64I-LARGE-NEXT:  # %bb.1: # %label
+; RV64I-LARGE-NEXT:  .Lpcrel_hi38:
+; RV64I-LARGE-NEXT:    auipc a0, %pcrel_hi(.LCPI46_0)
+; RV64I-LARGE-NEXT:    ld a0, %pcrel_lo(.Lpcrel_hi38)(a0)
+; RV64I-LARGE-NEXT:    addi a0, a0, 2000
+; RV64I-LARGE-NEXT:    #APP
+; RV64I-LARGE-NEXT:    lw zero, 0(a0)
+; RV64I-LARGE-NEXT:    #NO_APP
+; RV64I-LARGE-NEXT:    ret
 entry:
   br label %label
 



More information about the llvm-commits mailing list