diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp --- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp @@ -346,7 +346,11 @@ unsigned getEncodedAlign(MaybeAlign Alignment) { return encode(Alignment); } unsigned getTypeID(Type *T, const Value *V = nullptr); - unsigned getTypeID(Type *T, const Function *F); + // For Function and GlobalVariable, the type in map is saved as ptr to the + // FunctionType/ValueType. + // getGlobalObjectValueTypeID will return the FunctionType/ValueType if the + // Function/GlobalVariable in the map. + unsigned getGlobalObjectValueTypeID(Type *T, const GlobalObject *G); }; } // namespace dxil @@ -551,18 +555,21 @@ } 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); + if (!T->isOpaquePointerTy()) + return VE.getTypeID(T); 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); +unsigned DXILBitcodeWriter::getGlobalObjectValueTypeID(Type *T, + const GlobalObject *G) { + auto It = PointerMap.find(G); + if (It != PointerMap.end()) { + TypedPointerType *PtrTy = cast(It->second); + return VE.getTypeID(PtrTy->getElementType()); + } return VE.getTypeID(T); } @@ -1209,7 +1216,10 @@ }; for (const GlobalVariable &GV : M.globals()) { UpdateMaxAlignment(GV.getAlign()); - MaxGlobalType = std::max(MaxGlobalType, getTypeID(GV.getValueType(), &GV)); + // Here use getGlobalObjectValueTypeID for the Abbrev which store ValueType + // of GlobalVariable. + MaxGlobalType = std::max( + MaxGlobalType, getGlobalObjectValueTypeID(GV.getValueType(), &GV)); if (GV.hasSection()) { // Give section names unique ID's. unsigned &Entry = SectionMap[std::string(GV.getSection())]; @@ -1281,7 +1291,7 @@ // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, // comdat] - Vals.push_back(getTypeID(GV.getValueType(), &GV)); + Vals.push_back(getGlobalObjectValueTypeID(GV.getValueType(), &GV)); Vals.push_back( GV.getType()->getAddressSpace() << 2 | 2 | (GV.isConstant() ? 1 : 0)); // HLSL Change - bitwise | was used with @@ -1317,7 +1327,7 @@ // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, // section, visibility, gc, unnamed_addr, prologuedata, // dllstorageclass, comdat, prefixdata, personalityfn] - Vals.push_back(getTypeID(F.getFunctionType(), &F)); + Vals.push_back(getGlobalObjectValueTypeID(F.getFunctionType(), &F)); Vals.push_back(F.getCallingConv()); Vals.push_back(F.isDeclaration()); Vals.push_back(getEncodedLinkage(F)); @@ -1971,7 +1981,7 @@ // If we need to switch types, do so now. if (V->getType() != LastTy) { LastTy = V->getType(); - Record.push_back(getTypeID(LastTy)); + Record.push_back(getTypeID(LastTy, V)); Stream.EmitRecord(bitc::CST_CODE_SETTYPE, Record, CONSTANTS_SETTYPE_ABBREV); Record.clear(); @@ -2106,7 +2116,8 @@ if (Instruction::isCast(CE->getOpcode())) { Code = bitc::CST_CODE_CE_CAST; Record.push_back(getEncodedCastOpcode(CE->getOpcode())); - Record.push_back(getTypeID(C->getOperand(0)->getType())); + Record.push_back( + getTypeID(C->getOperand(0)->getType(), C->getOperand(0))); Record.push_back(VE.getValueID(C->getOperand(0))); AbbrevToUse = CONSTANTS_CE_CAST_Abbrev; } else { @@ -2127,7 +2138,8 @@ Code = bitc::CST_CODE_CE_INBOUNDS_GEP; Record.push_back(getTypeID(GO->getSourceElementType())); for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) { - Record.push_back(getTypeID(C->getOperand(i)->getType())); + Record.push_back( + getTypeID(C->getOperand(i)->getType(), C->getOperand(i))); Record.push_back(VE.getValueID(C->getOperand(i))); } break; @@ -2529,7 +2541,7 @@ 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(getTypeID(FTy, CI.getCalledFunction())); + Vals.push_back(getGlobalObjectValueTypeID(FTy, CI.getCalledFunction())); pushValueAndType(CI.getCalledOperand(), InstID, Vals); // Callee // Emit value #'s for the fixed parameters. diff --git a/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp b/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp --- a/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp +++ b/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "PointerTypeAnalysis.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" using namespace llvm; @@ -29,13 +30,19 @@ PointeeTy = Inst->getResultElementType(); } else if (auto *Inst = dyn_cast(V)) { PointeeTy = Inst->getAllocatedType(); + } else if (auto *GV = dyn_cast(V)) { + PointeeTy = GV->getValueType(); } + for (const auto *User : V->users()) { Type *NewPointeeTy = nullptr; if (const auto *Inst = dyn_cast(User)) { NewPointeeTy = Inst->getType(); } else if (const auto *Inst = dyn_cast(User)) { NewPointeeTy = Inst->getValueOperand()->getType(); + // When store value is ptr type, cannot get more type info. + if (NewPointeeTy->isOpaquePointerTy()) + continue; } else if (const auto *Inst = dyn_cast(User)) { NewPointeeTy = Inst->getSourceElementType(); } @@ -64,23 +71,26 @@ // the function's value in the type map. void classifyFunctionType(const Function &F, PointerTypeMap &Map) { SmallVector NewArgs; - bool HasOpaqueTy = false; Type *RetTy = F.getReturnType(); + LLVMContext &Ctx = F.getContext(); if (RetTy->isOpaquePointerTy()) { RetTy = nullptr; for (const auto &B : F) { - for (const auto &I : B) { - if (const auto *RetInst = dyn_cast_or_null(&I)) { - Type *NewRetTy = classifyPointerType(RetInst->getReturnValue()); - if (!RetTy) - RetTy = NewRetTy; - else if (RetTy != NewRetTy) - RetTy = TypedPointerType::get( - Type::getInt8Ty(I.getContext()), - F.getReturnType()->getPointerAddressSpace()); - } - } + const auto *RetInst = dyn_cast_or_null(B.getTerminator()); + if (!RetInst) + continue; + + Type *NewRetTy = classifyPointerType(RetInst->getReturnValue()); + if (!RetTy) + RetTy = NewRetTy; + else if (RetTy != NewRetTy) + RetTy = TypedPointerType::get( + Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace()); } + // For function decl. + if (!RetTy) + RetTy = TypedPointerType::get( + Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace()); } for (auto &A : F.args()) { Type *ArgTy = A.getType(); @@ -88,22 +98,83 @@ TypedPointerType *NewTy = classifyPointerType(&A); Map[&A] = NewTy; ArgTy = NewTy; - HasOpaqueTy = true; } NewArgs.push_back(ArgTy); } - if (!HasOpaqueTy) - return; - Map[&F] = FunctionType::get(RetTy, NewArgs, false); + Map[&F] = TypedPointerType::get(FunctionType::get(RetTy, NewArgs, false), 0); } } // anonymous namespace +static Type *classifyConstantWithOpaquePtr(const Constant *C, + PointerTypeMap &Map) { + // FIXME: support ConstantPointerNull which could map to more than one + // TypedPointerType. + auto It = Map.find(C); + if (It != Map.end()) + return It->second; + // Skip ConstantData which cannot have opaque ptr. + if (isa(C)) + return C->getType(); + + Type *Ty = C->getType(); + Type *TargetTy = nullptr; + if (auto *CS = dyn_cast(C)) { + SmallVector EltTys; + for (unsigned int I = 0; I < CS->getNumOperands(); ++I) { + const Constant *Elt = C->getAggregateElement(I); + Type *EltTy = classifyConstantWithOpaquePtr(Elt, Map); + EltTys.emplace_back(EltTy); + } + TargetTy = StructType::get(C->getContext(), EltTys); + } else if (auto *CA = dyn_cast(C)) { + + Type *TargetEltTy = nullptr; + for (auto &Elt : CA->operands()) { + Type *EltTy = classifyConstantWithOpaquePtr(cast(&Elt), Map); + assert(TargetEltTy == EltTy || TargetEltTy == nullptr); + TargetEltTy = EltTy; + } + + if (auto *AT = dyn_cast(Ty)) { + TargetTy = ArrayType::get(TargetEltTy, AT->getNumElements()); + } else { + // Not struct, not array, must be vector here. + auto *VT = cast(Ty); + TargetTy = VectorType::get(TargetEltTy, VT); + } + } + // Must have a target ty when map. + assert(TargetTy); + + // Same type, no need to map. + if (TargetTy == Ty) + return Ty; + + Map[C] = TargetTy; + return TargetTy; +} + +static void classifyGlobalCtorPointerType(const GlobalVariable &GV, + PointerTypeMap &Map) { + const auto *CA = cast(GV.getInitializer()); + // Type for global ctor should be array of { i32, void ()*, i8* }. + Type *CtorArrayTy = classifyConstantWithOpaquePtr(CA, Map); + + // Map the global type. + Map[&GV] = TypedPointerType::get(CtorArrayTy, + GV.getType()->getPointerAddressSpace()); +} + PointerTypeMap PointerTypeAnalysis::run(const Module &M) { PointerTypeMap Map; + SmallVector SpecialGVs; for (auto &G : M.globals()) { if (G.getType()->isOpaquePointerTy()) Map[&G] = classifyPointerType(&G); + if (G.getName() == "llvm.global_ctors") + SpecialGVs.emplace_back(&G); } + for (auto &F : M) { classifyFunctionType(F, Map); @@ -114,6 +185,10 @@ } } } - + // classify special GVs last to make sure functions are classified. + for (auto *G : SpecialGVs) { + if (G->getName() == "llvm.global_ctors") + classifyGlobalCtorPointerType(*G, Map); + } return Map; } diff --git a/llvm/test/tools/dxil-dis/global_ctor.ll b/llvm/test/tools/dxil-dis/global_ctor.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/global_ctor.ll @@ -0,0 +1,54 @@ +; RUN: llc --filetype=obj %s -o - 2>&1 | dxil-dis -o - | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-unknown-shadermodel6.7-library" +; Make sure global ctor type is changed to void ()*. +; CHECK:@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_global.hlsl, i8* null }] + +@f = internal unnamed_addr global float 0.000000e+00, align 4 +@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_static_global.hlsl, ptr null }] + +declare float @"?init@@YAMXZ"() local_unnamed_addr #0 + +; Function Attrs: nounwind +define float @"?foo@@YAMXZ"() local_unnamed_addr #1 { +entry: + %0 = load float, ptr @f, align 4, !tbaa !4 + %inc = fadd float %0, 1.000000e+00 + store float %inc, ptr @f, align 4, !tbaa !4 + ret float %0 +} + +; Function Attrs: nounwind +define float @"?bar@@YAMXZ"() local_unnamed_addr #1 { +entry: + %0 = load float, ptr @f, align 4, !tbaa !4 + %dec = fadd float %0, -1.000000e+00 + store float %dec, ptr @f, align 4, !tbaa !4 + ret float %0 +} + +; Function Attrs: nounwind +define internal void @_GLOBAL__sub_I_static_global.hlsl() #1 { +entry: + %call.i = tail call float @"?init@@YAMXZ"() #2 + store float %call.i, ptr @f, align 4, !tbaa !4 + ret void +} + +attributes #0 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} +!dx.valver = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 16.0.0 (https://github.com/llvm/llvm-project.git c5dfff0e58cc66d74e666c31368f6d44328dd2f7)"} +!3 = !{i32 1, i32 7} +!4 = !{!5, !5, i64 0} +!5 = !{!"float", !6, i64 0} +!6 = !{!"omnipotent char", !7, i64 0} +!7 = !{!"Simple C++ TBAA"}