From 04d4130a513783eecbec426c8151c1d2fe086430 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 24 May 2022 11:56:12 -0500 Subject: [PATCH] Support converting pointers from opaque to typed Using the pointer type analysis we can re-constitute typed pointers and populate the correct types in the bitcasts throughout the IR. This doesn't yet handle all cases, but this should be illustrative as to the dirction and feasability of the solution. Reviewed By: pete Differential Revision: https://reviews.llvm.org/D122270 --- llvm/lib/Target/DirectX/DXILPrepare.cpp | 6 +- llvm/lib/Target/DirectX/DXILWriter/CMakeLists.txt | 2 + .../DirectX/DXILWriter/DXILBitcodeWriter.cpp | 148 ++++++++++++++------- .../DirectX/DXILWriter/DXILValueEnumerator.cpp | 54 +------- .../DirectX/DXILWriter/DXILValueEnumerator.h | 10 +- llvm/test/tools/dxil-dis/opaque-gep.ll | 22 +++ llvm/test/tools/dxil-dis/opaque-pointers.ll | 59 ++++++++ 7 files changed, 193 insertions(+), 108 deletions(-) create mode 100644 llvm/test/tools/dxil-dis/opaque-gep.ll create mode 100644 llvm/test/tools/dxil-dis/opaque-pointers.ll diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp index 5da9f12..73420e3 100644 --- a/llvm/lib/Target/DirectX/DXILPrepare.cpp +++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp @@ -94,8 +94,10 @@ class DXILPrepareModule : public ModulePass { Builder.SetInsertPoint(&Inst); // This code only gets hit in opaque-pointer mode, so the type of the // pointer doesn't matter. - return Builder.Insert(CastInst::Create(Instruction::BitCast, Operand, - Builder.getInt8PtrTy())); + PointerType *PtrTy = cast(Operand->getType()); + return Builder.Insert( + CastInst::Create(Instruction::BitCast, Operand, + Builder.getInt8PtrTy(PtrTy->getAddressSpace()))); } public: diff --git a/llvm/lib/Target/DirectX/DXILWriter/CMakeLists.txt b/llvm/lib/Target/DirectX/DXILWriter/CMakeLists.txt index a6864f0..3a48942 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/DXILWriter/CMakeLists.txt @@ -1,3 +1,5 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../) + add_llvm_component_library(LLVMDXILBitWriter DXILBitcodeWriter.cpp DXILValueEnumerator.cpp diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp index 260242e..f575a3a 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp @@ -12,6 +12,7 @@ #include "DXILBitcodeWriter.h" #include "DXILValueEnumerator.h" +#include "PointerTypeAnalysis.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/BitcodeCommon.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -88,6 +89,10 @@ class DXILBitcodeWriter { FUNCTION_INST_GEP_ABBREV, }; + // Cache some types + Type *I8Ty; + Type *I8PtrTy; + /// The stream created and owned by the client. BitstreamWriter &Stream; @@ -117,14 +122,23 @@ class DXILBitcodeWriter { /// The start bit of the identification block. uint64_t BitcodeStartBit; + /// This maps values to their typed pointers + PointerTypeMap PointerMap; + public: /// Constructs a ModuleBitcodeWriter object for the given Module, /// writing to the provided \p Buffer. DXILBitcodeWriter(const Module &M, SmallVectorImpl &Buffer, StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream) - : Stream(Stream), StrtabBuilder(StrtabBuilder), M(M), VE(M, true), - Buffer(Buffer), BitcodeStartBit(Stream.GetCurrentBitNo()) { + : I8Ty(Type::getInt8Ty(M.getContext())), + I8PtrTy(TypedPointerType::get(I8Ty, 0)), Stream(Stream), + StrtabBuilder(StrtabBuilder), M(M), VE(M, I8PtrTy), Buffer(Buffer), + BitcodeStartBit(Stream.GetCurrentBitNo()), + PointerMap(PointerTypeAnalysis::run(M)) { GlobalValueId = VE.getValues().size(); + // Enumerate the typed pointers + for (auto El : PointerMap) + VE.EnumerateType(El.second); } /// Emit the current module to the bitstream. @@ -329,6 +343,9 @@ private: unsigned getEncodedSyncScopeID(SyncScope::ID SSID) { return unsigned(SSID); } unsigned getEncodedAlign(MaybeAlign Alignment) { return encode(Alignment); } + + unsigned getTypeID(Type *T, const Value *V = nullptr); + unsigned getTypeID(Type *T, const Function *F); }; } // namespace dxil @@ -532,6 +549,22 @@ unsigned DXILBitcodeWriter::getEncodedBinaryOpcode(unsigned Opcode) { } } +unsigned DXILBitcodeWriter::getTypeID(Type *T, const Value *V) { + if (!T->isOpaquePointerTy()) + return VE.getTypeID(T); + auto It = PointerMap.find(V); + if (It != PointerMap.end()) + return VE.getTypeID(It->second); + return VE.getTypeID(I8PtrTy); +} + +unsigned DXILBitcodeWriter::getTypeID(Type *T, const Function *F) { + auto It = PointerMap.find(F); + if (It != PointerMap.end()) + return VE.getTypeID(It->second); + return VE.getTypeID(T); +} + unsigned DXILBitcodeWriter::getEncodedRMWOperation(AtomicRMWInst::BinOp Op) { switch (Op) { default: @@ -993,7 +1026,6 @@ void DXILBitcodeWriter::writeTypeTable() { case Type::BFloatTyID: case Type::X86_AMXTyID: case Type::TokenTyID: - case Type::DXILPointerTyID: llvm_unreachable("These should never be used!!!"); break; case Type::VoidTyID: @@ -1031,25 +1063,46 @@ void DXILBitcodeWriter::writeTypeTable() { Code = bitc::TYPE_CODE_INTEGER; TypeVals.push_back(cast(T)->getBitWidth()); break; - case Type::PointerTyID: { - PointerType *PTy = cast(T); + case Type::DXILPointerTyID: { + TypedPointerType *PTy = cast(T); // POINTER: [pointee type, address space] Code = bitc::TYPE_CODE_POINTER; - TypeVals.push_back(VE.getTypeID(PTy->getNonOpaquePointerElementType())); + TypeVals.push_back(getTypeID(PTy->getElementType())); unsigned AddressSpace = PTy->getAddressSpace(); TypeVals.push_back(AddressSpace); if (AddressSpace == 0) AbbrevToUse = PtrAbbrev; break; } + case Type::PointerTyID: { + PointerType *PTy = cast(T); + // POINTER: [pointee type, address space] + Code = bitc::TYPE_CODE_POINTER; + // Emitting an empty struct type for the opaque pointer's type allows + // this to be order-independent. Non-struct types must be emitted in + // bitcode before they can be referenced. + if (PTy->isOpaquePointerTy()) { + TypeVals.push_back(false); + Code = bitc::TYPE_CODE_OPAQUE; + writeStringRecord(Stream, bitc::TYPE_CODE_STRUCT_NAME, + "dxilOpaquePtrReservedName", StructNameAbbrev); + } else { + TypeVals.push_back(getTypeID(PTy->getNonOpaquePointerElementType())); + unsigned AddressSpace = PTy->getAddressSpace(); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; + } + break; + } case Type::FunctionTyID: { FunctionType *FT = cast(T); // FUNCTION: [isvararg, retty, paramty x N] Code = bitc::TYPE_CODE_FUNCTION; TypeVals.push_back(FT->isVarArg()); - TypeVals.push_back(VE.getTypeID(FT->getReturnType())); + TypeVals.push_back(getTypeID(FT->getReturnType())); for (Type *PTy : FT->params()) - TypeVals.push_back(VE.getTypeID(PTy)); + TypeVals.push_back(getTypeID(PTy)); AbbrevToUse = FunctionAbbrev; break; } @@ -1059,7 +1112,7 @@ void DXILBitcodeWriter::writeTypeTable() { TypeVals.push_back(ST->isPacked()); // Output all of the element types. for (Type *ElTy : ST->elements()) - TypeVals.push_back(VE.getTypeID(ElTy)); + TypeVals.push_back(getTypeID(ElTy)); if (ST->isLiteral()) { Code = bitc::TYPE_CODE_STRUCT_ANON; @@ -1084,7 +1137,7 @@ void DXILBitcodeWriter::writeTypeTable() { // ARRAY: [numelts, eltty] Code = bitc::TYPE_CODE_ARRAY; TypeVals.push_back(AT->getNumElements()); - TypeVals.push_back(VE.getTypeID(AT->getElementType())); + TypeVals.push_back(getTypeID(AT->getElementType())); AbbrevToUse = ArrayAbbrev; break; } @@ -1094,7 +1147,7 @@ void DXILBitcodeWriter::writeTypeTable() { // VECTOR [numelts, eltty] Code = bitc::TYPE_CODE_VECTOR; TypeVals.push_back(VT->getElementCount().getKnownMinValue()); - TypeVals.push_back(VE.getTypeID(VT->getElementType())); + TypeVals.push_back(getTypeID(VT->getElementType())); break; } } @@ -1151,7 +1204,7 @@ void DXILBitcodeWriter::writeModuleInfo() { }; for (const GlobalVariable &GV : M.globals()) { UpdateMaxAlignment(GV.getAlign()); - MaxGlobalType = std::max(MaxGlobalType, VE.getTypeID(GV.getValueType())); + MaxGlobalType = std::max(MaxGlobalType, getTypeID(GV.getValueType(), &GV)); if (GV.hasSection()) { // Give section names unique ID's. unsigned &Entry = SectionMap[std::string(GV.getSection())]; @@ -1187,7 +1240,8 @@ void DXILBitcodeWriter::writeModuleInfo() { // Emit abbrev for globals, now that we know # sections and max alignment. unsigned SimpleGVarAbbrev = 0; if (!M.global_empty()) { - // Add an abbrev for common globals with no visibility or thread localness. + // Add an abbrev for common globals with no visibility or thread + // localness. auto Abbv = std::make_shared(); Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, @@ -1222,7 +1276,7 @@ void DXILBitcodeWriter::writeModuleInfo() { // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, // comdat] - Vals.push_back(VE.getTypeID(GV.getValueType())); + Vals.push_back(getTypeID(GV.getValueType(), &GV)); Vals.push_back( GV.getType()->getAddressSpace() << 2 | 2 | (GV.isConstant() ? 1 : 0)); // HLSL Change - bitwise | was used with @@ -1258,7 +1312,7 @@ void DXILBitcodeWriter::writeModuleInfo() { // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, // section, visibility, gc, unnamed_addr, prologuedata, // dllstorageclass, comdat, prefixdata, personalityfn] - Vals.push_back(VE.getTypeID(F.getFunctionType())); + Vals.push_back(getTypeID(F.getFunctionType(), &F)); Vals.push_back(F.getCallingConv()); Vals.push_back(F.isDeclaration()); Vals.push_back(getEncodedLinkage(F)); @@ -1286,7 +1340,7 @@ void DXILBitcodeWriter::writeModuleInfo() { // Emit the alias information. for (const GlobalAlias &A : M.aliases()) { // ALIAS: [alias type, aliasee val#, linkage, visibility] - Vals.push_back(VE.getTypeID(A.getValueType())); + Vals.push_back(getTypeID(A.getValueType(), &A)); Vals.push_back(VE.getValueID(A.getAliasee())); Vals.push_back(getEncodedLinkage(A)); Vals.push_back(getEncodedVisibility(A)); @@ -1303,7 +1357,7 @@ void DXILBitcodeWriter::writeValueAsMetadata( const ValueAsMetadata *MD, SmallVectorImpl &Record) { // Mimic an MDNode with a value as one operand. Value *V = MD->getValue(); - Record.push_back(VE.getTypeID(V->getType())); + Record.push_back(getTypeID(V->getType())); Record.push_back(VE.getValueID(V)); Stream.EmitRecord(bitc::METADATA_VALUE, Record, 0); Record.clear(); @@ -1907,7 +1961,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, // If we need to switch types, do so now. if (V->getType() != LastTy) { LastTy = V->getType(); - Record.push_back(VE.getTypeID(LastTy)); + Record.push_back(getTypeID(LastTy)); Stream.EmitRecord(bitc::CST_CODE_SETTYPE, Record, CONSTANTS_SETTYPE_ABBREV); Record.clear(); @@ -2042,7 +2096,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, if (Instruction::isCast(CE->getOpcode())) { Code = bitc::CST_CODE_CE_CAST; Record.push_back(getEncodedCastOpcode(CE->getOpcode())); - Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(getTypeID(C->getOperand(0)->getType())); Record.push_back(VE.getValueID(C->getOperand(0))); AbbrevToUse = CONSTANTS_CE_CAST_Abbrev; } else { @@ -2061,9 +2115,9 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, const auto *GO = cast(C); if (GO->isInBounds()) Code = bitc::CST_CODE_CE_INBOUNDS_GEP; - Record.push_back(VE.getTypeID(GO->getSourceElementType())); + Record.push_back(getTypeID(GO->getSourceElementType())); for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) { - Record.push_back(VE.getTypeID(C->getOperand(i)->getType())); + Record.push_back(getTypeID(C->getOperand(i)->getType())); Record.push_back(VE.getValueID(C->getOperand(i))); } break; @@ -2076,16 +2130,16 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, break; case Instruction::ExtractElement: Code = bitc::CST_CODE_CE_EXTRACTELT; - Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(getTypeID(C->getOperand(0)->getType())); Record.push_back(VE.getValueID(C->getOperand(0))); - Record.push_back(VE.getTypeID(C->getOperand(1)->getType())); + Record.push_back(getTypeID(C->getOperand(1)->getType())); Record.push_back(VE.getValueID(C->getOperand(1))); break; case Instruction::InsertElement: Code = bitc::CST_CODE_CE_INSERTELT; Record.push_back(VE.getValueID(C->getOperand(0))); Record.push_back(VE.getValueID(C->getOperand(1))); - Record.push_back(VE.getTypeID(C->getOperand(2)->getType())); + Record.push_back(getTypeID(C->getOperand(2)->getType())); Record.push_back(VE.getValueID(C->getOperand(2))); break; case Instruction::ShuffleVector: @@ -2097,7 +2151,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, Code = bitc::CST_CODE_CE_SHUFFLEVEC; } else { Code = bitc::CST_CODE_CE_SHUFVEC_EX; - Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(getTypeID(C->getOperand(0)->getType())); } Record.push_back(VE.getValueID(C->getOperand(0))); Record.push_back(VE.getValueID(C->getOperand(1))); @@ -2106,7 +2160,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, case Instruction::ICmp: case Instruction::FCmp: Code = bitc::CST_CODE_CE_CMP; - Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(getTypeID(C->getOperand(0)->getType())); Record.push_back(VE.getValueID(C->getOperand(0))); Record.push_back(VE.getValueID(C->getOperand(1))); Record.push_back(CE->getPredicate()); @@ -2114,7 +2168,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, } } else if (const BlockAddress *BA = dyn_cast(C)) { Code = bitc::CST_CODE_BLOCKADDRESS; - Record.push_back(VE.getTypeID(BA->getFunction()->getType())); + Record.push_back(getTypeID(BA->getFunction()->getType())); Record.push_back(VE.getValueID(BA->getFunction())); Record.push_back(VE.getGlobalBasicBlockID(BA->getBasicBlock())); } else { @@ -2157,7 +2211,7 @@ bool DXILBitcodeWriter::pushValueAndType(const Value *V, unsigned InstID, // Make encoding relative to the InstID. Vals.push_back(InstID - ValID); if (ValID >= InstID) { - Vals.push_back(VE.getTypeID(V->getType())); + Vals.push_back(getTypeID(V->getType(), V)); return true; } return false; @@ -2190,7 +2244,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, Code = bitc::FUNC_CODE_INST_CAST; if (!pushValueAndType(I.getOperand(0), InstID, Vals)) AbbrevToUse = (unsigned)FUNCTION_INST_CAST_ABBREV; - Vals.push_back(VE.getTypeID(I.getType())); + Vals.push_back(getTypeID(I.getType(), &I)); Vals.push_back(getEncodedCastOpcode(I.getOpcode())); } else { assert(isa(I) && "Unknown instruction!"); @@ -2213,7 +2267,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, AbbrevToUse = (unsigned)FUNCTION_INST_GEP_ABBREV; auto &GEPInst = cast(I); Vals.push_back(GEPInst.isInBounds()); - Vals.push_back(VE.getTypeID(GEPInst.getSourceElementType())); + Vals.push_back(getTypeID(GEPInst.getSourceElementType())); for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) pushValueAndType(I.getOperand(i), InstID, Vals); break; @@ -2294,7 +2348,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, case Instruction::Switch: { Code = bitc::FUNC_CODE_INST_SWITCH; const SwitchInst &SI = cast(I); - Vals.push_back(VE.getTypeID(SI.getCondition()->getType())); + Vals.push_back(getTypeID(SI.getCondition()->getType())); pushValue(SI.getCondition(), InstID, Vals); Vals.push_back(VE.getValueID(SI.getDefaultDest())); for (auto Case : SI.cases()) { @@ -2304,7 +2358,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, } break; case Instruction::IndirectBr: Code = bitc::FUNC_CODE_INST_INDIRECTBR; - Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); + Vals.push_back(getTypeID(I.getOperand(0)->getType())); // Encode the address operand as relative, but not the basic blocks. pushValue(I.getOperand(0), InstID, Vals); for (unsigned i = 1, e = I.getNumOperands(); i != e; ++i) @@ -2321,7 +2375,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, Vals.push_back(II->getCallingConv() | 1 << 13); Vals.push_back(VE.getValueID(II->getNormalDest())); Vals.push_back(VE.getValueID(II->getUnwindDest())); - Vals.push_back(VE.getTypeID(FTy)); + Vals.push_back(getTypeID(FTy)); pushValueAndType(Callee, InstID, Vals); // Emit value #'s for the fixed parameters. @@ -2352,7 +2406,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, // negative valued IDs. This is most common for PHIs, so we use // signed VBRs. SmallVector Vals64; - Vals64.push_back(VE.getTypeID(PN.getType())); + Vals64.push_back(getTypeID(PN.getType())); for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { pushValueSigned(PN.getIncomingValue(i), InstID, Vals64); Vals64.push_back(VE.getValueID(PN.getIncomingBlock(i))); @@ -2366,7 +2420,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, case Instruction::LandingPad: { const LandingPadInst &LP = cast(I); Code = bitc::FUNC_CODE_INST_LANDINGPAD; - Vals.push_back(VE.getTypeID(LP.getType())); + Vals.push_back(getTypeID(LP.getType())); Vals.push_back(LP.isCleanup()); Vals.push_back(LP.getNumClauses()); for (unsigned I = 0, E = LP.getNumClauses(); I != E; ++I) { @@ -2382,8 +2436,8 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, case Instruction::Alloca: { Code = bitc::FUNC_CODE_INST_ALLOCA; const AllocaInst &AI = cast(I); - Vals.push_back(VE.getTypeID(AI.getAllocatedType())); - Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); + Vals.push_back(getTypeID(AI.getAllocatedType())); + Vals.push_back(getTypeID(I.getOperand(0)->getType())); Vals.push_back(VE.getValueID(I.getOperand(0))); // size. using APV = AllocaPackedValues; unsigned Record = 0; @@ -2406,7 +2460,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, if (!pushValueAndType(I.getOperand(0), InstID, Vals)) // ptr AbbrevToUse = (unsigned)FUNCTION_INST_LOAD_ABBREV; } - Vals.push_back(VE.getTypeID(I.getType())); + Vals.push_back(getTypeID(I.getType())); Vals.push_back(Log2_32(cast(I).getAlignment()) + 1); Vals.push_back(cast(I).isVolatile()); if (cast(I).isAtomic()) { @@ -2468,7 +2522,7 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, Vals.push_back(VE.getAttributeListID(CI.getAttributes())); Vals.push_back((CI.getCallingConv() << 1) | unsigned(CI.isTailCall()) | unsigned(CI.isMustTailCall()) << 14 | 1 << 15); - Vals.push_back(VE.getTypeID(FTy)); + Vals.push_back(getTypeID(FTy, CI.getCalledFunction())); pushValueAndType(CI.getCalledOperand(), InstID, Vals); // Callee // Emit value #'s for the fixed parameters. @@ -2489,9 +2543,9 @@ void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, } case Instruction::VAArg: Code = bitc::FUNC_CODE_INST_VAARG; - Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); // valistty - pushValue(I.getOperand(0), InstID, Vals); // valist. - Vals.push_back(VE.getTypeID(I.getType())); // restype. + Vals.push_back(getTypeID(I.getOperand(0)->getType())); // valistty + pushValue(I.getOperand(0), InstID, Vals); // valist. + Vals.push_back(getTypeID(I.getType())); // restype. break; } @@ -2582,9 +2636,6 @@ void DXILBitcodeWriter::writeUseList(UseListOrder &&Order) { } void DXILBitcodeWriter::writeUseListBlock(const Function *F) { - assert(VE.shouldPreserveUseListOrder() && - "Expected to be preserving use-list order"); - auto hasMore = [&]() { return !VE.UseListOrders.empty() && VE.UseListOrders.back().F == F; }; @@ -2667,8 +2718,8 @@ void DXILBitcodeWriter::writeFunction(const Function &F) { if (NeedsMetadataAttachment) writeFunctionMetadataAttachment(F); - if (VE.shouldPreserveUseListOrder()) - writeUseListBlock(&F); + + writeUseListBlock(&F); VE.purgeFunction(); Stream.ExitBlock(); } @@ -2896,8 +2947,7 @@ void DXILBitcodeWriter::write() { writeFunctionLevelValueSymbolTable(M.getValueSymbolTable()); // Emit module-level use-lists. - if (VE.shouldPreserveUseListOrder()) - writeUseListBlock(nullptr); + writeUseListBlock(nullptr); // Emit function bodies. for (const Function &F : M) diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp index 286b2c8..69c3d56 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp @@ -358,15 +358,10 @@ static UseListOrderStack predictUseListOrder(const Module &M) { return Stack; } -static bool isIntOrIntVectorValue(const std::pair &V) { - return V.first->getType()->isIntOrIntVectorTy(); -} - -ValueEnumerator::ValueEnumerator(const Module &M, - bool ShouldPreserveUseListOrder) - : ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) { - if (ShouldPreserveUseListOrder) - UseListOrders = predictUseListOrder(M); +ValueEnumerator::ValueEnumerator(const Module &M, Type *PrefixType) { + EnumerateType(PrefixType); + + UseListOrders = predictUseListOrder(M); // Enumerate the global variables. for (const GlobalVariable &GV : M.globals()) { @@ -393,9 +388,6 @@ ValueEnumerator::ValueEnumerator(const Module &M, EnumerateType(GIF.getValueType()); } - // Remember what is the cutoff between globalvalue's and other constants. - unsigned FirstConstant = Values.size(); - // Enumerate the global variable initializers and attributes. for (const GlobalVariable &GV : M.globals()) { if (GV.hasInitializer()) @@ -499,9 +491,6 @@ ValueEnumerator::ValueEnumerator(const Module &M, } } - // Optimize constant ordering. - OptimizeConstants(FirstConstant, Values.size()); - // Organize metadata ordering. organizeMetadata(); } @@ -579,38 +568,6 @@ void ValueEnumerator::print(raw_ostream &OS, const MetadataMapType &Map, } } -/// OptimizeConstants - Reorder constant pool for denser encoding. -void ValueEnumerator::OptimizeConstants(unsigned CstStart, unsigned CstEnd) { - if (CstStart == CstEnd || CstStart + 1 == CstEnd) - return; - - if (ShouldPreserveUseListOrder) - // Optimizing constants makes the use-list order difficult to predict. - // Disable it for now when trying to preserve the order. - return; - - std::stable_sort(Values.begin() + CstStart, Values.begin() + CstEnd, - [this](const std::pair &LHS, - const std::pair &RHS) { - // Sort by plane. - if (LHS.first->getType() != RHS.first->getType()) - return getTypeID(LHS.first->getType()) < - getTypeID(RHS.first->getType()); - // Then by frequency. - return LHS.second > RHS.second; - }); - - // Ensure that integer and vector of integer constants are at the start of the - // constant pool. This is important so that GEP structure indices come before - // gep constant exprs. - std::stable_partition(Values.begin() + CstStart, Values.begin() + CstEnd, - isIntOrIntVectorValue); - - // Rebuild the modified portion of ValueMap. - for (; CstStart != CstEnd; ++CstStart) - ValueMap[Values[CstStart].first] = CstStart + 1; -} - /// EnumerateValueSymbolTable - Insert all of the values in the specified symbol /// table into the values table. void ValueEnumerator::EnumerateValueSymbolTable(const ValueSymbolTable &VST) { @@ -1098,9 +1055,6 @@ void ValueEnumerator::incorporateFunction(const Function &F) { ValueMap[&BB] = BasicBlocks.size(); } - // Optimize the constant layout. - OptimizeConstants(FirstFuncConstantID, Values.size()); - // Add the function's parameter attributes so they are available for use in // the function's instruction. EnumerateAttributes(F.getAttributes()); diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h index c4a842b..6cf339b 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h @@ -106,8 +106,6 @@ private: }; SmallDenseMap FunctionMDInfo; - bool ShouldPreserveUseListOrder; - using AttributeGroupMapType = DenseMap; AttributeGroupMapType AttributeGroupMap; std::vector AttributeGroups; @@ -141,7 +139,7 @@ private: unsigned FirstInstID; public: - ValueEnumerator(const Module &M, bool ShouldPreserveUseListOrder); + ValueEnumerator(const Module &M, Type *PrefixType); ValueEnumerator(const ValueEnumerator &) = delete; ValueEnumerator &operator=(const ValueEnumerator &) = delete; @@ -164,8 +162,6 @@ public: unsigned numMDs() const { return MDs.size(); } - bool shouldPreserveUseListOrder() const { return ShouldPreserveUseListOrder; } - unsigned getTypeID(Type *T) const { TypeMapType::const_iterator I = TypeMap.find(T); assert(I != TypeMap.end() && "Type not in ValueEnumerator!"); @@ -242,8 +238,9 @@ public: void purgeFunction(); uint64_t computeBitsRequiredForTypeIndicies() const; + void EnumerateType(Type *T); + private: - void OptimizeConstants(unsigned CstStart, unsigned CstEnd); /// Reorder the reachable metadata. /// @@ -298,7 +295,6 @@ private: void EnumerateFunctionLocalListMetadata(unsigned F, const DIArgList *Arglist); void EnumerateNamedMDNode(const NamedMDNode *NMD); void EnumerateValue(const Value *V); - void EnumerateType(Type *T); void EnumerateOperandType(const Value *V); void EnumerateAttributes(AttributeList PAL); diff --git a/llvm/test/tools/dxil-dis/opaque-gep.ll b/llvm/test/tools/dxil-dis/opaque-gep.ll new file mode 100644 index 0000000..fd3f608 --- /dev/null +++ b/llvm/test/tools/dxil-dis/opaque-gep.ll @@ -0,0 +1,22 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +define i32 @fn(ptr %0) { + %2 = getelementptr i32, ptr %0, i32 4 + %3 = load i32, ptr %2 + ret i32 %3 +} + +; CHECK: define i32 @fn(i32*) +; CHECK-NEXT: %2 = getelementptr i32, i32* %0, i32 4 +; CHECK-NEXT: %3 = load i32, i32* %2, align 4 + +define i32 @fn2(ptr addrspace(1) %0) { + %2 = getelementptr i32, ptr addrspace(1) %0, i32 4 + %3 = load i32, ptr addrspace(1) %2 + ret i32 %3 +} + +; CHECK: define i32 @fn2(i32 addrspace(1)*) +; CHECK-NEXT: %2 = getelementptr i32, i32 addrspace(1)* %0, i32 4 +; CHECK-NEXT: %3 = load i32, i32 addrspace(1)* %2, align 4 diff --git a/llvm/test/tools/dxil-dis/opaque-pointers.ll b/llvm/test/tools/dxil-dis/opaque-pointers.ll new file mode 100644 index 0000000..4e63b23 --- /dev/null +++ b/llvm/test/tools/dxil-dis/opaque-pointers.ll @@ -0,0 +1,59 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +define i64 @test(ptr %p) { + store i32 0, ptr %p + %v = load i64, ptr %p + ret i64 %v +} + +; CHECK: define i64 @test(i8* %p) { +; CHECK-NEXT: %1 = bitcast i8* %p to i32* +; CHECK-NEXT: store i32 0, i32* %1, align 4 +; CHECK-NEXT: %2 = bitcast i8* %p to i64* +; CHECK-NEXT: %3 = load i64, i64* %2, align 8 + +define i64 @test2(ptr %p) { + store i64 0, ptr %p + %v = load i64, ptr %p + ret i64 %v +} + +; CHECK: define i64 @test2(i64* %p) { +; CHECK-NEXT: store i64 0, i64* %p, align 8 +; CHECK-NEXT: %v = load i64, i64* %p, align 8 + +define i64 @test3(ptr addrspace(1) %p) { + store i32 0, ptr addrspace(1) %p + %v = load i64, ptr addrspace(1) %p + ret i64 %v +} + +; CHECK: define i64 @test3(i8 addrspace(1)* %p) { +; CHECK-NEXT: %1 = bitcast i8 addrspace(1)* %p to i32 addrspace(1)* +; CHECK-NEXT: store i32 0, i32 addrspace(1)* %1, align 4 +; CHECK-NEXT: %2 = bitcast i8 addrspace(1)* %p to i64 addrspace(1)* +; CHECK-NEXT: %3 = load i64, i64 addrspace(1)* %2, align 8 + +define i64 @test4(ptr addrspace(1) %p) { + store i64 0, ptr addrspace(1) %p + %v = load i64, ptr addrspace(1) %p + ret i64 %v +} + +; CHECK: define i64 @test4(i64 addrspace(1)* %p) { +; CHECK-NEXT: store i64 0, i64 addrspace(1)* %p, align 8 +; CHECK-NEXT: %v = load i64, i64 addrspace(1)* %p, align 8 + + +define i64 @test5(ptr %p) { + %casted = addrspacecast ptr %p to ptr addrspace(1) + store i64 0, ptr addrspace(1) %casted + %v = load i64, ptr addrspace(1) %casted + ret i64 %v +} + +; CHECK: define i64 @test5(i8* %p) { +; CHECK-NEXT: %casted = addrspacecast i8* %p to i64 addrspace(1)* +; CHECK-NEXT: store i64 0, i64 addrspace(1)* %casted, align 8 +; CHECK-NEXT: %v = load i64, i64 addrspace(1)* %casted, align 8 -- 2.7.4