diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -498,6 +498,14 @@ void emitAlignment(Align Alignment, const GlobalObject *GV = nullptr, unsigned MaxBytesToEmit = 0) const; + /// Constant-fold Constant as neened to allow it to be emitted into assembly. + /// By default, this calls ConstantFoldConstant(), which should be sufficient, + /// but this hook is provided to allow targets to define additional constant + /// folding rules that cannot be defined in `lowerConstant`. For example, + /// on AMDGPU, casting the null pointer to addrspace(7) yields a 128-bit + /// null descriptor that can't fit into MCExpr. + virtual Constant *constantFoldForPrint(const Constant *CV); + /// Lower the specified LLVM Constant to an MCExpr. virtual const MCExpr *lowerConstant(const Constant *CV); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2852,6 +2852,10 @@ // Constant emission. //===----------------------------------------------------------------------===// +Constant *AsmPrinter::constantFoldForPrint(const Constant *CV) { + return ConstantFoldConstant(CV, getDataLayout()); +} + const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { MCContext &Ctx = OutContext; @@ -2995,7 +2999,7 @@ // If the code isn't optimized, there may be outstanding folding // opportunities. Attempt to fold the expression using DataLayout as a // last resort before giving up. - Constant *C = ConstantFoldConstant(CE, getDataLayout()); + Constant *C = constantFoldForPrint(CE); if (C != CE) return lowerConstant(C); @@ -3447,6 +3451,12 @@ return emitGlobalConstantFP(CFP, AP); if (isa(CV)) { + if (Size > 8) { + // Not always used in order to preserve backwards compatibility while + // allowing for large pointers. + AP.OutStreamer->emitZeros(Size); + return; + } AP.OutStreamer->emitIntValue(0, Size); return; } @@ -3470,7 +3480,7 @@ // If the constant expression's size is greater than 64-bits, then we have // to emit the value in chunks. Try to constant fold the value and emit it // that way. - Constant *New = ConstantFoldConstant(CE, DL); + Constant *New = AP.constantFoldForPrint(CE); if (New != CE) return emitGlobalConstantImpl(DL, New, AP); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h --- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h @@ -99,6 +99,11 @@ /// pseudo lowering. bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; + /// Lower a cast of the null pointer to address space 7, which produces a + /// 128-bit null buffer descriptor, to a null constant value, because 128-bit + /// values do not fit in MCExpr. + Constant *constantFoldForPrint(const Constant *CV) override; + /// Lower the specified LLVM Constant to an MCExpr. /// The AsmPrinter::lowerConstantof does not know how to lower /// addrspacecast, therefore they should be lowered by this function. diff --git a/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp b/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp @@ -165,6 +165,23 @@ return MCInstLowering.lowerOperand(MO, MCOp); } +Constant *AMDGPUAsmPrinter::constantFoldForPrint(const Constant *CV) { + // TargetMachine does not support llvm-style cast. Use C++-style cast. + // This is safe since TM is always of type AMDGPUTargetMachine or its + // derived class. + auto &AT = static_cast(TM); + auto *CE = dyn_cast(CV); + if (CE && CE->getOpcode() == Instruction::AddrSpaceCast) { + auto *Op = CE->getOperand(0); + auto SrcAddr = Op->getType()->getPointerAddressSpace(); + auto DstAddr = CE->getType()->getPointerAddressSpace(); + if (Op->isNullValue() && AT.getNullPointerValue(SrcAddr) == 0 && + AT.getPointerSizeInBits(DstAddr) > 64) + return ConstantPointerNull::get(cast(CE->getType())); + } + return AsmPrinter::constantFoldForPrint(CV); +} + const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) { // Intercept LDS variables with known addresses