forked from OSchip/llvm-project
[RISCV] Generate address sequences suitable for mcmodel=medium
This patch adds an implementation of a PC-relative addressing sequence to be used when -mcmodel=medium is specified. With absolute addressing, a 'medium' codemodel may cause addresses to be out of range. This is because while 'medium' implies a 2 GiB addressing range, this 2 GiB can be at any offset as opposed to 'small', which implies the first 2 GiB only. Note that LLVM/Clang currently specifies code models differently to GCC, where small and medium imply the same functionality as GCC's medlow and medany respectively. Differential Revision: https://reviews.llvm.org/D54143 Patch by Lewis Revill. llvm-svn: 357393
This commit is contained in:
parent
efe376add6
commit
da20f5ca74
|
@ -114,6 +114,10 @@ private:
|
||||||
/// branch.
|
/// branch.
|
||||||
bool AddressTaken = false;
|
bool AddressTaken = false;
|
||||||
|
|
||||||
|
/// Indicate that this basic block needs its symbol be emitted regardless of
|
||||||
|
/// whether the flow just falls-through to it.
|
||||||
|
bool LabelMustBeEmitted = false;
|
||||||
|
|
||||||
/// Indicate that this basic block is the entry block of an EH scope, i.e.,
|
/// Indicate that this basic block is the entry block of an EH scope, i.e.,
|
||||||
/// the block that used to have a catchpad or cleanuppad instruction in the
|
/// the block that used to have a catchpad or cleanuppad instruction in the
|
||||||
/// LLVM IR.
|
/// LLVM IR.
|
||||||
|
@ -158,6 +162,13 @@ public:
|
||||||
/// branch.
|
/// branch.
|
||||||
void setHasAddressTaken() { AddressTaken = true; }
|
void setHasAddressTaken() { AddressTaken = true; }
|
||||||
|
|
||||||
|
/// Test whether this block must have its label emitted.
|
||||||
|
bool hasLabelMustBeEmitted() const { return LabelMustBeEmitted; }
|
||||||
|
|
||||||
|
/// Set this block to reflect that, regardless how we flow to it, we need
|
||||||
|
/// its label be emitted.
|
||||||
|
void setLabelMustBeEmitted() { LabelMustBeEmitted = true; }
|
||||||
|
|
||||||
/// Return the MachineFunction containing this basic block.
|
/// Return the MachineFunction containing this basic block.
|
||||||
const MachineFunction *getParent() const { return xParent; }
|
const MachineFunction *getParent() const { return xParent; }
|
||||||
MachineFunction *getParent() { return xParent; }
|
MachineFunction *getParent() { return xParent; }
|
||||||
|
|
|
@ -2925,13 +2925,16 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {
|
||||||
|
|
||||||
// Print the main label for the block.
|
// Print the main label for the block.
|
||||||
if (MBB.pred_empty() ||
|
if (MBB.pred_empty() ||
|
||||||
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) {
|
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() &&
|
||||||
|
!MBB.hasLabelMustBeEmitted())) {
|
||||||
if (isVerbose()) {
|
if (isVerbose()) {
|
||||||
// NOTE: Want this comment at start of line, don't emit with AddComment.
|
// NOTE: Want this comment at start of line, don't emit with AddComment.
|
||||||
OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":",
|
OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":",
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (isVerbose() && MBB.hasLabelMustBeEmitted())
|
||||||
|
OutStreamer->AddComment("Label of block must be emitted");
|
||||||
OutStreamer->EmitLabel(MBB.getSymbol());
|
OutStreamer->EmitLabel(MBB.getSymbol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,9 @@ private:
|
||||||
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
|
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock::iterator MBBI, bool IsMasked,
|
MachineBasicBlock::iterator MBBI, bool IsMasked,
|
||||||
int Width, MachineBasicBlock::iterator &NextMBBI);
|
int Width, MachineBasicBlock::iterator &NextMBBI);
|
||||||
|
bool expandLoadLocalAddress(MachineBasicBlock &MBB,
|
||||||
|
MachineBasicBlock::iterator MBBI,
|
||||||
|
MachineBasicBlock::iterator &NextMBBI);
|
||||||
};
|
};
|
||||||
|
|
||||||
char RISCVExpandPseudo::ID = 0;
|
char RISCVExpandPseudo::ID = 0;
|
||||||
|
@ -117,6 +120,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
|
||||||
return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
|
return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
|
||||||
case RISCV::PseudoMaskedCmpXchg32:
|
case RISCV::PseudoMaskedCmpXchg32:
|
||||||
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
|
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
|
||||||
|
case RISCV::PseudoLLA:
|
||||||
|
return expandLoadLocalAddress(MBB, MBBI, NextMBBI);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -597,6 +602,46 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RISCVExpandPseudo::expandLoadLocalAddress(
|
||||||
|
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||||
|
MachineBasicBlock::iterator &NextMBBI) {
|
||||||
|
MachineFunction *MF = MBB.getParent();
|
||||||
|
MachineInstr &MI = *MBBI;
|
||||||
|
DebugLoc DL = MI.getDebugLoc();
|
||||||
|
|
||||||
|
unsigned DestReg = MI.getOperand(0).getReg();
|
||||||
|
const MachineOperand &Symbol = MI.getOperand(1);
|
||||||
|
|
||||||
|
MachineBasicBlock *NewMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
|
||||||
|
|
||||||
|
// Tell AsmPrinter that we unconditionally want the symbol of this label to be
|
||||||
|
// emitted.
|
||||||
|
NewMBB->setLabelMustBeEmitted();
|
||||||
|
|
||||||
|
MF->insert(++MBB.getIterator(), NewMBB);
|
||||||
|
|
||||||
|
BuildMI(NewMBB, DL, TII->get(RISCV::AUIPC), DestReg)
|
||||||
|
.addDisp(Symbol, 0, RISCVII::MO_PCREL_HI);
|
||||||
|
BuildMI(NewMBB, DL, TII->get(RISCV::ADDI), DestReg)
|
||||||
|
.addReg(DestReg)
|
||||||
|
.addMBB(NewMBB, RISCVII::MO_PCREL_LO);
|
||||||
|
|
||||||
|
// Move all the rest of the instructions to NewMBB.
|
||||||
|
NewMBB->splice(NewMBB->end(), &MBB, std::next(MBBI), MBB.end());
|
||||||
|
// Update machine-CFG edges.
|
||||||
|
NewMBB->transferSuccessorsAndUpdatePHIs(&MBB);
|
||||||
|
// Make the original basic block fall-through to the new.
|
||||||
|
MBB.addSuccessor(NewMBB);
|
||||||
|
|
||||||
|
// Make sure live-ins are correctly attached to this new basic block.
|
||||||
|
LivePhysRegs LiveRegs;
|
||||||
|
computeAndAddLiveIns(LiveRegs, *NewMBB);
|
||||||
|
|
||||||
|
NextMBBI = MBB.end();
|
||||||
|
MI.eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
|
||||||
INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
|
INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
|
||||||
|
|
|
@ -374,72 +374,90 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
|
||||||
|
SelectionDAG &DAG, unsigned Flags) {
|
||||||
|
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
|
||||||
|
SelectionDAG &DAG, unsigned Flags) {
|
||||||
|
return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
|
||||||
|
Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
|
||||||
|
SelectionDAG &DAG, unsigned Flags) {
|
||||||
|
return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(),
|
||||||
|
N->getOffset(), Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class NodeTy>
|
||||||
|
SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG) const {
|
||||||
|
SDLoc DL(N);
|
||||||
|
EVT Ty = getPointerTy(DAG.getDataLayout());
|
||||||
|
|
||||||
|
switch (getTargetMachine().getCodeModel()) {
|
||||||
|
default:
|
||||||
|
report_fatal_error("Unsupported code model for lowering");
|
||||||
|
case CodeModel::Small: {
|
||||||
|
// Generate a sequence for accessing addresses within the first 2 GiB of
|
||||||
|
// address space. This generates the pattern (addi (lui %hi(sym)) %lo(sym)).
|
||||||
|
SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_HI);
|
||||||
|
SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_LO);
|
||||||
|
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0);
|
||||||
|
return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0);
|
||||||
|
}
|
||||||
|
case CodeModel::Medium: {
|
||||||
|
// Generate a sequence for accessing addresses within any 2GiB range within
|
||||||
|
// the address space. This generates the pattern (PseudoLLA sym), which
|
||||||
|
// expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
|
||||||
|
SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
|
||||||
|
return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op,
|
SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
EVT Ty = Op.getValueType();
|
EVT Ty = Op.getValueType();
|
||||||
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
|
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
|
||||||
const GlobalValue *GV = N->getGlobal();
|
|
||||||
int64_t Offset = N->getOffset();
|
int64_t Offset = N->getOffset();
|
||||||
MVT XLenVT = Subtarget.getXLenVT();
|
MVT XLenVT = Subtarget.getXLenVT();
|
||||||
|
|
||||||
if (isPositionIndependent())
|
if (isPositionIndependent())
|
||||||
report_fatal_error("Unable to lowerGlobalAddress");
|
report_fatal_error("Unable to lowerGlobalAddress");
|
||||||
|
|
||||||
|
SDValue Addr = getAddr(N, DAG);
|
||||||
|
|
||||||
// In order to maximise the opportunity for common subexpression elimination,
|
// In order to maximise the opportunity for common subexpression elimination,
|
||||||
// emit a separate ADD node for the global address offset instead of folding
|
// emit a separate ADD node for the global address offset instead of folding
|
||||||
// it in the global address node. Later peephole optimisations may choose to
|
// it in the global address node. Later peephole optimisations may choose to
|
||||||
// fold it back in when profitable.
|
// fold it back in when profitable.
|
||||||
SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_HI);
|
|
||||||
SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_LO);
|
|
||||||
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0);
|
|
||||||
SDValue MNLo =
|
|
||||||
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0);
|
|
||||||
if (Offset != 0)
|
if (Offset != 0)
|
||||||
return DAG.getNode(ISD::ADD, DL, Ty, MNLo,
|
return DAG.getNode(ISD::ADD, DL, Ty, Addr,
|
||||||
DAG.getConstant(Offset, DL, XLenVT));
|
DAG.getConstant(Offset, DL, XLenVT));
|
||||||
return MNLo;
|
return Addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op,
|
SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
|
||||||
EVT Ty = Op.getValueType();
|
|
||||||
BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op);
|
BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op);
|
||||||
const BlockAddress *BA = N->getBlockAddress();
|
|
||||||
int64_t Offset = N->getOffset();
|
|
||||||
|
|
||||||
if (isPositionIndependent())
|
if (isPositionIndependent())
|
||||||
report_fatal_error("Unable to lowerBlockAddress");
|
report_fatal_error("Unable to lowerBlockAddress");
|
||||||
|
|
||||||
SDValue BAHi = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_HI);
|
return getAddr(N, DAG);
|
||||||
SDValue BALo = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_LO);
|
|
||||||
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, BAHi), 0);
|
|
||||||
SDValue MNLo =
|
|
||||||
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, BALo), 0);
|
|
||||||
return MNLo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op,
|
SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
|
||||||
EVT Ty = Op.getValueType();
|
|
||||||
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
|
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
|
||||||
const Constant *CPA = N->getConstVal();
|
|
||||||
int64_t Offset = N->getOffset();
|
|
||||||
unsigned Alignment = N->getAlignment();
|
|
||||||
|
|
||||||
if (!isPositionIndependent()) {
|
if (isPositionIndependent())
|
||||||
SDValue CPAHi =
|
|
||||||
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_HI);
|
|
||||||
SDValue CPALo =
|
|
||||||
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_LO);
|
|
||||||
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, CPAHi), 0);
|
|
||||||
SDValue MNLo =
|
|
||||||
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, CPALo), 0);
|
|
||||||
return MNLo;
|
|
||||||
} else {
|
|
||||||
report_fatal_error("Unable to lowerConstantPool");
|
report_fatal_error("Unable to lowerConstantPool");
|
||||||
}
|
|
||||||
|
return getAddr(N, DAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
|
SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
|
||||||
|
|
|
@ -141,6 +141,10 @@ private:
|
||||||
Type *Ty) const override {
|
Type *Ty) const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class NodeTy>
|
||||||
|
SDValue getAddr(NodeTy *N, SelectionDAG &DAG) const;
|
||||||
|
|
||||||
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
|
|
@ -438,6 +438,7 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
||||||
return 0;
|
return 0;
|
||||||
case RISCV::PseudoCALL:
|
case RISCV::PseudoCALL:
|
||||||
case RISCV::PseudoTAIL:
|
case RISCV::PseudoTAIL:
|
||||||
|
case RISCV::PseudoLLA:
|
||||||
return 8;
|
return 8;
|
||||||
case TargetOpcode::INLINEASM:
|
case TargetOpcode::INLINEASM:
|
||||||
case TargetOpcode::INLINEASM_BR: {
|
case TargetOpcode::INLINEASM_BR: {
|
||||||
|
|
|
@ -42,6 +42,12 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
|
||||||
case RISCVII::MO_HI:
|
case RISCVII::MO_HI:
|
||||||
Kind = RISCVMCExpr::VK_RISCV_HI;
|
Kind = RISCVMCExpr::VK_RISCV_HI;
|
||||||
break;
|
break;
|
||||||
|
case RISCVII::MO_PCREL_LO:
|
||||||
|
Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;
|
||||||
|
break;
|
||||||
|
case RISCVII::MO_PCREL_HI:
|
||||||
|
Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCExpr *ME =
|
const MCExpr *ME =
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum {
|
||||||
MO_None,
|
MO_None,
|
||||||
MO_LO,
|
MO_LO,
|
||||||
MO_HI,
|
MO_HI,
|
||||||
|
MO_PCREL_LO,
|
||||||
MO_PCREL_HI,
|
MO_PCREL_HI,
|
||||||
};
|
};
|
||||||
} // namespace RISCVII
|
} // namespace RISCVII
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||||
|
; RUN: llc -mtriple=riscv32 -mattr=+f -code-model=small -verify-machineinstrs < %s \
|
||||||
|
; RUN: | FileCheck %s -check-prefix=RV32I-SMALL
|
||||||
|
; RUN: llc -mtriple=riscv32 -mattr=+f -code-model=medium -verify-machineinstrs < %s \
|
||||||
|
; RUN: | FileCheck %s -check-prefix=RV32I-MEDIUM
|
||||||
|
|
||||||
|
; Check lowering of globals
|
||||||
|
@G = global i32 0
|
||||||
|
|
||||||
|
define i32 @lower_global(i32 %a) nounwind {
|
||||||
|
; RV32I-SMALL-LABEL: lower_global:
|
||||||
|
; RV32I-SMALL: # %bb.0:
|
||||||
|
; RV32I-SMALL-NEXT: lui a0, %hi(G)
|
||||||
|
; RV32I-SMALL-NEXT: lw a0, %lo(G)(a0)
|
||||||
|
; RV32I-SMALL-NEXT: ret
|
||||||
|
;
|
||||||
|
; RV32I-MEDIUM-LABEL: lower_global:
|
||||||
|
; RV32I-MEDIUM: # %bb.0:
|
||||||
|
; RV32I-MEDIUM-NEXT: .LBB0_1: # Label of block must be emitted
|
||||||
|
; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(G)
|
||||||
|
; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB0_1)
|
||||||
|
; RV32I-MEDIUM-NEXT: lw a0, 0(a0)
|
||||||
|
; RV32I-MEDIUM-NEXT: ret
|
||||||
|
%1 = load volatile i32, i32* @G
|
||||||
|
ret i32 %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check lowering of blockaddresses
|
||||||
|
|
||||||
|
@addr = global i8* null
|
||||||
|
|
||||||
|
define void @lower_blockaddress() nounwind {
|
||||||
|
; RV32I-SMALL-LABEL: lower_blockaddress:
|
||||||
|
; RV32I-SMALL: # %bb.0:
|
||||||
|
; RV32I-SMALL-NEXT: lui a0, %hi(addr)
|
||||||
|
; RV32I-SMALL-NEXT: addi a1, zero, 1
|
||||||
|
; RV32I-SMALL-NEXT: sw a1, %lo(addr)(a0)
|
||||||
|
; RV32I-SMALL-NEXT: ret
|
||||||
|
;
|
||||||
|
; RV32I-MEDIUM-LABEL: lower_blockaddress:
|
||||||
|
; RV32I-MEDIUM: # %bb.0:
|
||||||
|
; RV32I-MEDIUM-NEXT: .LBB1_1: # Label of block must be emitted
|
||||||
|
; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(addr)
|
||||||
|
; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB1_1)
|
||||||
|
; RV32I-MEDIUM-NEXT: addi a1, zero, 1
|
||||||
|
; RV32I-MEDIUM-NEXT: sw a1, 0(a0)
|
||||||
|
; RV32I-MEDIUM-NEXT: ret
|
||||||
|
store volatile i8* blockaddress(@lower_blockaddress, %block), i8** @addr
|
||||||
|
ret void
|
||||||
|
|
||||||
|
block:
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check lowering of constantpools
|
||||||
|
|
||||||
|
define float @lower_constantpool(float %a) nounwind {
|
||||||
|
; RV32I-SMALL-LABEL: lower_constantpool:
|
||||||
|
; RV32I-SMALL: # %bb.0:
|
||||||
|
; RV32I-SMALL-NEXT: fmv.w.x ft0, a0
|
||||||
|
; RV32I-SMALL-NEXT: lui a0, %hi(.LCPI2_0)
|
||||||
|
; RV32I-SMALL-NEXT: addi a0, a0, %lo(.LCPI2_0)
|
||||||
|
; RV32I-SMALL-NEXT: flw ft1, 0(a0)
|
||||||
|
; RV32I-SMALL-NEXT: fadd.s ft0, ft0, ft1
|
||||||
|
; RV32I-SMALL-NEXT: fmv.x.w a0, ft0
|
||||||
|
; RV32I-SMALL-NEXT: ret
|
||||||
|
;
|
||||||
|
; RV32I-MEDIUM-LABEL: lower_constantpool:
|
||||||
|
; RV32I-MEDIUM: # %bb.0:
|
||||||
|
; RV32I-MEDIUM-NEXT: .LBB2_1: # Label of block must be emitted
|
||||||
|
; RV32I-MEDIUM-NEXT: auipc a1, %pcrel_hi(.LCPI2_0)
|
||||||
|
; RV32I-MEDIUM-NEXT: addi a1, a1, %pcrel_lo(.LBB2_1)
|
||||||
|
; RV32I-MEDIUM-NEXT: flw ft0, 0(a1)
|
||||||
|
; RV32I-MEDIUM-NEXT: fmv.w.x ft1, a0
|
||||||
|
; RV32I-MEDIUM-NEXT: fadd.s ft0, ft1, ft0
|
||||||
|
; RV32I-MEDIUM-NEXT: fmv.x.w a0, ft0
|
||||||
|
; RV32I-MEDIUM-NEXT: ret
|
||||||
|
%1 = fadd float %a, 1.0
|
||||||
|
ret float %1
|
||||||
|
}
|
Loading…
Reference in New Issue