diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index fe450b3c1a3a2..604febc16454c 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -63,13 +63,14 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { /// Given a constant with the SectionKind, return a section that it should be /// placed in. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; /// Similar to the function above, but append \p SectionSuffix to the section /// name. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F, StringRef SectionSuffix) const override; MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, @@ -152,8 +153,8 @@ class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { const TargetMachine &TM) const override; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; /// The mach-o version of this method defaults to returning a stub reference. const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, @@ -221,8 +222,8 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { /// Given a mergeable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; }; class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { @@ -283,8 +284,8 @@ class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile { /// Given a constant with the SectionKind, return a section that it should be /// placed in. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; static XCOFF::StorageClass getStorageClassForGlobal(const GlobalValue *GV); diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 397239b1685fb..e462b56ca4d8b 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -106,13 +106,14 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo { /// placed in. virtual MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const; + Align &Alignment, + const Function *F) const; /// Similar to the function above, but append \p SectionSuffix to the section /// name. virtual MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment, + Align &Alignment, const Function *F, StringRef SectionSuffix) const; virtual MCSection * diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 616627183744e..93bc6605fb2d0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2893,7 +2893,8 @@ void AsmPrinter::emitConstantPool() { C = CPE.Val.ConstVal; MCSection *S = getObjFileLowering().getSectionForConstant( - getDataLayout(), Kind, C, Alignment, getConstantSectionSuffix(C)); + getDataLayout(), Kind, C, Alignment, &MF->getFunction(), + getConstantSectionSuffix(C)); // The number of sections are small, just do a linear search from the // last section to the first. @@ -4221,8 +4222,8 @@ MCSymbol *AsmPrinter::GetCPISymbol(unsigned CPID) const { SectionKind Kind = CPE.getSectionKind(&DL); const Constant *C = CPE.Val.ConstVal; Align Alignment = CPE.Alignment; - auto *S = - getObjFileLowering().getSectionForConstant(DL, Kind, C, Alignment); + auto *S = getObjFileLowering().getSectionForConstant( + DL, Kind, C, Alignment, &MF->getFunction()); if (S && TM.getTargetTriple().isOSBinFormatCOFF()) { if (MCSymbol *Sym = static_cast(S)->getCOMDATSymbol()) { diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index e9172f4acb0cb..8392ec420d91f 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1033,8 +1033,8 @@ bool TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection( /// Given a mergeable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *TargetLoweringObjectFileELF::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (Kind.isMergeableConst4() && MergeableConst4Section) return MergeableConst4Section; if (Kind.isMergeableConst8() && MergeableConst8Section) @@ -1052,11 +1052,11 @@ MCSection *TargetLoweringObjectFileELF::getSectionForConstant( MCSection *TargetLoweringObjectFileELF::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, - StringRef SectionSuffix) const { + const Function *F, StringRef SectionSuffix) const { // TODO: Share code between this function and // MCObjectInfo::initELFMCObjectFileInfo. if (SectionSuffix.empty()) - return getSectionForConstant(DL, Kind, C, Alignment); + return getSectionForConstant(DL, Kind, C, Alignment, F); auto &Context = getContext(); if (Kind.isMergeableConst4() && MergeableConst4Section) @@ -1469,8 +1469,8 @@ MCSection *TargetLoweringObjectFileMachO::SelectSectionForGlobal( } MCSection *TargetLoweringObjectFileMachO::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { // If this constant requires a relocation, we have to put it in the data // segment, not in the text segment. if (Kind.isData() || Kind.isReadOnlyWithRel()) @@ -2132,8 +2132,8 @@ static std::string scalarConstantToHexString(const Constant *C) { } MCSection *TargetLoweringObjectFileCOFF::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (Kind.isMergeableConst() && C && getContext().getAsmInfo()->hasCOFFComdatConstants()) { // This creates comdat sections with the given symbol name, but unless @@ -2173,8 +2173,8 @@ MCSection *TargetLoweringObjectFileCOFF::getSectionForConstant( COFF::IMAGE_COMDAT_SELECT_ANY); } - return TargetLoweringObjectFile::getSectionForConstant(DL, Kind, C, - Alignment); + return TargetLoweringObjectFile::getSectionForConstant(DL, Kind, C, Alignment, + F); } //===----------------------------------------------------------------------===// @@ -2595,8 +2595,8 @@ bool TargetLoweringObjectFileXCOFF::shouldPutJumpTableInFunctionSection( /// Given a mergeable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *TargetLoweringObjectFileXCOFF::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { // TODO: Enable emiting constant pool to unique sections when we support it. if (Alignment > Align(16)) report_fatal_error("Alignments greater than 16 not yet supported."); diff --git a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp index 118689b034c36..472ee41b35599 100644 --- a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp +++ b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp @@ -114,12 +114,12 @@ bool LanaiTargetObjectFile::isConstantInSmallSection(const DataLayout &DL, } MCSection *LanaiTargetObjectFile::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (isConstantInSmallSection(DL, C)) return SmallDataSection; // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, - Alignment); + Alignment, F); } diff --git a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h index 404349465dbcb..ade56f9d6bccf 100644 --- a/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h +++ b/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h @@ -36,8 +36,8 @@ class LanaiTargetObjectFile : public TargetLoweringObjectFileELF { bool isConstantInSmallSection(const DataLayout &DL, const Constant *CN) const; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; }; } // end namespace llvm diff --git a/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp b/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp index 78a9f3b7cc71b..ba01d7b1e58c9 100644 --- a/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp +++ b/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -172,16 +172,15 @@ bool MipsTargetObjectFile::IsConstantInSmallSection( } /// Return true if this constant should be placed into small data section. -MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL, - SectionKind Kind, - const Constant *C, - Align &Alignment) const { +MCSection *MipsTargetObjectFile::getSectionForConstant( + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (IsConstantInSmallSection(DL, C, *TM)) return SmallDataSection; // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, - Alignment); + Alignment, F); } const MCExpr * diff --git a/llvm/lib/Target/Mips/MipsTargetObjectFile.h b/llvm/lib/Target/Mips/MipsTargetObjectFile.h index 07e9caf0dd092..bc2377ffcf9b6 100644 --- a/llvm/lib/Target/Mips/MipsTargetObjectFile.h +++ b/llvm/lib/Target/Mips/MipsTargetObjectFile.h @@ -39,8 +39,8 @@ class MipsTargetMachine; const TargetMachine &TM) const; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; /// Describe a TLS variable address within debug info. const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override; }; diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h b/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h index 6b68e79fabc29..d62e3a1acf7bc 100644 --- a/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h +++ b/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h @@ -22,8 +22,8 @@ class NVPTXTargetObjectFile : public TargetLoweringObjectFile { ~NVPTXTargetObjectFile() override; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override { + const Constant *C, Align &Alignment, + const Function *F) const override { return ReadOnlySection; } diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp index bc90cf8f53aba..1d78f705ba67e 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp @@ -159,8 +159,20 @@ bool RISCVELFTargetObjectFile::isConstantInSmallSection( } MCSection *RISCVELFTargetObjectFile::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { + + // The large code model has to put constant pools close to the program, so we + // put them in the .text section. Large code model doesn't support PIC, so + // there should be no dynamic relocations that would require `.data.rel.ro` + // (which could be too far away anyway). + if (TM->getCodeModel() == CodeModel::Large) { + if (F) + return SectionForGlobal(F, SectionKind::getText(), *TM); + else + return TextSection; + } + if (C && isConstantInSmallSection(DL, C)) { if (Kind.isMergeableConst4()) return SmallROData4Section; @@ -177,5 +189,5 @@ MCSection *RISCVELFTargetObjectFile::getSectionForConstant( // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, - Alignment); + Alignment, F); } diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h index ff7e3e4c752c3..ad24e16e98ecb 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h @@ -41,8 +41,8 @@ class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF { bool isConstantInSmallSection(const DataLayout &DL, const Constant *CN) const; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; void getModuleMetadata(Module &M) override; diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h b/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h index 00c456971ef10..078af7b22d8ae 100644 --- a/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h +++ b/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h @@ -26,8 +26,8 @@ class SPIRVTargetObjectFile : public TargetLoweringObjectFile { // sequence of instructions in a specific order. We put all the instructions // in the single text section. MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override { + const Constant *C, Align &Alignment, + const Function *F) const override { return TextSection; } MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp index 9b03e85ca45bf..602dd9fa529c5 100644 --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -383,9 +383,8 @@ MCSection *TargetLoweringObjectFile::getSectionForJumpTable( const Function &F, const TargetMachine &TM, const MachineJumpTableEntry *JTE) const { Align Alignment(1); - return getSectionForConstant(F.getDataLayout(), - SectionKind::getReadOnly(), /*C=*/nullptr, - Alignment); + return getSectionForConstant(F.getDataLayout(), SectionKind::getReadOnly(), + /*C=*/nullptr, Alignment, &F); } bool TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection( @@ -406,8 +405,8 @@ bool TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection( /// Given a mergable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *TargetLoweringObjectFile::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (Kind.isReadOnly() && ReadOnlySection != nullptr) return ReadOnlySection; @@ -416,11 +415,11 @@ MCSection *TargetLoweringObjectFile::getSectionForConstant( MCSection *TargetLoweringObjectFile::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, - StringRef SectionPrefix) const { + const Function *F, StringRef SectionPrefix) const { // Fallback to `getSectionForConstant` without `SectionPrefix` parameter if it // is empty. if (SectionPrefix.empty()) - return getSectionForConstant(DL, Kind, C, Alignment); + return getSectionForConstant(DL, Kind, C, Alignment, F); report_fatal_error( "TargetLoweringObjectFile::getSectionForConstant that " "accepts SectionPrefix is not implemented for the object file format"); diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index d406277e440bb..d36838c2be264 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -1093,7 +1093,7 @@ void X86AsmPrinter::emitEndOfAsmFile(Module &M) { Align Alignment(1); MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant( getDataLayout(), SectionKind::getReadOnly(), - /*C=*/nullptr, Alignment); + /*C=*/nullptr, Alignment, /*F=*/nullptr); OutStreamer->switchSection(ReadOnlySection); OutStreamer->emitLabel(AddrSymbol); diff --git a/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp b/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp index d0f9cce105e14..5a8a4d396a1da 100644 --- a/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp +++ b/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp @@ -141,8 +141,8 @@ MCSection *XCoreTargetObjectFile::SelectSectionForGlobal( } MCSection *XCoreTargetObjectFile::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - Align &Alignment) const { + const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment, + const Function *F) const { if (Kind.isMergeableConst4()) return MergeableConst4Section; if (Kind.isMergeableConst8()) return MergeableConst8Section; if (Kind.isMergeableConst16()) return MergeableConst16Section; diff --git a/llvm/lib/Target/XCore/XCoreTargetObjectFile.h b/llvm/lib/Target/XCore/XCoreTargetObjectFile.h index 73cc6686d7755..f9b895795c94a 100644 --- a/llvm/lib/Target/XCore/XCoreTargetObjectFile.h +++ b/llvm/lib/Target/XCore/XCoreTargetObjectFile.h @@ -31,8 +31,8 @@ static const unsigned CodeModelLargeSize = 256; const TargetMachine &TM) const override; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - Align &Alignment) const override; + const Constant *C, Align &Alignment, + const Function *F) const override; }; } // end namespace llvm diff --git a/llvm/test/CodeGen/RISCV/large-codemodel-sections.ll b/llvm/test/CodeGen/RISCV/large-codemodel-sections.ll new file mode 100644 index 0000000000000..c44c445cd68ed --- /dev/null +++ b/llvm/test/CodeGen/RISCV/large-codemodel-sections.ll @@ -0,0 +1,104 @@ +; RUN: llc -mtriple=riscv64 -mattr=+f,+zfh -target-abi=lp64f -code-model=large -verify-machineinstrs < %s \ +; RUN: -filetype=obj -o - | llvm-readobj -r - \ +; RUN: | FileCheck %s +; RUN: llc -mtriple=riscv64 -mattr=+zfinx,+zhinx -target-abi=lp64 -code-model=large -verify-machineinstrs < %s \ +; RUN: -filetype=obj -o - | llvm-readobj -r - \ +; RUN: | FileCheck %s +; RUN: llc -mtriple=riscv64 -mattr=+f,+zfh -target-abi=lp64f -code-model=large -verify-machineinstrs --function-sections < %s \ +; RUN: -filetype=obj -o - | llvm-readobj -r - \ +; RUN: | FileCheck %s --check-prefix=FUNCSEC + + +;; This tests that we are lowering large code model constants into `.text` +;; constant pools, so that accessing them is close to `.text`, rather than +;; far away in `.data`. The other choices are `.rodata` and `.data.rel.ro`, +;; both of which may not be close enough to `.text` to be referenced. +;; +;; The test uses `readobj` to check that there are relocations against the +;; `.text` section for these addresses. This is not compatible with PIC, +;; just like the rest of the large code model. + +; CHECK: Section (3) .rela.text { +; CHECK-NEXT: R_RISCV_64 G 0x0 +; CHECK-NEXT: R_RISCV_64 addr 0x0 +; CHECK-NEXT: R_RISCV_64 W 0x0 +; CHECK-NEXT: R_RISCV_64 X 0x0 +; CHECK-NEXT: } + +; FUNCSEC: Section (4) .rela.text.lower_global { +; FUNCSEC-NEXT: 0x0 R_RISCV_64 G 0x0 +; FUNCSEC-NEXT: } +; FUNCSEC: Section (6) .rela.text.lower_blockaddress { +; FUNCSEC-NEXT: 0x0 R_RISCV_64 addr 0x0 +; FUNCSEC-NEXT: } +; FUNCSEC: Section (10) .rela.text.lower_extern_weak { +; FUNCSEC-NEXT: 0x0 R_RISCV_64 W 0x0 +; FUNCSEC-NEXT: } +; FUNCSEC: Section (12) .rela.text.lower_global_half { +; FUNCSEC-NEXT: 0x0 R_RISCV_64 X 0x0 +; FUNCSEC-NEXT: } + +; Check lowering of globals +@G = global i32 0 +define i32 @lower_global(i32 %a) nounwind { + %1 = load volatile i32, ptr @G + ret i32 %1 +} + +; Check lowering of blockaddresses +@addr = global ptr null +define void @lower_blockaddress() nounwind { + store volatile ptr blockaddress(@lower_blockaddress, %block), ptr @addr + ret void + +block: + unreachable +} + +; Check lowering of blockaddress that forces a displacement to be added +define signext i32 @lower_blockaddress_displ(i32 signext %w) nounwind { +entry: + %x = alloca ptr, align 8 + store ptr blockaddress(@lower_blockaddress_displ, %test_block), ptr %x, align 8 + %cmp = icmp sgt i32 %w, 100 + br i1 %cmp, label %if.then, label %if.end + +if.then: + %addr = load ptr, ptr %x, align 8 + br label %indirectgoto + +if.end: + br label %return + +test_block: + br label %return + +return: + %retval = phi i32 [ 3, %if.end ], [ 4, %test_block ] + ret i32 %retval + +indirectgoto: + indirectbr ptr %addr, [ label %test_block ] +} + +; Check lowering of constantpools +define float @lower_constantpool(float %a) nounwind { + %1 = fadd float %a, 1.000244140625 + ret float %1 +} + +; Check lowering of extern_weaks +@W = extern_weak global i32 + +define i32 @lower_extern_weak(i32 %a) nounwind { + %1 = load volatile i32, ptr @W + ret i32 %1 +} + +@X = global half 1.5 + +define half @lower_global_half(half %a) nounwind { + %b = load half, ptr @X + %1 = fadd half %a, %b + ret half %1 +}