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(); @@ -2097,8 +2107,9 @@ } else if (isa(C) || isa(C) || isa(C)) { Code = bitc::CST_CODE_AGGREGATE; - for (const Value *Op : C->operands()) + for (const Value *Op : C->operands()) { Record.push_back(VE.getValueID(Op)); + } AbbrevToUse = AggregateAbbrev; } else if (const ConstantExpr *CE = dyn_cast(C)) { switch (CE->getOpcode()) { @@ -2106,7 +2117,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 +2139,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 +2542,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,18 @@ 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 +70,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 && !NewRetTy) + 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 +97,55 @@ 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 void classifyGlobalCtorPointerType(const GlobalVariable &GV, + PointerTypeMap &Map) { + // Type for global ctor should be array of { i32, void ()*, i8* }. + Type *Ty = GV.getValueType(); + LLVMContext &Ctx = GV.getContext(); + FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), false); + StructType *CtorEltTy = + StructType::get(Ctx, {Type::getInt32Ty(Ctx), TypedPointerType::get(FT, 0), + TypedPointerType::get(Type::getInt8Ty(Ctx), 0)}); + + const auto *CA = dyn_cast(GV.getInitializer()); + for (const auto &C : CA->operands()) { + if (isa(&C)) + continue; + ConstantStruct *CS = cast(&C); + Function *Ctor = dyn_cast_if_present(CS->getOperand(1)); + if (!Ctor) + continue; + assert(FT == Ctor->getFunctionType() && "invalid global ctor type"); + // Map each Ctor element to CtorEltTy. + Map[CS] = CtorEltTy; + } + + unsigned Size = Ty->getArrayNumElements(); + Type *PointeeTy = ArrayType::get(CtorEltTy, Size); + // Map init type. + Map[CA] = PointeeTy; + + // Map the global type. + Map[&GV] = + TypedPointerType::get(PointeeTy, GV.getType()->getPointerAddressSpace()); +} + PointerTypeMap PointerTypeAnalysis::run(const Module &M) { PointerTypeMap Map; for (auto &G : M.globals()) { if (G.getType()->isOpaquePointerTy()) Map[&G] = classifyPointerType(&G); + if (G.getName() == "llvm.global_ctors") + classifyGlobalCtorPointerType(G, Map); } + for (auto &F : M) { classifyFunctionType(F, 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"} \ No newline at end of file