================ @@ -0,0 +1,934 @@ +//===-- PISAAsmPrinter.cpp - PISA LLVM assembly writer --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PISAInstPrinter.h" +#include "MCTargetDesc/PISARegEncoder.h" +#include "MCTargetDesc/PISATargetStreamer.h" +#include "PISA.h" +#include "PISAInstrInfo.h" +#include "PISAMCInstLower.h" +#include "PISAMachineFunctionInfo.h" +#include "PISARegManager.h" +#include "PISASubtarget.h" +#include "PISATargetMachine.h" +#include "PISAUtils.h" +#include "TargetInfo/PISATargetInfo.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/PISAAddrSpace.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/PISATargetParser.h" +#include <llvm/IR/DiagnosticInfo.h> + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { +class PISAAsmPrinter : public AsmPrinter { + +public: + PISATargetStreamer &getTargetStreamer() const { + return static_cast<PISATargetStreamer &>(*OutStreamer->getTargetStreamer()); + } + +private: + void collectRegDcls(PISA::RegDcls &); + void collectLocalVariableDcls(PISA::LocalVariableDcls &); + void updateFuncParamIdxs(PISA::DataTypes &DTs); + + void outputInstruction(const MachineInstr *MI); + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + + std::string getVirtualRegisterName(Register R) const; + + void collectFunctionDeclaration(PISA::FunctionDeclaration &, + const Function &F); + void collectFunctionSignature(PISA::FunctionSignature &); + void collectFunctionParameters(PISA::FunctionSignature &); + void collectKernelParameters(PISA::FunctionSignature &); + void collectFunctionDirectiveAndName(PISA::FunctionDirectiveAndName &DN, + const Function &F); + PISA::LinkageTy collectLinkage(const GlobalValue &V); + void collectGlobalVariable(PISA::GlobalVariableDcl &PGV, + const GlobalVariable &GV); + + void emitGlobalsAndFuncDecls(Module &M); + + const PISASubtarget *ST = nullptr; + const PISAInstrInfo *TII = nullptr; + const PISARegisterInfo *TRI = nullptr; + PISA::RegManager *RegMgr = nullptr; + PISA::DataTypes *DTs = nullptr; + bool GlobalsEmitted = false; + + class FlattenGlobal { + public: + FlattenGlobal(const Constant *C, PISA::VariableInit &VI, + const DataLayout &DL, AsmPrinter &AP) + : DL(DL), VI(VI), AP(AP) { + process(C); + dischargeZeros(); + assert(computeSize(C) == DL.getTypeAllocSize(C->getType()) && + "size mismatch?"); + } + + private: + bool isZero(const Constant *C) const { + if (isa<ConstantPointerNull>(C)) + return false; + + return C->isNullValue() || isa<UndefValue>(C); + } + void pad(const Constant *C, unsigned NumElts = 0) { + unsigned Size = DL.getTypeAllocSize(C->getType()); + if (NumElts == 0) { + ZeroCnt += Size; + return; + } + unsigned EmittedSize = + DL.getTypeAllocSize(C->getType()->getContainedType(0)) * NumElts; + assert(EmittedSize <= Size && "Size cannot be less than EmittedSize!"); + if (unsigned Padding = Size - EmittedSize) + ZeroCnt += Padding; + } + void pad(uint64_t NumBytes) { ZeroCnt += NumBytes; } + void dischargeZeros() { + if (ZeroCnt == 0) + return; + // Insert dummy slot + VI.Initializer.push_back({LLT{}, 0}); + uint64_t Idx = VI.Initializer.size() - 1; + VI.Exprs.insert({Idx, PISA::VariableInit::Zeros{ZeroCnt}}); + ZeroCnt = 0; + } + void addVal(LLT Ty, uint64_t Val) { + dischargeZeros(); + VI.Initializer.push_back({Ty, Val}); + } + void addGlobal(LLT Ty, const PISA::VariableInit::GlobalExpr &GE) { + // Insert dummy slot + addVal(Ty, 0); + uint64_t Idx = VI.Initializer.size() - 1; + VI.Exprs.insert({Idx, GE}); + } + void lowerConstant(const Constant *C) { + auto *Expr = AP.lowerConstant(C); + MCValue Res; + if (!Expr->evaluateAsRelocatable(Res, nullptr)) + llvm_unreachable("unhandled expression!"); + LLT Ty = getLLTForType(*C->getType(), DL); + if (!Res.getAddSym() && !Res.getSubSym()) { + if (Res.getConstant() == 0) + pad(C); + else + addVal(Ty, static_cast<uint64_t>(Res.getConstant())); + return; + } + assert(!Res.getSubSym() && "unhandled expression!"); + std::string Name = Res.getAddSym()->getName().str(); + PISA::VariableInit::GlobalExpr E{std::move(Name), Res.getConstant()}; + addGlobal(Ty, E); + } + uint64_t computeSize(const Constant *C) const { + uint64_t Total = 0; + for (auto [i, Elt] : llvm::enumerate(VI.Initializer)) { + if (auto Iter = VI.Exprs.find(i); Iter != VI.Exprs.end()) { + auto &Entry = Iter->second; + if (auto *Z = std::get_if<PISA::VariableInit::Zeros>(&Entry)) { + Total += Z->N; + continue; + } + } + Total += Elt.Type.getSizeInBytes(); + } + return Total; + } + void emitGlobalConstantLargeInt(const ConstantInt *CI) { + unsigned BitWidth = CI->getBitWidth(); + + // Copy the value as we may massage the layout for constants whose bit + // width is not a multiple of 64-bits. + APInt Realigned(CI->getValue()); + uint64_t ExtraBits = 0; + unsigned ExtraBitsSize = BitWidth & 63; + + if (ExtraBitsSize) { + // The bit width of the data is not a multiple of 64-bits. + // The extra bits are expected to be at the end of the chunk of the + // memory. Little endian: + // * Nothing to be done, just record the extra bits to emit. + ExtraBits = Realigned.getRawData()[BitWidth / 64]; + } + + // We don't expect assemblers to support integer data directives + // for more than 64 bits, so we emit the data in at most 64-bit + // quantities at a time. + const uint64_t *RawData = Realigned.getRawData(); + for (unsigned I = 0, E = BitWidth / 64; I != E; ++I) + addVal(LLT::integer(64), RawData[I]); + + if (ExtraBitsSize) { + // Emit the extra bits after the 64-bits chunks. + // Emit a directive that fills the expected size. + uint64_t Size = DL.getTypeStoreSize(CI->getType()); + Size -= (BitWidth / 64) * 8; + assert(Size && Size * 8 >= ExtraBitsSize && + (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize))) == + ExtraBits && + "Directive too small for extra bits."); + addVal(LLT::integer(Size * 8), ExtraBits); + } + } + const DataLayout &DL; + PISA::VariableInit &VI; + AsmPrinter &AP; + void process(const Constant *C); + unsigned ZeroCnt = 0; + }; + +protected: + bool doInitialization(Module &M) override; + bool doFinalization(Module &M) override; + +public: + explicit PISAAsmPrinter(TargetMachine &TM, + std::unique_ptr<MCStreamer> Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + + StringRef getPassName() const override { return "PISA Assembly Printer"; } + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &O) override; + + void emitInstruction(const MachineInstr *MI) override; + void emitFunctionHeader() override; + void emitFunctionBodyStart() override; + void emitFunctionBodyEnd() override; + void emitEndOfAsmFile(Module &) override; + + void emitFunctionEntryLabel() override {} + void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {} + void emitGlobalVariable(const GlobalVariable *GV) override {} + + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // namespace + +void PISAAsmPrinter::FlattenGlobal::process(const Constant *C) { + uint64_t Size = DL.getTypeAllocSize(C->getType()); + if (isZero(C)) + return pad(C); + auto AddSplatVector = [&](LLT ScalarTy, const APInt &EltVal) { + assert(EltVal.getBitWidth() <= 64 && "Splat element too wide for uint64_t"); + auto *VTy = cast<FixedVectorType>(C->getType()); + unsigned NumElts = VTy->getNumElements(); + uint64_t Val = EltVal.getZExtValue(); + for (unsigned I = 0; I < NumElts; ++I) + addVal(ScalarTy, Val); + pad(C, NumElts); + }; + + if (auto *CI = dyn_cast<ConstantInt>(C)) { + if (C->getType()->isVectorTy()) { + auto *VTy = cast<FixedVectorType>(C->getType()); + uint64_t EltAllocSize = DL.getTypeAllocSize(VTy->getElementType()); + LLT ScalarTy = LLT::integer(EltAllocSize * 8); + AddSplatVector(ScalarTy, CI->getValue()); + } else { + // We don't use the LLT type of `C` directly here because `C` could be, + // for example, a s1. The allocation size is 1, so we want to give it + // a type of s8 to reflect that. + addVal(LLT::integer(Size * 8), CI->getZExtValue()); + } + } else if (auto *FP = dyn_cast<ConstantFP>(C)) { + if (C->getType()->isVectorTy()) { + auto *VTy = cast<FixedVectorType>(C->getType()); + LLT ScalarTy = getLLTForType(*VTy->getElementType(), DL); + AddSplatVector(ScalarTy, FP->getValueAPF().bitcastToAPInt()); + } else { + LLT Ty = getLLTForType(*C->getType(), DL); + addVal(Ty, FP->getValueAPF().bitcastToAPInt().getZExtValue()); + } + } else if (isa<ConstantPointerNull>(C)) { + LLT Ty = getLLTForType(*C->getType(), DL); + unsigned AS = C->getType()->getPointerAddressSpace(); + if (uint64_t Val = PISATargetMachine::getNullPointerValue(AS)) + addVal(Ty, Val); + else + pad(C); + } else if (auto *CV = dyn_cast<ConstantVector>(C)) { + Type *ElementType = CV->getType()->getElementType(); + uint64_t ElementSizeInBits = DL.getTypeSizeInBits(ElementType); + uint64_t ElementAllocSizeInBits = DL.getTypeAllocSizeInBits(ElementType); + if (ElementSizeInBits != ElementAllocSizeInBits) { + // If the allocation size of an element is different from the size in + // bits, printing each element separately will insert incorrect padding. + // + // The general algorithm here is complicated; instead of writing it out + // here, just use the existing code in ConstantFolding. + Type *IntT = IntegerType::get(CV->getContext(), + DL.getTypeSizeInBits(CV->getType())); + ConstantInt *CI = dyn_cast_or_null<ConstantInt>(ConstantFoldConstant( + ConstantExpr::getBitCast(const_cast<ConstantVector *>(CV), IntT), + DL)); + if (!CI) { + report_fatal_error( + "Cannot lower vector global with unusual element type"); + } + emitGlobalConstantLargeInt(CI); + uint64_t EmittedSize = DL.getTypeStoreSize(CV->getType()); + if (unsigned Padding = Size - EmittedSize) + pad(Padding); + } else { + for (unsigned I = 0; I < CV->getNumOperands(); I++) + process(CV->getAggregateElement(I)); + pad(C, CV->getNumOperands()); + } + } else if (auto *CA = dyn_cast<ConstantArray>(C)) { + for (unsigned I = 0; I < CA->getNumOperands(); I++) + process(CA->getAggregateElement(I)); + } else if (auto *CS = dyn_cast<ConstantStruct>(C)) { + auto *StructTy = cast<StructType>(CS->getType()); + auto *Layout = DL.getStructLayout(StructTy); + for (unsigned I = 0, E = CS->getNumOperands(); I != E; ++I) { + const Constant *Field = CS->getOperand(I); + // Print the actual field value. + process(Field); + // Check if padding is needed and insert one or more 0s. + uint64_t FieldSize = DL.getTypeAllocSize(Field->getType()); + uint64_t PadSize = + ((I == E - 1 ? Size : Layout->getElementOffset(I + 1)) - + Layout->getElementOffset(I)) - + FieldSize; + // Insert padding - this may include padding to increase the size of the + // current field up to the ABI size (if the struct is not packed) as well + // as padding to ensure that the next field starts at the right offset. + pad(PadSize); + } + } else if (auto *CDS = dyn_cast<ConstantDataSequential>(C)) { + for (unsigned I = 0; I < CDS->getNumElements(); I++) + process(CDS->getElementAsConstant(I)); + pad(C, CDS->getNumElements()); + } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { + // Look through bitcasts, which might not be able to be MCExpr'ized (e.g. + // of vectors). + if (CE->getOpcode() == Instruction::BitCast) + return process(CE->getOperand(0)); + if (Size > 8) { + // 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); + if (New != CE) + return process(New); + } + lowerConstant(C); + } else if (isa<GlobalVariable>(C) || isa<Function>(C)) { + assert(Size == 8 && "global symbol with non 64-bit size?"); + lowerConstant(C); + } else { + llvm_unreachable("unhandled constant!"); + } +} + +static bool isIgnoredIntrinsicGlobal(const GlobalVariable &GV) { + if (GV.getName() == "llvm.used") + return true; + + // Ignore debug and non-emitted data. This handles llvm.compiler.used. + if (GV.getSection() == "llvm.metadata") + return true; + + // Skip globals only used as annotation strings by llvm.ptr.annotation. + // These are metadata for the annotation intrinsic, not real data. + if (GV.hasPrivateLinkage() && GV.isConstant() && + all_of(GV.users(), [](const User *U) { ---------------- arsenm wrote:
You shouldn't have to scan over all users, this is also untested https://github.com/llvm/llvm-project/pull/214647 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
