diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Target/DirectX | |
parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
download | src-145449b1e420787bb99721a429341fa6be3adfb6.tar.gz src-145449b1e420787bb99721a429341fa6be3adfb6.zip |
Vendor import of llvm-project main llvmorg-15-init-15358-g53dc0f107877.vendor/llvm-project/llvmorg-15-init-15358-g53dc0f107877
Diffstat (limited to 'llvm/lib/Target/DirectX')
36 files changed, 6596 insertions, 0 deletions
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td new file mode 100644 index 000000000000..4d6e1a9d3166 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -0,0 +1,144 @@ +//- DXIL.td - Describe DXIL operation -------------------------*- tablegen -*-// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a target description file for DXIL operation. +/// +//===----------------------------------------------------------------------===// + +include "llvm/IR/Intrinsics.td" + +class dxil_class<string _name> { + string name = _name; +} +class dxil_category<string _name> { + string name = _name; +} + +def Unary : dxil_class<"Unary">; +def Binary : dxil_class<"Binary">; +def FlattenedThreadIdInGroupClass : dxil_class<"FlattenedThreadIdInGroup">; +def ThreadIdInGroupClass : dxil_class<"ThreadIdInGroup">; +def ThreadIdClass : dxil_class<"ThreadId">; +def GroupIdClass : dxil_class<"GroupId">; + +def binary_uint : dxil_category<"Binary uint">; +def unary_float : dxil_category<"Unary float">; +def ComputeID : dxil_category<"Compute/Mesh/Amplification shader">; + + +// The parameter description for a DXIL instruction +class dxil_param<int _pos, string type, string _name, string _doc, + bit _is_const = 0, string _enum_name = "", + int _max_value = 0> { + int pos = _pos; // position in parameter list + string llvm_type = type; // llvm type name, $o for overload, $r for resource + // type, $cb for legacy cbuffer, $u4 for u4 struct + string name = _name; // short, unique name + string doc = _doc; // the documentation description of this parameter + bit is_const = + _is_const; // whether this argument requires a constant value in the IR + string enum_name = _enum_name; // the name of the enum type if applicable + int max_value = + _max_value; // the maximum value for this parameter if applicable +} + +// A representation for a DXIL instruction +class dxil_inst<string _name> { + string name = _name; // short, unique name + + string dxil_op = ""; // name of DXIL operation + int dxil_opid = 0; // ID of DXIL operation + dxil_class op_class; // name of the opcode class + dxil_category category; // classification for this instruction + string doc = ""; // the documentation description of this instruction + list<dxil_param> ops = []; // the operands that this instruction takes + string oload_types = ""; // overload types if applicable + string fn_attr = ""; // attribute shorthands: rn=does not access + // memory,ro=only reads from memory, + bit is_deriv = 0; // whether this is some kind of derivative + bit is_gradient = 0; // whether this requires a gradient calculation + bit is_feedback = 0; // whether this is a sampler feedback op + bit is_wave = 0; // whether this requires in-wave, cross-lane functionality + bit requires_uniform_inputs = 0; // whether this operation requires that all + // of its inputs are uniform across the wave + // Group dxil operation for stats. + // Like how many atomic/float/uint/int/... instructions used in the program. + list<string> stats_group = []; +} + +class dxil_op<string name, int code_id, dxil_class code_class, dxil_category op_category, string _doc, + string _oload_types, string _fn_attr, list<dxil_param> op_params, + list<string> _stats_group = []> : dxil_inst<name> { + let dxil_op = name; + let dxil_opid = code_id; + let doc = _doc; + let ops = op_params; + let op_class = code_class; + let category = op_category; + let oload_types = _oload_types; + let fn_attr = _fn_attr; + let stats_group = _stats_group; +} + +// The intrinsic which map directly to this dxil op. +class dxil_map_intrinsic<Intrinsic llvm_intrinsic_> { Intrinsic llvm_intrinsic = llvm_intrinsic_; } + +def Sin : dxil_op<"Sin", 13, Unary, unary_float, "returns sine(theta) for theta in radians.", + "half;float;", "rn", + [ + dxil_param<0, "$o", "", "operation result">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "$o", "value", "input value"> + ], + ["floats"]>, + dxil_map_intrinsic<int_sin>; + +def UMax :dxil_op< "UMax", 39, Binary, binary_uint, "unsigned integer maximum. UMax(a,b) = a > b ? a : b", + "i16;i32;i64;", "rn", + [ + dxil_param<0, "$o", "", "operation result">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "$o", "a", "input value">, + dxil_param<3, "$o", "b", "input value"> + ], + ["uints"]>, + dxil_map_intrinsic<int_umax>; + +def ThreadId :dxil_op< "ThreadId", 93, ThreadIdClass, ComputeID, "reads the thread ID", "i32;", "rn", + [ + dxil_param<0, "i32", "", "thread ID component">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "i32", "component", "component to read (x,y,z)"> + ]>, + dxil_map_intrinsic<int_dxil_thread_id>; + +def GroupId :dxil_op< "GroupId", 94, GroupIdClass, ComputeID, "reads the group ID (SV_GroupID)", "i32;", "rn", + [ + dxil_param<0, "i32", "", "group ID component">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "i32", "component", "component to read"> + ]>, + dxil_map_intrinsic<int_dxil_group_id>; + +def ThreadIdInGroup :dxil_op< "ThreadIdInGroup", 95, ThreadIdInGroupClass, ComputeID, + "reads the thread ID within the group (SV_GroupThreadID)", "i32;", "rn", + [ + dxil_param<0, "i32", "", "thread ID in group component">, + dxil_param<1, "i32", "opcode", "DXIL opcode">, + dxil_param<2, "i32", "component", "component to read (x,y,z)"> + ]>, + dxil_map_intrinsic<int_dxil_thread_id_in_group>; + +def FlattenedThreadIdInGroup :dxil_op< "FlattenedThreadIdInGroup", 96, FlattenedThreadIdInGroupClass, ComputeID, + "provides a flattened index for a given thread within a given group (SV_GroupIndex)", "i32;", "rn", + [ + dxil_param<0, "i32", "", "result">, + dxil_param<1, "i32", "opcode", "DXIL opcode"> + ]>, + dxil_map_intrinsic<int_dxil_flattened_thread_id_in_group>; diff --git a/llvm/lib/Target/DirectX/DXILConstants.h b/llvm/lib/Target/DirectX/DXILConstants.h new file mode 100644 index 000000000000..e8e7b5396a46 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILConstants.h @@ -0,0 +1,25 @@ +//===- DXILConstants.h - Essential DXIL constants -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file This file contains essential DXIL constants. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_DIRECTX_DXILCONSTANTS_H +#define LLVM_LIB_TARGET_DIRECTX_DXILCONSTANTS_H + +namespace llvm { +namespace DXIL { + +#define DXIL_OP_ENUM +#include "DXILOperation.inc" +#undef DXIL_OP_ENUM + +} // namespace DXIL +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp new file mode 100644 index 000000000000..11b89e4ec890 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -0,0 +1,265 @@ +//===- DXILOpLower.cpp - Lowering LLVM intrinsic to DIXLOp function -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file This file contains passes and utilities to lower llvm intrinsic call +/// to DXILOp function call. +//===----------------------------------------------------------------------===// + +#include "DXILConstants.h" +#include "DirectX.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsDirectX.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Support/ErrorHandling.h" + +#define DEBUG_TYPE "dxil-op-lower" + +using namespace llvm; +using namespace llvm::DXIL; + +constexpr StringLiteral DXILOpNamePrefix = "dx.op."; + +enum OverloadKind : uint16_t { + VOID = 1, + HALF = 1 << 1, + FLOAT = 1 << 2, + DOUBLE = 1 << 3, + I1 = 1 << 4, + I8 = 1 << 5, + I16 = 1 << 6, + I32 = 1 << 7, + I64 = 1 << 8, + UserDefineType = 1 << 9, + ObjectType = 1 << 10, +}; + +static const char *getOverloadTypeName(OverloadKind Kind) { + switch (Kind) { + case OverloadKind::HALF: + return "f16"; + case OverloadKind::FLOAT: + return "f32"; + case OverloadKind::DOUBLE: + return "f64"; + case OverloadKind::I1: + return "i1"; + case OverloadKind::I8: + return "i8"; + case OverloadKind::I16: + return "i16"; + case OverloadKind::I32: + return "i32"; + case OverloadKind::I64: + return "i64"; + case OverloadKind::VOID: + case OverloadKind::ObjectType: + case OverloadKind::UserDefineType: + break; + } + llvm_unreachable("invalid overload type for name"); + return "void"; +} + +static OverloadKind getOverloadKind(Type *Ty) { + Type::TypeID T = Ty->getTypeID(); + switch (T) { + case Type::VoidTyID: + return OverloadKind::VOID; + case Type::HalfTyID: + return OverloadKind::HALF; + case Type::FloatTyID: + return OverloadKind::FLOAT; + case Type::DoubleTyID: + return OverloadKind::DOUBLE; + case Type::IntegerTyID: { + IntegerType *ITy = cast<IntegerType>(Ty); + unsigned Bits = ITy->getBitWidth(); + switch (Bits) { + case 1: + return OverloadKind::I1; + case 8: + return OverloadKind::I8; + case 16: + return OverloadKind::I16; + case 32: + return OverloadKind::I32; + case 64: + return OverloadKind::I64; + default: + llvm_unreachable("invalid overload type"); + return OverloadKind::VOID; + } + } + case Type::PointerTyID: + return OverloadKind::UserDefineType; + case Type::StructTyID: + return OverloadKind::ObjectType; + default: + llvm_unreachable("invalid overload type"); + return OverloadKind::VOID; + } +} + +static std::string getTypeName(OverloadKind Kind, Type *Ty) { + if (Kind < OverloadKind::UserDefineType) { + return getOverloadTypeName(Kind); + } else if (Kind == OverloadKind::UserDefineType) { + StructType *ST = cast<StructType>(Ty); + return ST->getStructName().str(); + } else if (Kind == OverloadKind::ObjectType) { + StructType *ST = cast<StructType>(Ty); + return ST->getStructName().str(); + } else { + std::string Str; + raw_string_ostream OS(Str); + Ty->print(OS); + return OS.str(); + } +} + +// Static properties. +struct OpCodeProperty { + DXIL::OpCode OpCode; + // Offset in DXILOpCodeNameTable. + unsigned OpCodeNameOffset; + DXIL::OpCodeClass OpCodeClass; + // Offset in DXILOpCodeClassNameTable. + unsigned OpCodeClassNameOffset; + uint16_t OverloadTys; + llvm::Attribute::AttrKind FuncAttr; +}; + +// Include getOpCodeClassName getOpCodeProperty and getOpCodeName which +// generated by tableGen. +#define DXIL_OP_OPERATION_TABLE +#include "DXILOperation.inc" +#undef DXIL_OP_OPERATION_TABLE + +static std::string constructOverloadName(OverloadKind Kind, Type *Ty, + const OpCodeProperty &Prop) { + if (Kind == OverloadKind::VOID) { + return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str(); + } + return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." + + getTypeName(Kind, Ty)) + .str(); +} + +static FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F, + Module &M) { + const OpCodeProperty *Prop = getOpCodeProperty(DXILOp); + + // Get return type as overload type for DXILOp. + // Only simple mapping case here, so return type is good enough. + Type *OverloadTy = F.getReturnType(); + + OverloadKind Kind = getOverloadKind(OverloadTy); + // FIXME: find the issue and report error in clang instead of check it in + // backend. + if ((Prop->OverloadTys & (uint16_t)Kind) == 0) { + llvm_unreachable("invalid overload"); + } + + std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop); + assert(!M.getFunction(FnName) && "Function already exists"); + + auto &Ctx = M.getContext(); + Type *OpCodeTy = Type::getInt32Ty(Ctx); + + SmallVector<Type *> ArgTypes; + // DXIL has i32 opcode as first arg. + ArgTypes.emplace_back(OpCodeTy); + FunctionType *FT = F.getFunctionType(); + ArgTypes.append(FT->param_begin(), FT->param_end()); + FunctionType *DXILOpFT = FunctionType::get(OverloadTy, ArgTypes, false); + return M.getOrInsertFunction(FnName, DXILOpFT); +} + +static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M) { + auto DXILOpFn = createDXILOpFunction(DXILOp, F, M); + IRBuilder<> B(M.getContext()); + Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp)); + for (User *U : make_early_inc_range(F.users())) { + CallInst *CI = dyn_cast<CallInst>(U); + if (!CI) + continue; + + SmallVector<Value *> Args; + Args.emplace_back(DXILOpArg); + Args.append(CI->arg_begin(), CI->arg_end()); + B.SetInsertPoint(CI); + CallInst *DXILCI = B.CreateCall(DXILOpFn, Args); + LLVM_DEBUG(DXILCI->setName(getOpCodeName(DXILOp))); + CI->replaceAllUsesWith(DXILCI); + CI->eraseFromParent(); + } + if (F.user_empty()) + F.eraseFromParent(); +} + +static bool lowerIntrinsics(Module &M) { + bool Updated = false; + +#define DXIL_OP_INTRINSIC_MAP +#include "DXILOperation.inc" +#undef DXIL_OP_INTRINSIC_MAP + + for (Function &F : make_early_inc_range(M.functions())) { + if (!F.isDeclaration()) + continue; + Intrinsic::ID ID = F.getIntrinsicID(); + if (ID == Intrinsic::not_intrinsic) + continue; + auto LowerIt = LowerMap.find(ID); + if (LowerIt == LowerMap.end()) + continue; + lowerIntrinsic(LowerIt->second, F, M); + Updated = true; + } + return Updated; +} + +namespace { +/// A pass that transforms external global definitions into declarations. +class DXILOpLowering : public PassInfoMixin<DXILOpLowering> { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { + if (lowerIntrinsics(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); + } +}; +} // namespace + +namespace { +class DXILOpLoweringLegacy : public ModulePass { +public: + bool runOnModule(Module &M) override { return lowerIntrinsics(M); } + StringRef getPassName() const override { return "DXIL Op Lowering"; } + DXILOpLoweringLegacy() : ModulePass(ID) {} + + static char ID; // Pass identification. +}; +char DXILOpLoweringLegacy::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", + false, false) +INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false, + false) + +ModulePass *llvm::createDXILOpLoweringLegacyPass() { + return new DXILOpLoweringLegacy(); +} diff --git a/llvm/lib/Target/DirectX/DXILPointerType.cpp b/llvm/lib/Target/DirectX/DXILPointerType.cpp new file mode 100644 index 000000000000..1e67f1a30ec4 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILPointerType.cpp @@ -0,0 +1,66 @@ +//===- Target/DirectX/DXILTypedPointerType.cpp - DXIL Typed Pointer Type +//-------===// +// +// 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 "DXILPointerType.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/LLVMContext.h" + +using namespace llvm; +using namespace llvm::dxil; + +class TypedPointerTracking { +public: + TypedPointerTracking() {} + DenseMap<Type *, std::unique_ptr<TypedPointerType>> PointerTypes; + DenseMap<std::pair<Type *, unsigned>, std::unique_ptr<TypedPointerType>> + ASPointerTypes; +}; + +TypedPointerType *TypedPointerType::get(Type *EltTy, unsigned AddressSpace) { + assert(EltTy && "Can't get a pointer to <null> type!"); + assert(isValidElementType(EltTy) && "Invalid type for pointer element!"); + + llvm::Any &TargetData = EltTy->getContext().getTargetData(); + if (!TargetData.hasValue()) + TargetData = Any{std::make_shared<TypedPointerTracking>()}; + + assert(any_isa<std::shared_ptr<TypedPointerTracking>>(TargetData) && + "Unexpected target data type"); + + std::shared_ptr<TypedPointerTracking> Tracking = + any_cast<std::shared_ptr<TypedPointerTracking>>(TargetData); + + // Since AddressSpace #0 is the common case, we special case it. + std::unique_ptr<TypedPointerType> &Entry = + AddressSpace == 0 + ? Tracking->PointerTypes[EltTy] + : Tracking->ASPointerTypes[std::make_pair(EltTy, AddressSpace)]; + + if (!Entry) + Entry = std::unique_ptr<TypedPointerType>( + new TypedPointerType(EltTy, AddressSpace)); + return Entry.get(); +} + +TypedPointerType::TypedPointerType(Type *E, unsigned AddrSpace) + : Type(E->getContext(), DXILPointerTyID), PointeeTy(E) { + ContainedTys = &PointeeTy; + NumContainedTys = 1; + setSubclassData(AddrSpace); +} + +bool TypedPointerType::isValidElementType(Type *ElemTy) { + return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && + !ElemTy->isMetadataTy() && !ElemTy->isTokenTy() && + !ElemTy->isX86_AMXTy(); +} diff --git a/llvm/lib/Target/DirectX/DXILPointerType.h b/llvm/lib/Target/DirectX/DXILPointerType.h new file mode 100644 index 000000000000..52cf2dbc40b0 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILPointerType.h @@ -0,0 +1,52 @@ +//===- Target/DirectX/DXILPointerType.h - DXIL Typed Pointer Type ---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_DIRECTX_DXILPOINTERTYPE_H +#define LLVM_TARGET_DIRECTX_DXILPOINTERTYPE_H + +#include "llvm/IR/Type.h" + +namespace llvm { +namespace dxil { + +// DXIL has typed pointers, this pointer type abstraction is used for tracking +// in PointerTypeAnalysis and for the bitcode ValueEnumerator +class TypedPointerType : public Type { + explicit TypedPointerType(Type *ElType, unsigned AddrSpace); + + Type *PointeeTy; + +public: + TypedPointerType(const TypedPointerType &) = delete; + TypedPointerType &operator=(const TypedPointerType &) = delete; + + /// This constructs a pointer to an object of the specified type in a numbered + /// address space. + static TypedPointerType *get(Type *ElementType, unsigned AddressSpace); + + /// Return true if the specified type is valid as a element type. + static bool isValidElementType(Type *ElemTy); + + /// Return the address space of the Pointer type. + unsigned getAddressSpace() const { return getSubclassData(); } + + Type *getElementType() const { return PointeeTy; } + + /// Implement support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Type *T) { + return T->getTypeID() == DXILPointerTyID; + } +}; + +} // namespace dxil +} // namespace llvm + +#endif // LLVM_TARGET_DIRECTX_DXILPOINTERTYPE_H diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp new file mode 100644 index 000000000000..14d970e6b69a --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp @@ -0,0 +1,184 @@ +//===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file This file contains pases and utilities to convert a modern LLVM +/// module into a module compatible with the LLVM 3.7-based DirectX Intermediate +/// Language (DXIL). +//===----------------------------------------------------------------------===// + +#include "DirectX.h" +#include "PointerTypeAnalysis.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Compiler.h" + +#define DEBUG_TYPE "dxil-prepare" + +using namespace llvm; +using namespace llvm::dxil; + +namespace { + +constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { + return is_contained({Attribute::Alignment, + Attribute::AlwaysInline, + Attribute::Builtin, + Attribute::ByVal, + Attribute::InAlloca, + Attribute::Cold, + Attribute::Convergent, + Attribute::InlineHint, + Attribute::InReg, + Attribute::JumpTable, + Attribute::MinSize, + Attribute::Naked, + Attribute::Nest, + Attribute::NoAlias, + Attribute::NoBuiltin, + Attribute::NoCapture, + Attribute::NoDuplicate, + Attribute::NoImplicitFloat, + Attribute::NoInline, + Attribute::NonLazyBind, + Attribute::NonNull, + Attribute::Dereferenceable, + Attribute::DereferenceableOrNull, + Attribute::NoRedZone, + Attribute::NoReturn, + Attribute::NoUnwind, + Attribute::OptimizeForSize, + Attribute::OptimizeNone, + Attribute::ReadNone, + Attribute::ReadOnly, + Attribute::ArgMemOnly, + Attribute::Returned, + Attribute::ReturnsTwice, + Attribute::SExt, + Attribute::StackAlignment, + Attribute::StackProtect, + Attribute::StackProtectReq, + Attribute::StackProtectStrong, + Attribute::SafeStack, + Attribute::StructRet, + Attribute::SanitizeAddress, + Attribute::SanitizeThread, + Attribute::SanitizeMemory, + Attribute::UWTable, + Attribute::ZExt}, + Attr); +} + +class DXILPrepareModule : public ModulePass { + + static Value *maybeGenerateBitcast(IRBuilder<> &Builder, + PointerTypeMap &PointerTypes, + Instruction &Inst, Value *Operand, + Type *Ty) { + // Omit bitcasts if the incoming value matches the instruction type. + auto It = PointerTypes.find(Operand); + if (It != PointerTypes.end()) + if (cast<TypedPointerType>(It->second)->getElementType() == Ty) + return nullptr; + // Insert bitcasts where we are removing the instruction. + Builder.SetInsertPoint(&Inst); + // This code only gets hit in opaque-pointer mode, so the type of the + // pointer doesn't matter. + PointerType *PtrTy = cast<PointerType>(Operand->getType()); + return Builder.Insert( + CastInst::Create(Instruction::BitCast, Operand, + Builder.getInt8PtrTy(PtrTy->getAddressSpace()))); + } + +public: + bool runOnModule(Module &M) override { + PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); + AttributeMask AttrMask; + for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; + I = Attribute::AttrKind(I + 1)) { + if (!isValidForDXIL(I)) + AttrMask.addAttribute(I); + } + for (auto &F : M.functions()) { + F.removeFnAttrs(AttrMask); + F.removeRetAttrs(AttrMask); + for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) + F.removeParamAttrs(Idx, AttrMask); + + for (auto &BB : F) { + IRBuilder<> Builder(&BB); + for (auto &I : make_early_inc_range(BB)) { + if (I.getOpcode() == Instruction::FNeg) { + Builder.SetInsertPoint(&I); + Value *In = I.getOperand(0); + Value *Zero = ConstantFP::get(In->getType(), -0.0); + I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); + I.eraseFromParent(); + continue; + } + // Only insert bitcasts if the IR is using opaque pointers. + if (M.getContext().supportsTypedPointers()) + continue; + + // Emtting NoOp bitcast instructions allows the ValueEnumerator to be + // unmodified as it reserves instruction IDs during contruction. + if (auto LI = dyn_cast<LoadInst>(&I)) { + if (Value *NoOpBitcast = maybeGenerateBitcast( + Builder, PointerTypes, I, LI->getPointerOperand(), + LI->getType())) { + LI->replaceAllUsesWith( + Builder.CreateLoad(LI->getType(), NoOpBitcast)); + LI->eraseFromParent(); + } + continue; + } + if (auto SI = dyn_cast<StoreInst>(&I)) { + if (Value *NoOpBitcast = maybeGenerateBitcast( + Builder, PointerTypes, I, SI->getPointerOperand(), + SI->getValueOperand()->getType())) { + + SI->replaceAllUsesWith( + Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); + SI->eraseFromParent(); + } + continue; + } + if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { + if (Value *NoOpBitcast = maybeGenerateBitcast( + Builder, PointerTypes, I, GEP->getPointerOperand(), + GEP->getResultElementType())) + GEP->setOperand(0, NoOpBitcast); + continue; + } + } + } + } + return true; + } + + DXILPrepareModule() : ModulePass(ID) {} + + static char ID; // Pass identification. +}; +char DXILPrepareModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", + false, false) +INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, + false) + +ModulePass *llvm::createDXILPrepareModulePass() { + return new DXILPrepareModule(); +} diff --git a/llvm/lib/Target/DirectX/DXILStubs.td b/llvm/lib/Target/DirectX/DXILStubs.td new file mode 100644 index 000000000000..ce4327f93bc1 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILStubs.td @@ -0,0 +1,18 @@ +// DXIL doesn't actually use registers, but this gets the boilerplate code +// generated through tablegen. +let Namespace = "DXIL" in { +def DXIL : Register<"DXIL">; +def DXILClass : RegisterClass<"DXIL", [i32], 32, (add DXIL)>; +} + +class DXILInst : Instruction { + let Namespace = "DXIL"; + let DecoderNamespace = "DXIL"; + + dag OutOperandList = (outs); + dag InOperandList = (ins); + let AsmString = "dummy"; + let Pattern = []; +} + +def DummyInst : DXILInst; diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp new file mode 100644 index 000000000000..634ead98a6ae --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp @@ -0,0 +1,121 @@ +//===- DXILTranslateMetadata.cpp - Pass to emit DXIL metadata ---*- C++ -*-===// +// +// 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 "DirectX.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" + +using namespace llvm; + +static uint32_t ConstMDToUint32(const MDOperand &MDO) { + ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); + return (uint32_t)pConst->getZExtValue(); +} + +static ConstantAsMetadata *Uint32ToConstMD(unsigned v, LLVMContext &Ctx) { + return ConstantAsMetadata::get( + Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v))); +} + +constexpr StringLiteral ValVerKey = "dx.valver"; +constexpr unsigned DXILVersionNumFields = 2; + +static void emitDXILValidatorVersion(Module &M, VersionTuple &ValidatorVer) { + NamedMDNode *DXILValidatorVersionMD = M.getNamedMetadata(ValVerKey); + + // Allow re-writing the validator version, since this can be changed at + // later points. + if (DXILValidatorVersionMD) + M.eraseNamedMetadata(DXILValidatorVersionMD); + + DXILValidatorVersionMD = M.getOrInsertNamedMetadata(ValVerKey); + + auto &Ctx = M.getContext(); + Metadata *MDVals[DXILVersionNumFields]; + MDVals[0] = Uint32ToConstMD(ValidatorVer.getMajor(), Ctx); + MDVals[1] = Uint32ToConstMD(ValidatorVer.getMinor().value_or(0), Ctx); + + DXILValidatorVersionMD->addOperand(MDNode::get(Ctx, MDVals)); +} + +static VersionTuple loadDXILValidatorVersion(MDNode *ValVerMD) { + if (ValVerMD->getNumOperands() != DXILVersionNumFields) + return VersionTuple(); + + unsigned Major = ConstMDToUint32(ValVerMD->getOperand(0)); + unsigned Minor = ConstMDToUint32(ValVerMD->getOperand(1)); + return VersionTuple(Major, Minor); +} + +static void cleanModuleFlags(Module &M) { + constexpr StringLiteral DeadKeys[] = {ValVerKey}; + // Collect DeadKeys in ModuleFlags. + StringSet<> DeadKeySet; + for (auto &Key : DeadKeys) { + if (M.getModuleFlag(Key)) + DeadKeySet.insert(Key); + } + if (DeadKeySet.empty()) + return; + + SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; + M.getModuleFlagsMetadata(ModuleFlags); + NamedMDNode *MDFlags = M.getModuleFlagsMetadata(); + MDFlags->eraseFromParent(); + // Add ModuleFlag which not dead. + for (auto &Flag : ModuleFlags) { + StringRef Key = Flag.Key->getString(); + if (DeadKeySet.contains(Key)) + continue; + M.addModuleFlag(Flag.Behavior, Key, Flag.Val); + } +} + +static void cleanModule(Module &M) { cleanModuleFlags(M); } + +namespace { +class DXILTranslateMetadata : public ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + explicit DXILTranslateMetadata() : ModulePass(ID), ValidatorVer(1, 0) {} + + StringRef getPassName() const override { return "DXIL Metadata Emit"; } + + bool runOnModule(Module &M) override; + +private: + VersionTuple ValidatorVer; +}; + +} // namespace + +bool DXILTranslateMetadata::runOnModule(Module &M) { + if (MDNode *ValVerMD = cast_or_null<MDNode>(M.getModuleFlag(ValVerKey))) { + auto ValVer = loadDXILValidatorVersion(ValVerMD); + if (!ValVer.empty()) + ValidatorVer = ValVer; + } + emitDXILValidatorVersion(M, ValidatorVer); + cleanModule(M); + return false; +} + +char DXILTranslateMetadata::ID = 0; + +ModulePass *llvm::createDXILTranslateMetadataPass() { + return new DXILTranslateMetadata(); +} + +INITIALIZE_PASS(DXILTranslateMetadata, "dxil-metadata-emit", + "DXIL Metadata Emit", false, false) diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp new file mode 100644 index 000000000000..494a71e51a89 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp @@ -0,0 +1,2963 @@ +//===- Bitcode/Writer/DXILBitcodeWriter.cpp - DXIL Bitcode 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 +// +//===----------------------------------------------------------------------===// +// +// Bitcode writer implementation. +// +//===----------------------------------------------------------------------===// + +#include "DXILBitcodeWriter.h" +#include "DXILValueEnumerator.h" +#include "PointerTypeAnalysis.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/BitcodeCommon.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Comdat.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" +#include "llvm/IR/GlobalObject.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/UseListOrder.h" +#include "llvm/IR/Value.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Object/IRSymtab.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SHA1.h" + +namespace llvm { +namespace dxil { + +// Generates an enum to use as an index in the Abbrev array of Metadata record. +enum MetadataAbbrev : unsigned { +#define HANDLE_MDNODE_LEAF(CLASS) CLASS##AbbrevID, +#include "llvm/IR/Metadata.def" + LastPlusOne +}; + +class DXILBitcodeWriter { + + /// These are manifest constants used by the bitcode writer. They do not need + /// to be kept in sync with the reader, but need to be consistent within this + /// file. + enum { + // VALUE_SYMTAB_BLOCK abbrev id's. + VST_ENTRY_8_ABBREV = bitc::FIRST_APPLICATION_ABBREV, + VST_ENTRY_7_ABBREV, + VST_ENTRY_6_ABBREV, + VST_BBENTRY_6_ABBREV, + + // CONSTANTS_BLOCK abbrev id's. + CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV, + CONSTANTS_INTEGER_ABBREV, + CONSTANTS_CE_CAST_Abbrev, + CONSTANTS_NULL_Abbrev, + + // FUNCTION_BLOCK abbrev id's. + FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV, + FUNCTION_INST_BINOP_ABBREV, + FUNCTION_INST_BINOP_FLAGS_ABBREV, + FUNCTION_INST_CAST_ABBREV, + FUNCTION_INST_RET_VOID_ABBREV, + FUNCTION_INST_RET_VAL_ABBREV, + FUNCTION_INST_UNREACHABLE_ABBREV, + FUNCTION_INST_GEP_ABBREV, + }; + + // Cache some types + Type *I8Ty; + Type *I8PtrTy; + + /// The stream created and owned by the client. + BitstreamWriter &Stream; + + StringTableBuilder &StrtabBuilder; + + /// The Module to write to bitcode. + const Module &M; + + /// Enumerates ids for all values in the module. + ValueEnumerator VE; + + /// Map that holds the correspondence between GUIDs in the summary index, + /// that came from indirect call profiles, and a value id generated by this + /// class to use in the VST and summary block records. + std::map<GlobalValue::GUID, unsigned> GUIDToValueIdMap; + + /// Tracks the last value id recorded in the GUIDToValueMap. + unsigned GlobalValueId; + + /// Saves the offset of the VSTOffset record that must eventually be + /// backpatched with the offset of the actual VST. + uint64_t VSTOffsetPlaceholder = 0; + + /// Pointer to the buffer allocated by caller for bitcode writing. + const SmallVectorImpl<char> &Buffer; + + /// 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<char> &Buffer, + StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream) + : 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. + void write(); + + static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind); + static void writeStringRecord(BitstreamWriter &Stream, unsigned Code, + StringRef Str, unsigned AbbrevToUse); + static void writeIdentificationBlock(BitstreamWriter &Stream); + static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V); + static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A); + + static unsigned getEncodedComdatSelectionKind(const Comdat &C); + static unsigned getEncodedLinkage(const GlobalValue::LinkageTypes Linkage); + static unsigned getEncodedLinkage(const GlobalValue &GV); + static unsigned getEncodedVisibility(const GlobalValue &GV); + static unsigned getEncodedThreadLocalMode(const GlobalValue &GV); + static unsigned getEncodedDLLStorageClass(const GlobalValue &GV); + static unsigned getEncodedCastOpcode(unsigned Opcode); + static unsigned getEncodedUnaryOpcode(unsigned Opcode); + static unsigned getEncodedBinaryOpcode(unsigned Opcode); + static unsigned getEncodedRMWOperation(AtomicRMWInst::BinOp Op); + static unsigned getEncodedOrdering(AtomicOrdering Ordering); + static uint64_t getOptimizationFlags(const Value *V); + +private: + void writeModuleVersion(); + void writePerModuleGlobalValueSummary(); + + void writePerModuleFunctionSummaryRecord(SmallVector<uint64_t, 64> &NameVals, + GlobalValueSummary *Summary, + unsigned ValueID, + unsigned FSCallsAbbrev, + unsigned FSCallsProfileAbbrev, + const Function &F); + void writeModuleLevelReferences(const GlobalVariable &V, + SmallVector<uint64_t, 64> &NameVals, + unsigned FSModRefsAbbrev, + unsigned FSModVTableRefsAbbrev); + + void assignValueId(GlobalValue::GUID ValGUID) { + GUIDToValueIdMap[ValGUID] = ++GlobalValueId; + } + + unsigned getValueId(GlobalValue::GUID ValGUID) { + const auto &VMI = GUIDToValueIdMap.find(ValGUID); + // Expect that any GUID value had a value Id assigned by an + // earlier call to assignValueId. + assert(VMI != GUIDToValueIdMap.end() && + "GUID does not have assigned value Id"); + return VMI->second; + } + + // Helper to get the valueId for the type of value recorded in VI. + unsigned getValueId(ValueInfo VI) { + if (!VI.haveGVs() || !VI.getValue()) + return getValueId(VI.getGUID()); + return VE.getValueID(VI.getValue()); + } + + std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; } + + uint64_t bitcodeStartBit() { return BitcodeStartBit; } + + size_t addToStrtab(StringRef Str); + + unsigned createDILocationAbbrev(); + unsigned createGenericDINodeAbbrev(); + + void writeAttributeGroupTable(); + void writeAttributeTable(); + void writeTypeTable(); + void writeComdats(); + void writeValueSymbolTableForwardDecl(); + void writeModuleInfo(); + void writeValueAsMetadata(const ValueAsMetadata *MD, + SmallVectorImpl<uint64_t> &Record); + void writeMDTuple(const MDTuple *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDILocation(const DILocation *N, SmallVectorImpl<uint64_t> &Record, + unsigned &Abbrev); + void writeGenericDINode(const GenericDINode *N, + SmallVectorImpl<uint64_t> &Record, unsigned &Abbrev) { + llvm_unreachable("DXIL cannot contain GenericDI Nodes"); + } + void writeDISubrange(const DISubrange *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDIGenericSubrange(const DIGenericSubrange *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIGenericSubrange Nodes"); + } + void writeDIEnumerator(const DIEnumerator *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDIBasicType(const DIBasicType *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDIStringType(const DIStringType *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIStringType Nodes"); + } + void writeDIDerivedType(const DIDerivedType *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDICompositeType(const DICompositeType *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDISubroutineType(const DISubroutineType *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDIFile(const DIFile *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDICompileUnit(const DICompileUnit *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDISubprogram(const DISubprogram *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDILexicalBlock(const DILexicalBlock *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDILexicalBlockFile(const DILexicalBlockFile *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDICommonBlock(const DICommonBlock *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DICommonBlock Nodes"); + } + void writeDINamespace(const DINamespace *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDIMacro(const DIMacro *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIMacro Nodes"); + } + void writeDIMacroFile(const DIMacroFile *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIMacroFile Nodes"); + } + void writeDIArgList(const DIArgList *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIArgList Nodes"); + } + void writeDIModule(const DIModule *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDITemplateTypeParameter(const DITemplateTypeParameter *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDITemplateValueParameter(const DITemplateValueParameter *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDIGlobalVariable(const DIGlobalVariable *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + void writeDILocalVariable(const DILocalVariable *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDILabel(const DILabel *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DILabel Nodes"); + } + void writeDIExpression(const DIExpression *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDIGlobalVariableExpression(const DIGlobalVariableExpression *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain GlobalVariableExpression Nodes"); + } + void writeDIObjCProperty(const DIObjCProperty *N, + SmallVectorImpl<uint64_t> &Record, unsigned Abbrev); + void writeDIImportedEntity(const DIImportedEntity *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev); + unsigned createNamedMetadataAbbrev(); + void writeNamedMetadata(SmallVectorImpl<uint64_t> &Record); + unsigned createMetadataStringsAbbrev(); + void writeMetadataStrings(ArrayRef<const Metadata *> Strings, + SmallVectorImpl<uint64_t> &Record); + void writeMetadataRecords(ArrayRef<const Metadata *> MDs, + SmallVectorImpl<uint64_t> &Record, + std::vector<unsigned> *MDAbbrevs = nullptr, + std::vector<uint64_t> *IndexPos = nullptr); + void writeModuleMetadata(); + void writeFunctionMetadata(const Function &F); + void writeFunctionMetadataAttachment(const Function &F); + void pushGlobalMetadataAttachment(SmallVectorImpl<uint64_t> &Record, + const GlobalObject &GO); + void writeModuleMetadataKinds(); + void writeOperandBundleTags(); + void writeSyncScopeNames(); + void writeConstants(unsigned FirstVal, unsigned LastVal, bool isGlobal); + void writeModuleConstants(); + bool pushValueAndType(const Value *V, unsigned InstID, + SmallVectorImpl<unsigned> &Vals); + void writeOperandBundles(const CallBase &CB, unsigned InstID); + void pushValue(const Value *V, unsigned InstID, + SmallVectorImpl<unsigned> &Vals); + void pushValueSigned(const Value *V, unsigned InstID, + SmallVectorImpl<uint64_t> &Vals); + void writeInstruction(const Instruction &I, unsigned InstID, + SmallVectorImpl<unsigned> &Vals); + void writeFunctionLevelValueSymbolTable(const ValueSymbolTable &VST); + void writeGlobalValueSymbolTable( + DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex); + void writeUseList(UseListOrder &&Order); + void writeUseListBlock(const Function *F); + void writeFunction(const Function &F); + void writeBlockInfo(); + + 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 +} // namespace llvm + +using namespace llvm; +using namespace llvm::dxil; + +//////////////////////////////////////////////////////////////////////////////// +/// Begin dxil::BitcodeWriter Implementation +//////////////////////////////////////////////////////////////////////////////// + +dxil::BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer, + raw_fd_stream *FS) + : Buffer(Buffer), Stream(new BitstreamWriter(Buffer, FS, 512)) { + // Emit the file header. + Stream->Emit((unsigned)'B', 8); + Stream->Emit((unsigned)'C', 8); + Stream->Emit(0x0, 4); + Stream->Emit(0xC, 4); + Stream->Emit(0xE, 4); + Stream->Emit(0xD, 4); +} + +dxil::BitcodeWriter::~BitcodeWriter() { assert(WroteStrtab); } + +/// Write the specified module to the specified output stream. +void dxil::WriteDXILToFile(const Module &M, raw_ostream &Out) { + SmallVector<char, 0> Buffer; + Buffer.reserve(256 * 1024); + + // If this is darwin or another generic macho target, reserve space for the + // header. + Triple TT(M.getTargetTriple()); + if (TT.isOSDarwin() || TT.isOSBinFormatMachO()) + Buffer.insert(Buffer.begin(), BWH_HeaderSize, 0); + + BitcodeWriter Writer(Buffer, dyn_cast<raw_fd_stream>(&Out)); + Writer.writeModule(M); + Writer.writeSymtab(); + Writer.writeStrtab(); + + // Write the generated bitstream to "Out". + if (!Buffer.empty()) + Out.write((char *)&Buffer.front(), Buffer.size()); +} + +void BitcodeWriter::writeBlob(unsigned Block, unsigned Record, StringRef Blob) { + Stream->EnterSubblock(Block, 3); + + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(Record)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + auto AbbrevNo = Stream->EmitAbbrev(std::move(Abbv)); + + Stream->EmitRecordWithBlob(AbbrevNo, ArrayRef<uint64_t>{Record}, Blob); + + Stream->ExitBlock(); +} + +void BitcodeWriter::writeSymtab() { + assert(!WroteStrtab && !WroteSymtab); + + // If any module has module-level inline asm, we will require a registered asm + // parser for the target so that we can create an accurate symbol table for + // the module. + for (Module *M : Mods) { + if (M->getModuleInlineAsm().empty()) + continue; + } + + WroteSymtab = true; + SmallVector<char, 0> Symtab; + // The irsymtab::build function may be unable to create a symbol table if the + // module is malformed (e.g. it contains an invalid alias). Writing a symbol + // table is not required for correctness, but we still want to be able to + // write malformed modules to bitcode files, so swallow the error. + if (Error E = irsymtab::build(Mods, Symtab, StrtabBuilder, Alloc)) { + consumeError(std::move(E)); + return; + } + + writeBlob(bitc::SYMTAB_BLOCK_ID, bitc::SYMTAB_BLOB, + {Symtab.data(), Symtab.size()}); +} + +void BitcodeWriter::writeStrtab() { + assert(!WroteStrtab); + + std::vector<char> Strtab; + StrtabBuilder.finalizeInOrder(); + Strtab.resize(StrtabBuilder.getSize()); + StrtabBuilder.write((uint8_t *)Strtab.data()); + + writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB, + {Strtab.data(), Strtab.size()}); + + WroteStrtab = true; +} + +void BitcodeWriter::copyStrtab(StringRef Strtab) { + writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB, Strtab); + WroteStrtab = true; +} + +void BitcodeWriter::writeModule(const Module &M) { + assert(!WroteStrtab); + + // The Mods vector is used by irsymtab::build, which requires non-const + // Modules in case it needs to materialize metadata. But the bitcode writer + // requires that the module is materialized, so we can cast to non-const here, + // after checking that it is in fact materialized. + assert(M.isMaterialized()); + Mods.push_back(const_cast<Module *>(&M)); + + DXILBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream); + ModuleWriter.write(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Begin dxil::BitcodeWriterBase Implementation +//////////////////////////////////////////////////////////////////////////////// + +unsigned DXILBitcodeWriter::getEncodedCastOpcode(unsigned Opcode) { + switch (Opcode) { + default: + llvm_unreachable("Unknown cast instruction!"); + case Instruction::Trunc: + return bitc::CAST_TRUNC; + case Instruction::ZExt: + return bitc::CAST_ZEXT; + case Instruction::SExt: + return bitc::CAST_SEXT; + case Instruction::FPToUI: + return bitc::CAST_FPTOUI; + case Instruction::FPToSI: + return bitc::CAST_FPTOSI; + case Instruction::UIToFP: + return bitc::CAST_UITOFP; + case Instruction::SIToFP: + return bitc::CAST_SITOFP; + case Instruction::FPTrunc: + return bitc::CAST_FPTRUNC; + case Instruction::FPExt: + return bitc::CAST_FPEXT; + case Instruction::PtrToInt: + return bitc::CAST_PTRTOINT; + case Instruction::IntToPtr: + return bitc::CAST_INTTOPTR; + case Instruction::BitCast: + return bitc::CAST_BITCAST; + case Instruction::AddrSpaceCast: + return bitc::CAST_ADDRSPACECAST; + } +} + +unsigned DXILBitcodeWriter::getEncodedUnaryOpcode(unsigned Opcode) { + switch (Opcode) { + default: + llvm_unreachable("Unknown binary instruction!"); + case Instruction::FNeg: + return bitc::UNOP_FNEG; + } +} + +unsigned DXILBitcodeWriter::getEncodedBinaryOpcode(unsigned Opcode) { + switch (Opcode) { + default: + llvm_unreachable("Unknown binary instruction!"); + case Instruction::Add: + case Instruction::FAdd: + return bitc::BINOP_ADD; + case Instruction::Sub: + case Instruction::FSub: + return bitc::BINOP_SUB; + case Instruction::Mul: + case Instruction::FMul: + return bitc::BINOP_MUL; + case Instruction::UDiv: + return bitc::BINOP_UDIV; + case Instruction::FDiv: + case Instruction::SDiv: + return bitc::BINOP_SDIV; + case Instruction::URem: + return bitc::BINOP_UREM; + case Instruction::FRem: + case Instruction::SRem: + return bitc::BINOP_SREM; + case Instruction::Shl: + return bitc::BINOP_SHL; + case Instruction::LShr: + return bitc::BINOP_LSHR; + case Instruction::AShr: + return bitc::BINOP_ASHR; + case Instruction::And: + return bitc::BINOP_AND; + case Instruction::Or: + return bitc::BINOP_OR; + case Instruction::Xor: + return bitc::BINOP_XOR; + } +} + +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: + llvm_unreachable("Unknown RMW operation!"); + case AtomicRMWInst::Xchg: + return bitc::RMW_XCHG; + case AtomicRMWInst::Add: + return bitc::RMW_ADD; + case AtomicRMWInst::Sub: + return bitc::RMW_SUB; + case AtomicRMWInst::And: + return bitc::RMW_AND; + case AtomicRMWInst::Nand: + return bitc::RMW_NAND; + case AtomicRMWInst::Or: + return bitc::RMW_OR; + case AtomicRMWInst::Xor: + return bitc::RMW_XOR; + case AtomicRMWInst::Max: + return bitc::RMW_MAX; + case AtomicRMWInst::Min: + return bitc::RMW_MIN; + case AtomicRMWInst::UMax: + return bitc::RMW_UMAX; + case AtomicRMWInst::UMin: + return bitc::RMW_UMIN; + case AtomicRMWInst::FAdd: + return bitc::RMW_FADD; + case AtomicRMWInst::FSub: + return bitc::RMW_FSUB; + } +} + +unsigned DXILBitcodeWriter::getEncodedOrdering(AtomicOrdering Ordering) { + switch (Ordering) { + case AtomicOrdering::NotAtomic: + return bitc::ORDERING_NOTATOMIC; + case AtomicOrdering::Unordered: + return bitc::ORDERING_UNORDERED; + case AtomicOrdering::Monotonic: + return bitc::ORDERING_MONOTONIC; + case AtomicOrdering::Acquire: + return bitc::ORDERING_ACQUIRE; + case AtomicOrdering::Release: + return bitc::ORDERING_RELEASE; + case AtomicOrdering::AcquireRelease: + return bitc::ORDERING_ACQREL; + case AtomicOrdering::SequentiallyConsistent: + return bitc::ORDERING_SEQCST; + } + llvm_unreachable("Invalid ordering"); +} + +void DXILBitcodeWriter::writeStringRecord(BitstreamWriter &Stream, + unsigned Code, StringRef Str, + unsigned AbbrevToUse) { + SmallVector<unsigned, 64> Vals; + + // Code: [strchar x N] + for (char C : Str) { + if (AbbrevToUse && !BitCodeAbbrevOp::isChar6(C)) + AbbrevToUse = 0; + Vals.push_back(C); + } + + // Emit the finished record. + Stream.EmitRecord(Code, Vals, AbbrevToUse); +} + +uint64_t DXILBitcodeWriter::getAttrKindEncoding(Attribute::AttrKind Kind) { + switch (Kind) { + case Attribute::Alignment: + return bitc::ATTR_KIND_ALIGNMENT; + case Attribute::AlwaysInline: + return bitc::ATTR_KIND_ALWAYS_INLINE; + case Attribute::ArgMemOnly: + return bitc::ATTR_KIND_ARGMEMONLY; + case Attribute::Builtin: + return bitc::ATTR_KIND_BUILTIN; + case Attribute::ByVal: + return bitc::ATTR_KIND_BY_VAL; + case Attribute::Convergent: + return bitc::ATTR_KIND_CONVERGENT; + case Attribute::InAlloca: + return bitc::ATTR_KIND_IN_ALLOCA; + case Attribute::Cold: + return bitc::ATTR_KIND_COLD; + case Attribute::InlineHint: + return bitc::ATTR_KIND_INLINE_HINT; + case Attribute::InReg: + return bitc::ATTR_KIND_IN_REG; + case Attribute::JumpTable: + return bitc::ATTR_KIND_JUMP_TABLE; + case Attribute::MinSize: + return bitc::ATTR_KIND_MIN_SIZE; + case Attribute::Naked: + return bitc::ATTR_KIND_NAKED; + case Attribute::Nest: + return bitc::ATTR_KIND_NEST; + case Attribute::NoAlias: + return bitc::ATTR_KIND_NO_ALIAS; + case Attribute::NoBuiltin: + return bitc::ATTR_KIND_NO_BUILTIN; + case Attribute::NoCapture: + return bitc::ATTR_KIND_NO_CAPTURE; + case Attribute::NoDuplicate: + return bitc::ATTR_KIND_NO_DUPLICATE; + case Attribute::NoImplicitFloat: + return bitc::ATTR_KIND_NO_IMPLICIT_FLOAT; + case Attribute::NoInline: + return bitc::ATTR_KIND_NO_INLINE; + case Attribute::NonLazyBind: + return bitc::ATTR_KIND_NON_LAZY_BIND; + case Attribute::NonNull: + return bitc::ATTR_KIND_NON_NULL; + case Attribute::Dereferenceable: + return bitc::ATTR_KIND_DEREFERENCEABLE; + case Attribute::DereferenceableOrNull: + return bitc::ATTR_KIND_DEREFERENCEABLE_OR_NULL; + case Attribute::NoRedZone: + return bitc::ATTR_KIND_NO_RED_ZONE; + case Attribute::NoReturn: + return bitc::ATTR_KIND_NO_RETURN; + case Attribute::NoUnwind: + return bitc::ATTR_KIND_NO_UNWIND; + case Attribute::OptimizeForSize: + return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE; + case Attribute::OptimizeNone: + return bitc::ATTR_KIND_OPTIMIZE_NONE; + case Attribute::ReadNone: + return bitc::ATTR_KIND_READ_NONE; + case Attribute::ReadOnly: + return bitc::ATTR_KIND_READ_ONLY; + case Attribute::Returned: + return bitc::ATTR_KIND_RETURNED; + case Attribute::ReturnsTwice: + return bitc::ATTR_KIND_RETURNS_TWICE; + case Attribute::SExt: + return bitc::ATTR_KIND_S_EXT; + case Attribute::StackAlignment: + return bitc::ATTR_KIND_STACK_ALIGNMENT; + case Attribute::StackProtect: + return bitc::ATTR_KIND_STACK_PROTECT; + case Attribute::StackProtectReq: + return bitc::ATTR_KIND_STACK_PROTECT_REQ; + case Attribute::StackProtectStrong: + return bitc::ATTR_KIND_STACK_PROTECT_STRONG; + case Attribute::SafeStack: + return bitc::ATTR_KIND_SAFESTACK; + case Attribute::StructRet: + return bitc::ATTR_KIND_STRUCT_RET; + case Attribute::SanitizeAddress: + return bitc::ATTR_KIND_SANITIZE_ADDRESS; + case Attribute::SanitizeThread: + return bitc::ATTR_KIND_SANITIZE_THREAD; + case Attribute::SanitizeMemory: + return bitc::ATTR_KIND_SANITIZE_MEMORY; + case Attribute::UWTable: + return bitc::ATTR_KIND_UW_TABLE; + case Attribute::ZExt: + return bitc::ATTR_KIND_Z_EXT; + case Attribute::EndAttrKinds: + llvm_unreachable("Can not encode end-attribute kinds marker."); + case Attribute::None: + llvm_unreachable("Can not encode none-attribute."); + case Attribute::EmptyKey: + case Attribute::TombstoneKey: + llvm_unreachable("Trying to encode EmptyKey/TombstoneKey"); + default: + llvm_unreachable("Trying to encode attribute not supported by DXIL. These " + "should be stripped in DXILPrepare"); + } + + llvm_unreachable("Trying to encode unknown attribute"); +} + +void DXILBitcodeWriter::emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, + uint64_t V) { + if ((int64_t)V >= 0) + Vals.push_back(V << 1); + else + Vals.push_back((-V << 1) | 1); +} + +void DXILBitcodeWriter::emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, + const APInt &A) { + // We have an arbitrary precision integer value to write whose + // bit width is > 64. However, in canonical unsigned integer + // format it is likely that the high bits are going to be zero. + // So, we only write the number of active words. + unsigned NumWords = A.getActiveWords(); + const uint64_t *RawData = A.getRawData(); + for (unsigned i = 0; i < NumWords; i++) + emitSignedInt64(Vals, RawData[i]); +} + +uint64_t DXILBitcodeWriter::getOptimizationFlags(const Value *V) { + uint64_t Flags = 0; + + if (const auto *OBO = dyn_cast<OverflowingBinaryOperator>(V)) { + if (OBO->hasNoSignedWrap()) + Flags |= 1 << bitc::OBO_NO_SIGNED_WRAP; + if (OBO->hasNoUnsignedWrap()) + Flags |= 1 << bitc::OBO_NO_UNSIGNED_WRAP; + } else if (const auto *PEO = dyn_cast<PossiblyExactOperator>(V)) { + if (PEO->isExact()) + Flags |= 1 << bitc::PEO_EXACT; + } else if (const auto *FPMO = dyn_cast<FPMathOperator>(V)) { + if (FPMO->hasAllowReassoc()) + Flags |= bitc::AllowReassoc; + if (FPMO->hasNoNaNs()) + Flags |= bitc::NoNaNs; + if (FPMO->hasNoInfs()) + Flags |= bitc::NoInfs; + if (FPMO->hasNoSignedZeros()) + Flags |= bitc::NoSignedZeros; + if (FPMO->hasAllowReciprocal()) + Flags |= bitc::AllowReciprocal; + if (FPMO->hasAllowContract()) + Flags |= bitc::AllowContract; + if (FPMO->hasApproxFunc()) + Flags |= bitc::ApproxFunc; + } + + return Flags; +} + +unsigned +DXILBitcodeWriter::getEncodedLinkage(const GlobalValue::LinkageTypes Linkage) { + switch (Linkage) { + case GlobalValue::ExternalLinkage: + return 0; + case GlobalValue::WeakAnyLinkage: + return 16; + case GlobalValue::AppendingLinkage: + return 2; + case GlobalValue::InternalLinkage: + return 3; + case GlobalValue::LinkOnceAnyLinkage: + return 18; + case GlobalValue::ExternalWeakLinkage: + return 7; + case GlobalValue::CommonLinkage: + return 8; + case GlobalValue::PrivateLinkage: + return 9; + case GlobalValue::WeakODRLinkage: + return 17; + case GlobalValue::LinkOnceODRLinkage: + return 19; + case GlobalValue::AvailableExternallyLinkage: + return 12; + } + llvm_unreachable("Invalid linkage"); +} + +unsigned DXILBitcodeWriter::getEncodedLinkage(const GlobalValue &GV) { + return getEncodedLinkage(GV.getLinkage()); +} + +unsigned DXILBitcodeWriter::getEncodedVisibility(const GlobalValue &GV) { + switch (GV.getVisibility()) { + case GlobalValue::DefaultVisibility: + return 0; + case GlobalValue::HiddenVisibility: + return 1; + case GlobalValue::ProtectedVisibility: + return 2; + } + llvm_unreachable("Invalid visibility"); +} + +unsigned DXILBitcodeWriter::getEncodedDLLStorageClass(const GlobalValue &GV) { + switch (GV.getDLLStorageClass()) { + case GlobalValue::DefaultStorageClass: + return 0; + case GlobalValue::DLLImportStorageClass: + return 1; + case GlobalValue::DLLExportStorageClass: + return 2; + } + llvm_unreachable("Invalid DLL storage class"); +} + +unsigned DXILBitcodeWriter::getEncodedThreadLocalMode(const GlobalValue &GV) { + switch (GV.getThreadLocalMode()) { + case GlobalVariable::NotThreadLocal: + return 0; + case GlobalVariable::GeneralDynamicTLSModel: + return 1; + case GlobalVariable::LocalDynamicTLSModel: + return 2; + case GlobalVariable::InitialExecTLSModel: + return 3; + case GlobalVariable::LocalExecTLSModel: + return 4; + } + llvm_unreachable("Invalid TLS model"); +} + +unsigned DXILBitcodeWriter::getEncodedComdatSelectionKind(const Comdat &C) { + switch (C.getSelectionKind()) { + case Comdat::Any: + return bitc::COMDAT_SELECTION_KIND_ANY; + case Comdat::ExactMatch: + return bitc::COMDAT_SELECTION_KIND_EXACT_MATCH; + case Comdat::Largest: + return bitc::COMDAT_SELECTION_KIND_LARGEST; + case Comdat::NoDeduplicate: + return bitc::COMDAT_SELECTION_KIND_NO_DUPLICATES; + case Comdat::SameSize: + return bitc::COMDAT_SELECTION_KIND_SAME_SIZE; + } + llvm_unreachable("Invalid selection kind"); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Begin DXILBitcodeWriter Implementation +//////////////////////////////////////////////////////////////////////////////// + +void DXILBitcodeWriter::writeAttributeGroupTable() { + const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps = + VE.getAttributeGroups(); + if (AttrGrps.empty()) + return; + + Stream.EnterSubblock(bitc::PARAMATTR_GROUP_BLOCK_ID, 3); + + SmallVector<uint64_t, 64> Record; + for (ValueEnumerator::IndexAndAttrSet Pair : AttrGrps) { + unsigned AttrListIndex = Pair.first; + AttributeSet AS = Pair.second; + Record.push_back(VE.getAttributeGroupID(Pair)); + Record.push_back(AttrListIndex); + + for (Attribute Attr : AS) { + if (Attr.isEnumAttribute()) { + uint64_t Val = getAttrKindEncoding(Attr.getKindAsEnum()); + assert(Val <= bitc::ATTR_KIND_ARGMEMONLY && + "DXIL does not support attributes above ATTR_KIND_ARGMEMONLY"); + Record.push_back(0); + Record.push_back(Val); + } else if (Attr.isIntAttribute()) { + uint64_t Val = getAttrKindEncoding(Attr.getKindAsEnum()); + assert(Val <= bitc::ATTR_KIND_ARGMEMONLY && + "DXIL does not support attributes above ATTR_KIND_ARGMEMONLY"); + Record.push_back(1); + Record.push_back(Val); + Record.push_back(Attr.getValueAsInt()); + } else { + StringRef Kind = Attr.getKindAsString(); + StringRef Val = Attr.getValueAsString(); + + Record.push_back(Val.empty() ? 3 : 4); + Record.append(Kind.begin(), Kind.end()); + Record.push_back(0); + if (!Val.empty()) { + Record.append(Val.begin(), Val.end()); + Record.push_back(0); + } + } + } + + Stream.EmitRecord(bitc::PARAMATTR_GRP_CODE_ENTRY, Record); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeAttributeTable() { + const std::vector<AttributeList> &Attrs = VE.getAttributeLists(); + if (Attrs.empty()) + return; + + Stream.EnterSubblock(bitc::PARAMATTR_BLOCK_ID, 3); + + SmallVector<uint64_t, 64> Record; + for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { + AttributeList AL = Attrs[i]; + for (unsigned i : AL.indexes()) { + AttributeSet AS = AL.getAttributes(i); + if (AS.hasAttributes()) + Record.push_back(VE.getAttributeGroupID({i, AS})); + } + + Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record); + Record.clear(); + } + + Stream.ExitBlock(); +} + +/// WriteTypeTable - Write out the type table for a module. +void DXILBitcodeWriter::writeTypeTable() { + const ValueEnumerator::TypeList &TypeList = VE.getTypes(); + + Stream.EnterSubblock(bitc::TYPE_BLOCK_ID_NEW, 4 /*count from # abbrevs */); + SmallVector<uint64_t, 64> TypeVals; + + uint64_t NumBits = VE.computeBitsRequiredForTypeIndicies(); + + // Abbrev for TYPE_CODE_POINTER. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_POINTER)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0 + unsigned PtrAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_FUNCTION. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isvararg + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned FunctionAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_ANON. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_ANON)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ispacked + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned StructAnonAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_NAME. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_NAME)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + unsigned StructNameAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_NAMED. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_NAMED)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ispacked + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned StructNamedAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_ARRAY. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_ARRAY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // size + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned ArrayAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Emit an entry count so the reader can reserve space. + TypeVals.push_back(TypeList.size()); + Stream.EmitRecord(bitc::TYPE_CODE_NUMENTRY, TypeVals); + TypeVals.clear(); + + // Loop over all of the types, emitting each in turn. + for (Type *T : TypeList) { + int AbbrevToUse = 0; + unsigned Code = 0; + + switch (T->getTypeID()) { + case Type::BFloatTyID: + case Type::X86_AMXTyID: + case Type::TokenTyID: + llvm_unreachable("These should never be used!!!"); + break; + case Type::VoidTyID: + Code = bitc::TYPE_CODE_VOID; + break; + case Type::HalfTyID: + Code = bitc::TYPE_CODE_HALF; + break; + case Type::FloatTyID: + Code = bitc::TYPE_CODE_FLOAT; + break; + case Type::DoubleTyID: + Code = bitc::TYPE_CODE_DOUBLE; + break; + case Type::X86_FP80TyID: + Code = bitc::TYPE_CODE_X86_FP80; + break; + case Type::FP128TyID: + Code = bitc::TYPE_CODE_FP128; + break; + case Type::PPC_FP128TyID: + Code = bitc::TYPE_CODE_PPC_FP128; + break; + case Type::LabelTyID: + Code = bitc::TYPE_CODE_LABEL; + break; + case Type::MetadataTyID: + Code = bitc::TYPE_CODE_METADATA; + break; + case Type::X86_MMXTyID: + Code = bitc::TYPE_CODE_X86_MMX; + break; + case Type::IntegerTyID: + // INTEGER: [width] + Code = bitc::TYPE_CODE_INTEGER; + TypeVals.push_back(cast<IntegerType>(T)->getBitWidth()); + break; + case Type::DXILPointerTyID: { + TypedPointerType *PTy = cast<TypedPointerType>(T); + // POINTER: [pointee type, address space] + Code = bitc::TYPE_CODE_POINTER; + 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<PointerType>(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<FunctionType>(T); + // FUNCTION: [isvararg, retty, paramty x N] + Code = bitc::TYPE_CODE_FUNCTION; + TypeVals.push_back(FT->isVarArg()); + TypeVals.push_back(getTypeID(FT->getReturnType())); + for (Type *PTy : FT->params()) + TypeVals.push_back(getTypeID(PTy)); + AbbrevToUse = FunctionAbbrev; + break; + } + case Type::StructTyID: { + StructType *ST = cast<StructType>(T); + // STRUCT: [ispacked, eltty x N] + TypeVals.push_back(ST->isPacked()); + // Output all of the element types. + for (Type *ElTy : ST->elements()) + TypeVals.push_back(getTypeID(ElTy)); + + if (ST->isLiteral()) { + Code = bitc::TYPE_CODE_STRUCT_ANON; + AbbrevToUse = StructAnonAbbrev; + } else { + if (ST->isOpaque()) { + Code = bitc::TYPE_CODE_OPAQUE; + } else { + Code = bitc::TYPE_CODE_STRUCT_NAMED; + AbbrevToUse = StructNamedAbbrev; + } + + // Emit the name if it is present. + if (!ST->getName().empty()) + writeStringRecord(Stream, bitc::TYPE_CODE_STRUCT_NAME, ST->getName(), + StructNameAbbrev); + } + break; + } + case Type::ArrayTyID: { + ArrayType *AT = cast<ArrayType>(T); + // ARRAY: [numelts, eltty] + Code = bitc::TYPE_CODE_ARRAY; + TypeVals.push_back(AT->getNumElements()); + TypeVals.push_back(getTypeID(AT->getElementType())); + AbbrevToUse = ArrayAbbrev; + break; + } + case Type::FixedVectorTyID: + case Type::ScalableVectorTyID: { + VectorType *VT = cast<VectorType>(T); + // VECTOR [numelts, eltty] + Code = bitc::TYPE_CODE_VECTOR; + TypeVals.push_back(VT->getElementCount().getKnownMinValue()); + TypeVals.push_back(getTypeID(VT->getElementType())); + break; + } + } + + // Emit the finished record. + Stream.EmitRecord(Code, TypeVals, AbbrevToUse); + TypeVals.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeComdats() { + SmallVector<uint16_t, 64> Vals; + for (const Comdat *C : VE.getComdats()) { + // COMDAT: [selection_kind, name] + Vals.push_back(getEncodedComdatSelectionKind(*C)); + size_t Size = C->getName().size(); + assert(isUInt<16>(Size)); + Vals.push_back(Size); + for (char Chr : C->getName()) + Vals.push_back((unsigned char)Chr); + Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0); + Vals.clear(); + } +} + +void DXILBitcodeWriter::writeValueSymbolTableForwardDecl() {} + +/// Emit top-level description of module, including target triple, inline asm, +/// descriptors for global variables, and function prototype info. +/// Returns the bit offset to backpatch with the location of the real VST. +void DXILBitcodeWriter::writeModuleInfo() { + // Emit various pieces of data attached to a module. + if (!M.getTargetTriple().empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_TRIPLE, M.getTargetTriple(), + 0 /*TODO*/); + const std::string &DL = M.getDataLayoutStr(); + if (!DL.empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/); + if (!M.getModuleInlineAsm().empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_ASM, M.getModuleInlineAsm(), + 0 /*TODO*/); + + // Emit information about sections and GC, computing how many there are. Also + // compute the maximum alignment value. + std::map<std::string, unsigned> SectionMap; + std::map<std::string, unsigned> GCMap; + MaybeAlign MaxAlignment; + unsigned MaxGlobalType = 0; + const auto UpdateMaxAlignment = [&MaxAlignment](const MaybeAlign A) { + if (A) + MaxAlignment = !MaxAlignment ? *A : std::max(*MaxAlignment, *A); + }; + for (const GlobalVariable &GV : M.globals()) { + UpdateMaxAlignment(GV.getAlign()); + MaxGlobalType = std::max(MaxGlobalType, getTypeID(GV.getValueType(), &GV)); + if (GV.hasSection()) { + // Give section names unique ID's. + unsigned &Entry = SectionMap[std::string(GV.getSection())]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, + GV.getSection(), 0 /*TODO*/); + Entry = SectionMap.size(); + } + } + } + for (const Function &F : M) { + UpdateMaxAlignment(F.getAlign()); + if (F.hasSection()) { + // Give section names unique ID's. + unsigned &Entry = SectionMap[std::string(F.getSection())]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, F.getSection(), + 0 /*TODO*/); + Entry = SectionMap.size(); + } + } + if (F.hasGC()) { + // Same for GC names. + unsigned &Entry = GCMap[F.getGC()]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_GCNAME, F.getGC(), + 0 /*TODO*/); + Entry = GCMap.size(); + } + } + } + + // 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. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(MaxGlobalType + 1))); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2 + //| explicitType << 1 + //| constant + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Initializer. + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5)); // Linkage. + if (!MaxAlignment) // Alignment. + Abbv->Add(BitCodeAbbrevOp(0)); + else { + unsigned MaxEncAlignment = getEncodedAlign(MaxAlignment); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(MaxEncAlignment + 1))); + } + if (SectionMap.empty()) // Section. + Abbv->Add(BitCodeAbbrevOp(0)); + else + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(SectionMap.size() + 1))); + // Don't bother emitting vis + thread local. + SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + // Emit the global variable information. + SmallVector<unsigned, 64> Vals; + for (const GlobalVariable &GV : M.globals()) { + unsigned AbbrevToUse = 0; + + // GLOBALVAR: [type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr, externally_initialized, dllstorageclass, + // comdat] + 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 + // unsigned int and bool + Vals.push_back( + GV.isDeclaration() ? 0 : (VE.getValueID(GV.getInitializer()) + 1)); + Vals.push_back(getEncodedLinkage(GV)); + Vals.push_back(getEncodedAlign(GV.getAlign())); + Vals.push_back(GV.hasSection() ? SectionMap[std::string(GV.getSection())] + : 0); + if (GV.isThreadLocal() || + GV.getVisibility() != GlobalValue::DefaultVisibility || + GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None || + GV.isExternallyInitialized() || + GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass || + GV.hasComdat()) { + Vals.push_back(getEncodedVisibility(GV)); + Vals.push_back(getEncodedThreadLocalMode(GV)); + Vals.push_back(GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + Vals.push_back(GV.isExternallyInitialized()); + Vals.push_back(getEncodedDLLStorageClass(GV)); + Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0); + } else { + AbbrevToUse = SimpleGVarAbbrev; + } + + Stream.EmitRecord(bitc::MODULE_CODE_GLOBALVAR, Vals, AbbrevToUse); + Vals.clear(); + } + + // Emit the function proto information. + for (const Function &F : M) { + // 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(F.getCallingConv()); + Vals.push_back(F.isDeclaration()); + Vals.push_back(getEncodedLinkage(F)); + Vals.push_back(VE.getAttributeListID(F.getAttributes())); + Vals.push_back(getEncodedAlign(F.getAlign())); + Vals.push_back(F.hasSection() ? SectionMap[std::string(F.getSection())] + : 0); + Vals.push_back(getEncodedVisibility(F)); + Vals.push_back(F.hasGC() ? GCMap[F.getGC()] : 0); + Vals.push_back(F.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + Vals.push_back( + F.hasPrologueData() ? (VE.getValueID(F.getPrologueData()) + 1) : 0); + Vals.push_back(getEncodedDLLStorageClass(F)); + Vals.push_back(F.hasComdat() ? VE.getComdatID(F.getComdat()) : 0); + Vals.push_back(F.hasPrefixData() ? (VE.getValueID(F.getPrefixData()) + 1) + : 0); + Vals.push_back( + F.hasPersonalityFn() ? (VE.getValueID(F.getPersonalityFn()) + 1) : 0); + + unsigned AbbrevToUse = 0; + Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); + Vals.clear(); + } + + // Emit the alias information. + for (const GlobalAlias &A : M.aliases()) { + // ALIAS: [alias type, aliasee val#, linkage, visibility] + Vals.push_back(getTypeID(A.getValueType(), &A)); + Vals.push_back(VE.getValueID(A.getAliasee())); + Vals.push_back(getEncodedLinkage(A)); + Vals.push_back(getEncodedVisibility(A)); + Vals.push_back(getEncodedDLLStorageClass(A)); + Vals.push_back(getEncodedThreadLocalMode(A)); + Vals.push_back(A.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + unsigned AbbrevToUse = 0; + Stream.EmitRecord(bitc::MODULE_CODE_ALIAS_OLD, Vals, AbbrevToUse); + Vals.clear(); + } +} + +void DXILBitcodeWriter::writeValueAsMetadata( + const ValueAsMetadata *MD, SmallVectorImpl<uint64_t> &Record) { + // Mimic an MDNode with a value as one operand. + Value *V = MD->getValue(); + Type *Ty = V->getType(); + if (Function *F = dyn_cast<Function>(V)) + Ty = TypedPointerType::get(F->getFunctionType(), F->getAddressSpace()); + else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) + Ty = TypedPointerType::get(GV->getValueType(), GV->getAddressSpace()); + Record.push_back(getTypeID(Ty)); + Record.push_back(VE.getValueID(V)); + Stream.EmitRecord(bitc::METADATA_VALUE, Record, 0); + Record.clear(); +} + +void DXILBitcodeWriter::writeMDTuple(const MDTuple *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + Metadata *MD = N->getOperand(i); + assert(!(MD && isa<LocalAsMetadata>(MD)) && + "Unexpected function-local metadata"); + Record.push_back(VE.getMetadataOrNullID(MD)); + } + Stream.EmitRecord(N->isDistinct() ? bitc::METADATA_DISTINCT_NODE + : bitc::METADATA_NODE, + Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILocation(const DILocation *N, + SmallVectorImpl<uint64_t> &Record, + unsigned &Abbrev) { + if (!Abbrev) + Abbrev = createDILocationAbbrev(); + Record.push_back(N->isDistinct()); + Record.push_back(N->getLine()); + Record.push_back(N->getColumn()); + Record.push_back(VE.getMetadataID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getInlinedAt())); + + Stream.EmitRecord(bitc::METADATA_LOCATION, Record, Abbrev); + Record.clear(); +} + +static uint64_t rotateSign(APInt Val) { + int64_t I = Val.getSExtValue(); + uint64_t U = I; + return I < 0 ? ~(U << 1) : U << 1; +} + +static uint64_t rotateSign(DISubrange::BoundType Val) { + return rotateSign(Val.get<ConstantInt *>()->getValue()); +} + +void DXILBitcodeWriter::writeDISubrange(const DISubrange *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back( + N->getCount().get<ConstantInt *>()->getValue().getSExtValue()); + Record.push_back(rotateSign(N->getLowerBound())); + + Stream.EmitRecord(bitc::METADATA_SUBRANGE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIEnumerator(const DIEnumerator *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(rotateSign(N->getValue())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + + Stream.EmitRecord(bitc::METADATA_ENUMERATOR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIBasicType(const DIBasicType *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getEncoding()); + + Stream.EmitRecord(bitc::METADATA_BASIC_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIDerivedType(const DIDerivedType *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getBaseType())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getOffsetInBits()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getExtraData())); + + Stream.EmitRecord(bitc::METADATA_DERIVED_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDICompositeType(const DICompositeType *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getBaseType())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getOffsetInBits()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getElements().get())); + Record.push_back(N->getRuntimeLang()); + Record.push_back(VE.getMetadataOrNullID(N->getVTableHolder())); + Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get())); + Record.push_back(VE.getMetadataOrNullID(N->getRawIdentifier())); + + Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDISubroutineType(const DISubroutineType *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getTypeArray().get())); + + Stream.EmitRecord(bitc::METADATA_SUBROUTINE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIFile(const DIFile *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawFilename())); + Record.push_back(VE.getMetadataOrNullID(N->getRawDirectory())); + + Stream.EmitRecord(bitc::METADATA_FILE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDICompileUnit(const DICompileUnit *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getSourceLanguage()); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getRawProducer())); + Record.push_back(N->isOptimized()); + Record.push_back(VE.getMetadataOrNullID(N->getRawFlags())); + Record.push_back(N->getRuntimeVersion()); + Record.push_back(VE.getMetadataOrNullID(N->getRawSplitDebugFilename())); + Record.push_back(N->getEmissionKind()); + Record.push_back(VE.getMetadataOrNullID(N->getEnumTypes().get())); + Record.push_back(VE.getMetadataOrNullID(N->getRetainedTypes().get())); + Record.push_back(/* subprograms */ 0); + Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables().get())); + Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities().get())); + Record.push_back(N->getDWOId()); + + Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isLocalToUnit()); + Record.push_back(N->isDefinition()); + Record.push_back(N->getScopeLine()); + Record.push_back(VE.getMetadataOrNullID(N->getContainingType())); + Record.push_back(N->getVirtuality()); + Record.push_back(N->getVirtualIndex()); + Record.push_back(N->getFlags()); + Record.push_back(N->isOptimized()); + Record.push_back(VE.getMetadataOrNullID(N->getRawUnit())); + Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get())); + Record.push_back(VE.getMetadataOrNullID(N->getDeclaration())); + Record.push_back(VE.getMetadataOrNullID(N->getRetainedNodes().get())); + + Stream.EmitRecord(bitc::METADATA_SUBPROGRAM, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILexicalBlock(const DILexicalBlock *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(N->getColumn()); + + Stream.EmitRecord(bitc::METADATA_LEXICAL_BLOCK, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILexicalBlockFile( + const DILexicalBlockFile *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getDiscriminator()); + + Stream.EmitRecord(bitc::METADATA_LEXICAL_BLOCK_FILE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDINamespace(const DINamespace *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(/* line number */ 0); + + Stream.EmitRecord(bitc::METADATA_NAMESPACE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIModule(const DIModule *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + for (auto &I : N->operands()) + Record.push_back(VE.getMetadataOrNullID(I)); + + Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDITemplateTypeParameter( + const DITemplateTypeParameter *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + + Stream.EmitRecord(bitc::METADATA_TEMPLATE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDITemplateValueParameter( + const DITemplateValueParameter *N, SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(VE.getMetadataOrNullID(N->getValue())); + + Stream.EmitRecord(bitc::METADATA_TEMPLATE_VALUE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIGlobalVariable(const DIGlobalVariable *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isLocalToUnit()); + Record.push_back(N->isDefinition()); + Record.push_back(/* N->getRawVariable() */ 0); + Record.push_back(VE.getMetadataOrNullID(N->getStaticDataMemberDeclaration())); + + Stream.EmitRecord(bitc::METADATA_GLOBAL_VAR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILocalVariable(const DILocalVariable *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->getArg()); + Record.push_back(N->getFlags()); + + Stream.EmitRecord(bitc::METADATA_LOCAL_VAR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIExpression(const DIExpression *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.reserve(N->getElements().size() + 1); + + Record.push_back(N->isDistinct()); + Record.append(N->elements_begin(), N->elements_end()); + + Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIObjCProperty(const DIObjCProperty *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL does not support objc!!!"); +} + +void DXILBitcodeWriter::writeDIImportedEntity(const DIImportedEntity *N, + SmallVectorImpl<uint64_t> &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getEntity())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + + Stream.EmitRecord(bitc::METADATA_IMPORTED_ENTITY, Record, Abbrev); + Record.clear(); +} + +unsigned DXILBitcodeWriter::createDILocationAbbrev() { + // Abbrev for METADATA_LOCATION. + // + // Assume the column is usually under 128, and always output the inlined-at + // location (it's never more expensive than building an array size 1). + std::shared_ptr<BitCodeAbbrev> Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_LOCATION)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +unsigned DXILBitcodeWriter::createGenericDINodeAbbrev() { + // Abbrev for METADATA_GENERIC_DEBUG. + // + // Assume the column is usually under 128, and always output the inlined-at + // location (it's never more expensive than building an array size 1). + std::shared_ptr<BitCodeAbbrev> Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_GENERIC_DEBUG)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +void DXILBitcodeWriter::writeMetadataRecords(ArrayRef<const Metadata *> MDs, + SmallVectorImpl<uint64_t> &Record, + std::vector<unsigned> *MDAbbrevs, + std::vector<uint64_t> *IndexPos) { + if (MDs.empty()) + return; + + // Initialize MDNode abbreviations. +#define HANDLE_MDNODE_LEAF(CLASS) unsigned CLASS##Abbrev = 0; +#include "llvm/IR/Metadata.def" + + for (const Metadata *MD : MDs) { + if (IndexPos) + IndexPos->push_back(Stream.GetCurrentBitNo()); + if (const MDNode *N = dyn_cast<MDNode>(MD)) { + assert(N->isResolved() && "Expected forward references to be resolved"); + + switch (N->getMetadataID()) { + default: + llvm_unreachable("Invalid MDNode subclass"); +#define HANDLE_MDNODE_LEAF(CLASS) \ + case Metadata::CLASS##Kind: \ + if (MDAbbrevs) \ + write##CLASS(cast<CLASS>(N), Record, \ + (*MDAbbrevs)[MetadataAbbrev::CLASS##AbbrevID]); \ + else \ + write##CLASS(cast<CLASS>(N), Record, CLASS##Abbrev); \ + continue; +#include "llvm/IR/Metadata.def" + } + } + writeValueAsMetadata(cast<ValueAsMetadata>(MD), Record); + } +} + +unsigned DXILBitcodeWriter::createMetadataStringsAbbrev() { + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_STRING_OLD)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +void DXILBitcodeWriter::writeMetadataStrings( + ArrayRef<const Metadata *> Strings, SmallVectorImpl<uint64_t> &Record) { + for (const Metadata *MD : Strings) { + const MDString *MDS = cast<MDString>(MD); + // Code: [strchar x N] + Record.append(MDS->bytes_begin(), MDS->bytes_end()); + + // Emit the finished record. + Stream.EmitRecord(bitc::METADATA_STRING_OLD, Record, + createMetadataStringsAbbrev()); + Record.clear(); + } +} + +void DXILBitcodeWriter::writeModuleMetadata() { + if (!VE.hasMDs() && M.named_metadata_empty()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 5); + + // Emit all abbrevs upfront, so that the reader can jump in the middle of the + // block and load any metadata. + std::vector<unsigned> MDAbbrevs; + + MDAbbrevs.resize(MetadataAbbrev::LastPlusOne); + MDAbbrevs[MetadataAbbrev::DILocationAbbrevID] = createDILocationAbbrev(); + MDAbbrevs[MetadataAbbrev::GenericDINodeAbbrevID] = + createGenericDINodeAbbrev(); + + unsigned NameAbbrev = 0; + if (!M.named_metadata_empty()) { + // Abbrev for METADATA_NAME. + std::shared_ptr<BitCodeAbbrev> Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_NAME)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + NameAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + SmallVector<uint64_t, 64> Record; + writeMetadataStrings(VE.getMDStrings(), Record); + + std::vector<uint64_t> IndexPos; + IndexPos.reserve(VE.getNonMDStrings().size()); + writeMetadataRecords(VE.getNonMDStrings(), Record, &MDAbbrevs, &IndexPos); + + // Write named metadata. + for (const NamedMDNode &NMD : M.named_metadata()) { + // Write name. + StringRef Str = NMD.getName(); + Record.append(Str.bytes_begin(), Str.bytes_end()); + Stream.EmitRecord(bitc::METADATA_NAME, Record, NameAbbrev); + Record.clear(); + + // Write named metadata operands. + for (const MDNode *N : NMD.operands()) + Record.push_back(VE.getMetadataID(N)); + Stream.EmitRecord(bitc::METADATA_NAMED_NODE, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeFunctionMetadata(const Function &F) { + if (!VE.hasMDs()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 4); + SmallVector<uint64_t, 64> Record; + writeMetadataStrings(VE.getMDStrings(), Record); + writeMetadataRecords(VE.getNonMDStrings(), Record); + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeFunctionMetadataAttachment(const Function &F) { + Stream.EnterSubblock(bitc::METADATA_ATTACHMENT_ID, 3); + + SmallVector<uint64_t, 64> Record; + + // Write metadata attachments + // METADATA_ATTACHMENT - [m x [value, [n x [id, mdnode]]] + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + F.getAllMetadata(MDs); + if (!MDs.empty()) { + for (const auto &I : MDs) { + Record.push_back(I.first); + Record.push_back(VE.getMetadataID(I.second)); + } + Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Record.clear(); + } + + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) { + MDs.clear(); + I.getAllMetadataOtherThanDebugLoc(MDs); + + // If no metadata, ignore instruction. + if (MDs.empty()) + continue; + + Record.push_back(VE.getInstructionID(&I)); + + for (unsigned i = 0, e = MDs.size(); i != e; ++i) { + Record.push_back(MDs[i].first); + Record.push_back(VE.getMetadataID(MDs[i].second)); + } + Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleMetadataKinds() { + SmallVector<uint64_t, 64> Record; + + // Write metadata kinds + // METADATA_KIND - [n x [id, name]] + SmallVector<StringRef, 8> Names; + M.getMDKindNames(Names); + + if (Names.empty()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); + + for (unsigned MDKindID = 0, e = Names.size(); MDKindID != e; ++MDKindID) { + Record.push_back(MDKindID); + StringRef KName = Names[MDKindID]; + Record.append(KName.begin(), KName.end()); + + Stream.EmitRecord(bitc::METADATA_KIND, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, + bool isGlobal) { + if (FirstVal == LastVal) + return; + + Stream.EnterSubblock(bitc::CONSTANTS_BLOCK_ID, 4); + + unsigned AggregateAbbrev = 0; + unsigned String8Abbrev = 0; + unsigned CString7Abbrev = 0; + unsigned CString6Abbrev = 0; + // If this is a constant pool for the module, emit module-specific abbrevs. + if (isGlobal) { + // Abbrev for CST_CODE_AGGREGATE. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_AGGREGATE)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add( + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, Log2_32_Ceil(LastVal + 1))); + AggregateAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for CST_CODE_STRING. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_STRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + String8Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for CST_CODE_CSTRING. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CSTRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); + CString7Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for CST_CODE_CSTRING. + Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CSTRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + CString6Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + SmallVector<uint64_t, 64> Record; + + const ValueEnumerator::ValueList &Vals = VE.getValues(); + Type *LastTy = nullptr; + for (unsigned i = FirstVal; i != LastVal; ++i) { + const Value *V = Vals[i].first; + // If we need to switch types, do so now. + if (V->getType() != LastTy) { + LastTy = V->getType(); + Record.push_back(getTypeID(LastTy)); + Stream.EmitRecord(bitc::CST_CODE_SETTYPE, Record, + CONSTANTS_SETTYPE_ABBREV); + Record.clear(); + } + + if (const InlineAsm *IA = dyn_cast<InlineAsm>(V)) { + Record.push_back(unsigned(IA->hasSideEffects()) | + unsigned(IA->isAlignStack()) << 1 | + unsigned(IA->getDialect() & 1) << 2); + + // Add the asm string. + const std::string &AsmStr = IA->getAsmString(); + Record.push_back(AsmStr.size()); + Record.append(AsmStr.begin(), AsmStr.end()); + + // Add the constraint string. + const std::string &ConstraintStr = IA->getConstraintString(); + Record.push_back(ConstraintStr.size()); + Record.append(ConstraintStr.begin(), ConstraintStr.end()); + Stream.EmitRecord(bitc::CST_CODE_INLINEASM, Record); + Record.clear(); + continue; + } + const Constant *C = cast<Constant>(V); + unsigned Code = -1U; + unsigned AbbrevToUse = 0; + if (C->isNullValue()) { + Code = bitc::CST_CODE_NULL; + } else if (isa<UndefValue>(C)) { + Code = bitc::CST_CODE_UNDEF; + } else if (const ConstantInt *IV = dyn_cast<ConstantInt>(C)) { + if (IV->getBitWidth() <= 64) { + uint64_t V = IV->getSExtValue(); + emitSignedInt64(Record, V); + Code = bitc::CST_CODE_INTEGER; + AbbrevToUse = CONSTANTS_INTEGER_ABBREV; + } else { // Wide integers, > 64 bits in size. + // We have an arbitrary precision integer value to write whose + // bit width is > 64. However, in canonical unsigned integer + // format it is likely that the high bits are going to be zero. + // So, we only write the number of active words. + unsigned NWords = IV->getValue().getActiveWords(); + const uint64_t *RawWords = IV->getValue().getRawData(); + for (unsigned i = 0; i != NWords; ++i) { + emitSignedInt64(Record, RawWords[i]); + } + Code = bitc::CST_CODE_WIDE_INTEGER; + } + } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) { + Code = bitc::CST_CODE_FLOAT; + Type *Ty = CFP->getType(); + if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy()) { + Record.push_back(CFP->getValueAPF().bitcastToAPInt().getZExtValue()); + } else if (Ty->isX86_FP80Ty()) { + // api needed to prevent premature destruction + // bits are not in the same order as a normal i80 APInt, compensate. + APInt api = CFP->getValueAPF().bitcastToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back((p[1] << 48) | (p[0] >> 16)); + Record.push_back(p[0] & 0xffffLL); + } else if (Ty->isFP128Ty() || Ty->isPPC_FP128Ty()) { + APInt api = CFP->getValueAPF().bitcastToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back(p[0]); + Record.push_back(p[1]); + } else { + assert(0 && "Unknown FP type!"); + } + } else if (isa<ConstantDataSequential>(C) && + cast<ConstantDataSequential>(C)->isString()) { + const ConstantDataSequential *Str = cast<ConstantDataSequential>(C); + // Emit constant strings specially. + unsigned NumElts = Str->getNumElements(); + // If this is a null-terminated string, use the denser CSTRING encoding. + if (Str->isCString()) { + Code = bitc::CST_CODE_CSTRING; + --NumElts; // Don't encode the null, which isn't allowed by char6. + } else { + Code = bitc::CST_CODE_STRING; + AbbrevToUse = String8Abbrev; + } + bool isCStr7 = Code == bitc::CST_CODE_CSTRING; + bool isCStrChar6 = Code == bitc::CST_CODE_CSTRING; + for (unsigned i = 0; i != NumElts; ++i) { + unsigned char V = Str->getElementAsInteger(i); + Record.push_back(V); + isCStr7 &= (V & 128) == 0; + if (isCStrChar6) + isCStrChar6 = BitCodeAbbrevOp::isChar6(V); + } + + if (isCStrChar6) + AbbrevToUse = CString6Abbrev; + else if (isCStr7) + AbbrevToUse = CString7Abbrev; + } else if (const ConstantDataSequential *CDS = + dyn_cast<ConstantDataSequential>(C)) { + Code = bitc::CST_CODE_DATA; + Type *EltTy = CDS->getType()->getArrayElementType(); + if (isa<IntegerType>(EltTy)) { + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) + Record.push_back(CDS->getElementAsInteger(i)); + } else if (EltTy->isFloatTy()) { + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { + union { + float F; + uint32_t I; + }; + F = CDS->getElementAsFloat(i); + Record.push_back(I); + } + } else { + assert(EltTy->isDoubleTy() && "Unknown ConstantData element type"); + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { + union { + double F; + uint64_t I; + }; + F = CDS->getElementAsDouble(i); + Record.push_back(I); + } + } + } else if (isa<ConstantArray>(C) || isa<ConstantStruct>(C) || + isa<ConstantVector>(C)) { + Code = bitc::CST_CODE_AGGREGATE; + for (const Value *Op : C->operands()) + Record.push_back(VE.getValueID(Op)); + AbbrevToUse = AggregateAbbrev; + } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { + switch (CE->getOpcode()) { + default: + 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(VE.getValueID(C->getOperand(0))); + AbbrevToUse = CONSTANTS_CE_CAST_Abbrev; + } else { + assert(CE->getNumOperands() == 2 && "Unknown constant expr!"); + Code = bitc::CST_CODE_CE_BINOP; + Record.push_back(getEncodedBinaryOpcode(CE->getOpcode())); + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + uint64_t Flags = getOptimizationFlags(CE); + if (Flags != 0) + Record.push_back(Flags); + } + break; + case Instruction::GetElementPtr: { + Code = bitc::CST_CODE_CE_GEP; + const auto *GO = cast<GEPOperator>(C); + if (GO->isInBounds()) + 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(VE.getValueID(C->getOperand(i))); + } + break; + } + case Instruction::Select: + Code = bitc::CST_CODE_CE_SELECT; + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + Record.push_back(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ExtractElement: + Code = bitc::CST_CODE_CE_EXTRACTELT; + Record.push_back(getTypeID(C->getOperand(0)->getType())); + Record.push_back(VE.getValueID(C->getOperand(0))); + 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(getTypeID(C->getOperand(2)->getType())); + Record.push_back(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ShuffleVector: + // If the return type and argument types are the same, this is a + // standard shufflevector instruction. If the types are different, + // then the shuffle is widening or truncating the input vectors, and + // the argument type must also be encoded. + if (C->getType() == C->getOperand(0)->getType()) { + Code = bitc::CST_CODE_CE_SHUFFLEVEC; + } else { + Code = bitc::CST_CODE_CE_SHUFVEC_EX; + 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(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ICmp: + case Instruction::FCmp: + Code = bitc::CST_CODE_CE_CMP; + 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()); + break; + } + } else if (const BlockAddress *BA = dyn_cast<BlockAddress>(C)) { + Code = bitc::CST_CODE_BLOCKADDRESS; + Record.push_back(getTypeID(BA->getFunction()->getType())); + Record.push_back(VE.getValueID(BA->getFunction())); + Record.push_back(VE.getGlobalBasicBlockID(BA->getBasicBlock())); + } else { +#ifndef NDEBUG + C->dump(); +#endif + llvm_unreachable("Unknown constant!"); + } + Stream.EmitRecord(Code, Record, AbbrevToUse); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleConstants() { + const ValueEnumerator::ValueList &Vals = VE.getValues(); + + // Find the first constant to emit, which is the first non-globalvalue value. + // We know globalvalues have been emitted by WriteModuleInfo. + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + if (!isa<GlobalValue>(Vals[i].first)) { + writeConstants(i, Vals.size(), true); + return; + } + } +} + +/// pushValueAndType - The file has to encode both the value and type id for +/// many values, because we need to know what type to create for forward +/// references. However, most operands are not forward references, so this type +/// field is not needed. +/// +/// This function adds V's value ID to Vals. If the value ID is higher than the +/// instruction ID, then it is a forward reference, and it also includes the +/// type ID. The value ID that is written is encoded relative to the InstID. +bool DXILBitcodeWriter::pushValueAndType(const Value *V, unsigned InstID, + SmallVectorImpl<unsigned> &Vals) { + unsigned ValID = VE.getValueID(V); + // Make encoding relative to the InstID. + Vals.push_back(InstID - ValID); + if (ValID >= InstID) { + Vals.push_back(getTypeID(V->getType(), V)); + return true; + } + return false; +} + +/// pushValue - Like pushValueAndType, but where the type of the value is +/// omitted (perhaps it was already encoded in an earlier operand). +void DXILBitcodeWriter::pushValue(const Value *V, unsigned InstID, + SmallVectorImpl<unsigned> &Vals) { + unsigned ValID = VE.getValueID(V); + Vals.push_back(InstID - ValID); +} + +void DXILBitcodeWriter::pushValueSigned(const Value *V, unsigned InstID, + SmallVectorImpl<uint64_t> &Vals) { + unsigned ValID = VE.getValueID(V); + int64_t diff = ((int32_t)InstID - (int32_t)ValID); + emitSignedInt64(Vals, diff); +} + +/// WriteInstruction - Emit an instruction +void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, + SmallVectorImpl<unsigned> &Vals) { + unsigned Code = 0; + unsigned AbbrevToUse = 0; + VE.setInstructionID(&I); + switch (I.getOpcode()) { + default: + if (Instruction::isCast(I.getOpcode())) { + Code = bitc::FUNC_CODE_INST_CAST; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)FUNCTION_INST_CAST_ABBREV; + Vals.push_back(getTypeID(I.getType(), &I)); + Vals.push_back(getEncodedCastOpcode(I.getOpcode())); + } else { + assert(isa<BinaryOperator>(I) && "Unknown instruction!"); + Code = bitc::FUNC_CODE_INST_BINOP; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)FUNCTION_INST_BINOP_ABBREV; + pushValue(I.getOperand(1), InstID, Vals); + Vals.push_back(getEncodedBinaryOpcode(I.getOpcode())); + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) { + if (AbbrevToUse == (unsigned)FUNCTION_INST_BINOP_ABBREV) + AbbrevToUse = (unsigned)FUNCTION_INST_BINOP_FLAGS_ABBREV; + Vals.push_back(Flags); + } + } + break; + + case Instruction::GetElementPtr: { + Code = bitc::FUNC_CODE_INST_GEP; + AbbrevToUse = (unsigned)FUNCTION_INST_GEP_ABBREV; + auto &GEPInst = cast<GetElementPtrInst>(I); + Vals.push_back(GEPInst.isInBounds()); + Vals.push_back(getTypeID(GEPInst.getSourceElementType())); + for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); + break; + } + case Instruction::ExtractValue: { + Code = bitc::FUNC_CODE_INST_EXTRACTVAL; + pushValueAndType(I.getOperand(0), InstID, Vals); + const ExtractValueInst *EVI = cast<ExtractValueInst>(&I); + Vals.append(EVI->idx_begin(), EVI->idx_end()); + break; + } + case Instruction::InsertValue: { + Code = bitc::FUNC_CODE_INST_INSERTVAL; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValueAndType(I.getOperand(1), InstID, Vals); + const InsertValueInst *IVI = cast<InsertValueInst>(&I); + Vals.append(IVI->idx_begin(), IVI->idx_end()); + break; + } + case Instruction::Select: + Code = bitc::FUNC_CODE_INST_VSELECT; + pushValueAndType(I.getOperand(1), InstID, Vals); + pushValue(I.getOperand(2), InstID, Vals); + pushValueAndType(I.getOperand(0), InstID, Vals); + break; + case Instruction::ExtractElement: + Code = bitc::FUNC_CODE_INST_EXTRACTELT; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValueAndType(I.getOperand(1), InstID, Vals); + break; + case Instruction::InsertElement: + Code = bitc::FUNC_CODE_INST_INSERTELT; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + pushValueAndType(I.getOperand(2), InstID, Vals); + break; + case Instruction::ShuffleVector: + Code = bitc::FUNC_CODE_INST_SHUFFLEVEC; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + pushValue(I.getOperand(2), InstID, Vals); + break; + case Instruction::ICmp: + case Instruction::FCmp: { + // compare returning Int1Ty or vector of Int1Ty + Code = bitc::FUNC_CODE_INST_CMP2; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + Vals.push_back(cast<CmpInst>(I).getPredicate()); + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) + Vals.push_back(Flags); + break; + } + + case Instruction::Ret: { + Code = bitc::FUNC_CODE_INST_RET; + unsigned NumOperands = I.getNumOperands(); + if (NumOperands == 0) + AbbrevToUse = (unsigned)FUNCTION_INST_RET_VOID_ABBREV; + else if (NumOperands == 1) { + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)FUNCTION_INST_RET_VAL_ABBREV; + } else { + for (unsigned i = 0, e = NumOperands; i != e; ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); + } + } break; + case Instruction::Br: { + Code = bitc::FUNC_CODE_INST_BR; + const BranchInst &II = cast<BranchInst>(I); + Vals.push_back(VE.getValueID(II.getSuccessor(0))); + if (II.isConditional()) { + Vals.push_back(VE.getValueID(II.getSuccessor(1))); + pushValue(II.getCondition(), InstID, Vals); + } + } break; + case Instruction::Switch: { + Code = bitc::FUNC_CODE_INST_SWITCH; + const SwitchInst &SI = cast<SwitchInst>(I); + Vals.push_back(getTypeID(SI.getCondition()->getType())); + pushValue(SI.getCondition(), InstID, Vals); + Vals.push_back(VE.getValueID(SI.getDefaultDest())); + for (auto Case : SI.cases()) { + Vals.push_back(VE.getValueID(Case.getCaseValue())); + Vals.push_back(VE.getValueID(Case.getCaseSuccessor())); + } + } break; + case Instruction::IndirectBr: + Code = bitc::FUNC_CODE_INST_INDIRECTBR; + 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) + Vals.push_back(VE.getValueID(I.getOperand(i))); + break; + + case Instruction::Invoke: { + const InvokeInst *II = cast<InvokeInst>(&I); + const Value *Callee = II->getCalledOperand(); + FunctionType *FTy = II->getFunctionType(); + Code = bitc::FUNC_CODE_INST_INVOKE; + + Vals.push_back(VE.getAttributeListID(II->getAttributes())); + Vals.push_back(II->getCallingConv() | 1 << 13); + Vals.push_back(VE.getValueID(II->getNormalDest())); + Vals.push_back(VE.getValueID(II->getUnwindDest())); + Vals.push_back(getTypeID(FTy)); + pushValueAndType(Callee, InstID, Vals); + + // Emit value #'s for the fixed parameters. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) + pushValue(I.getOperand(i), InstID, Vals); // fixed param. + + // Emit type/value pairs for varargs params. + if (FTy->isVarArg()) { + for (unsigned i = FTy->getNumParams(), e = I.getNumOperands() - 3; i != e; + ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); // vararg + } + break; + } + case Instruction::Resume: + Code = bitc::FUNC_CODE_INST_RESUME; + pushValueAndType(I.getOperand(0), InstID, Vals); + break; + case Instruction::Unreachable: + Code = bitc::FUNC_CODE_INST_UNREACHABLE; + AbbrevToUse = (unsigned)FUNCTION_INST_UNREACHABLE_ABBREV; + break; + + case Instruction::PHI: { + const PHINode &PN = cast<PHINode>(I); + Code = bitc::FUNC_CODE_INST_PHI; + // With the newer instruction encoding, forward references could give + // negative valued IDs. This is most common for PHIs, so we use + // signed VBRs. + SmallVector<uint64_t, 128> Vals64; + 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))); + } + // Emit a Vals64 vector and exit. + Stream.EmitRecord(Code, Vals64, AbbrevToUse); + Vals64.clear(); + return; + } + + case Instruction::LandingPad: { + const LandingPadInst &LP = cast<LandingPadInst>(I); + Code = bitc::FUNC_CODE_INST_LANDINGPAD; + 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) { + if (LP.isCatch(I)) + Vals.push_back(LandingPadInst::Catch); + else + Vals.push_back(LandingPadInst::Filter); + pushValueAndType(LP.getClause(I), InstID, Vals); + } + break; + } + + case Instruction::Alloca: { + Code = bitc::FUNC_CODE_INST_ALLOCA; + const AllocaInst &AI = cast<AllocaInst>(I); + 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; + unsigned EncodedAlign = getEncodedAlign(AI.getAlign()); + Bitfield::set<APV::AlignLower>( + Record, EncodedAlign & ((1 << APV::AlignLower::Bits) - 1)); + Bitfield::set<APV::AlignUpper>(Record, + EncodedAlign >> APV::AlignLower::Bits); + Bitfield::set<APV::UsedWithInAlloca>(Record, AI.isUsedWithInAlloca()); + Vals.push_back(Record); + break; + } + + case Instruction::Load: + if (cast<LoadInst>(I).isAtomic()) { + Code = bitc::FUNC_CODE_INST_LOADATOMIC; + pushValueAndType(I.getOperand(0), InstID, Vals); + } else { + Code = bitc::FUNC_CODE_INST_LOAD; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) // ptr + AbbrevToUse = (unsigned)FUNCTION_INST_LOAD_ABBREV; + } + Vals.push_back(getTypeID(I.getType())); + Vals.push_back(Log2(cast<LoadInst>(I).getAlign()) + 1); + Vals.push_back(cast<LoadInst>(I).isVolatile()); + if (cast<LoadInst>(I).isAtomic()) { + Vals.push_back(getEncodedOrdering(cast<LoadInst>(I).getOrdering())); + Vals.push_back(getEncodedSyncScopeID(cast<LoadInst>(I).getSyncScopeID())); + } + break; + case Instruction::Store: + if (cast<StoreInst>(I).isAtomic()) + Code = bitc::FUNC_CODE_INST_STOREATOMIC; + else + Code = bitc::FUNC_CODE_INST_STORE; + pushValueAndType(I.getOperand(1), InstID, Vals); // ptrty + ptr + pushValueAndType(I.getOperand(0), InstID, Vals); // valty + val + Vals.push_back(Log2(cast<StoreInst>(I).getAlign()) + 1); + Vals.push_back(cast<StoreInst>(I).isVolatile()); + if (cast<StoreInst>(I).isAtomic()) { + Vals.push_back(getEncodedOrdering(cast<StoreInst>(I).getOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast<StoreInst>(I).getSyncScopeID())); + } + break; + case Instruction::AtomicCmpXchg: + Code = bitc::FUNC_CODE_INST_CMPXCHG; + pushValueAndType(I.getOperand(0), InstID, Vals); // ptrty + ptr + pushValueAndType(I.getOperand(1), InstID, Vals); // cmp. + pushValue(I.getOperand(2), InstID, Vals); // newval. + Vals.push_back(cast<AtomicCmpXchgInst>(I).isVolatile()); + Vals.push_back( + getEncodedOrdering(cast<AtomicCmpXchgInst>(I).getSuccessOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast<AtomicCmpXchgInst>(I).getSyncScopeID())); + Vals.push_back( + getEncodedOrdering(cast<AtomicCmpXchgInst>(I).getFailureOrdering())); + Vals.push_back(cast<AtomicCmpXchgInst>(I).isWeak()); + break; + case Instruction::AtomicRMW: + Code = bitc::FUNC_CODE_INST_ATOMICRMW; + pushValueAndType(I.getOperand(0), InstID, Vals); // ptrty + ptr + pushValue(I.getOperand(1), InstID, Vals); // val. + Vals.push_back( + getEncodedRMWOperation(cast<AtomicRMWInst>(I).getOperation())); + Vals.push_back(cast<AtomicRMWInst>(I).isVolatile()); + Vals.push_back(getEncodedOrdering(cast<AtomicRMWInst>(I).getOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast<AtomicRMWInst>(I).getSyncScopeID())); + break; + case Instruction::Fence: + Code = bitc::FUNC_CODE_INST_FENCE; + Vals.push_back(getEncodedOrdering(cast<FenceInst>(I).getOrdering())); + Vals.push_back(getEncodedSyncScopeID(cast<FenceInst>(I).getSyncScopeID())); + break; + case Instruction::Call: { + const CallInst &CI = cast<CallInst>(I); + FunctionType *FTy = CI.getFunctionType(); + + Code = bitc::FUNC_CODE_INST_CALL; + + 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())); + pushValueAndType(CI.getCalledOperand(), InstID, Vals); // Callee + + // Emit value #'s for the fixed parameters. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) { + // Check for labels (can happen with asm labels). + if (FTy->getParamType(i)->isLabelTy()) + Vals.push_back(VE.getValueID(CI.getArgOperand(i))); + else + pushValue(CI.getArgOperand(i), InstID, Vals); // fixed param. + } + + // Emit type/value pairs for varargs params. + if (FTy->isVarArg()) { + for (unsigned i = FTy->getNumParams(), e = CI.arg_size(); i != e; ++i) + pushValueAndType(CI.getArgOperand(i), InstID, Vals); // varargs + } + break; + } + case Instruction::VAArg: + Code = bitc::FUNC_CODE_INST_VAARG; + Vals.push_back(getTypeID(I.getOperand(0)->getType())); // valistty + pushValue(I.getOperand(0), InstID, Vals); // valist. + Vals.push_back(getTypeID(I.getType())); // restype. + break; + } + + Stream.EmitRecord(Code, Vals, AbbrevToUse); + Vals.clear(); +} + +// Emit names for globals/functions etc. +void DXILBitcodeWriter::writeFunctionLevelValueSymbolTable( + const ValueSymbolTable &VST) { + if (VST.empty()) + return; + Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4); + + SmallVector<unsigned, 64> NameVals; + + // HLSL Change + // Read the named values from a sorted list instead of the original list + // to ensure the binary is the same no matter what values ever existed. + SmallVector<const ValueName *, 16> SortedTable; + + for (auto &VI : VST) { + SortedTable.push_back(VI.second->getValueName()); + } + // The keys are unique, so there shouldn't be stability issues. + std::sort(SortedTable.begin(), SortedTable.end(), + [](const ValueName *A, const ValueName *B) { + return A->first() < B->first(); + }); + + for (const ValueName *SI : SortedTable) { + auto &Name = *SI; + + // Figure out the encoding to use for the name. + bool is7Bit = true; + bool isChar6 = true; + for (const char *C = Name.getKeyData(), *E = C + Name.getKeyLength(); + C != E; ++C) { + if (isChar6) + isChar6 = BitCodeAbbrevOp::isChar6(*C); + if ((unsigned char)*C & 128) { + is7Bit = false; + break; // don't bother scanning the rest. + } + } + + unsigned AbbrevToUse = VST_ENTRY_8_ABBREV; + + // VST_ENTRY: [valueid, namechar x N] + // VST_BBENTRY: [bbid, namechar x N] + unsigned Code; + if (isa<BasicBlock>(SI->getValue())) { + Code = bitc::VST_CODE_BBENTRY; + if (isChar6) + AbbrevToUse = VST_BBENTRY_6_ABBREV; + } else { + Code = bitc::VST_CODE_ENTRY; + if (isChar6) + AbbrevToUse = VST_ENTRY_6_ABBREV; + else if (is7Bit) + AbbrevToUse = VST_ENTRY_7_ABBREV; + } + + NameVals.push_back(VE.getValueID(SI->getValue())); + for (const char *P = Name.getKeyData(), + *E = Name.getKeyData() + Name.getKeyLength(); + P != E; ++P) + NameVals.push_back((unsigned char)*P); + + // Emit the finished record. + Stream.EmitRecord(Code, NameVals, AbbrevToUse); + NameVals.clear(); + } + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeUseList(UseListOrder &&Order) { + assert(Order.Shuffle.size() >= 2 && "Shuffle too small"); + unsigned Code; + if (isa<BasicBlock>(Order.V)) + Code = bitc::USELIST_CODE_BB; + else + Code = bitc::USELIST_CODE_DEFAULT; + + SmallVector<uint64_t, 64> Record(Order.Shuffle.begin(), Order.Shuffle.end()); + Record.push_back(VE.getValueID(Order.V)); + Stream.EmitRecord(Code, Record); +} + +void DXILBitcodeWriter::writeUseListBlock(const Function *F) { + auto hasMore = [&]() { + return !VE.UseListOrders.empty() && VE.UseListOrders.back().F == F; + }; + if (!hasMore()) + // Nothing to do. + return; + + Stream.EnterSubblock(bitc::USELIST_BLOCK_ID, 3); + while (hasMore()) { + writeUseList(std::move(VE.UseListOrders.back())); + VE.UseListOrders.pop_back(); + } + Stream.ExitBlock(); +} + +/// Emit a function body to the module stream. +void DXILBitcodeWriter::writeFunction(const Function &F) { + Stream.EnterSubblock(bitc::FUNCTION_BLOCK_ID, 4); + VE.incorporateFunction(F); + + SmallVector<unsigned, 64> Vals; + + // Emit the number of basic blocks, so the reader can create them ahead of + // time. + Vals.push_back(VE.getBasicBlocks().size()); + Stream.EmitRecord(bitc::FUNC_CODE_DECLAREBLOCKS, Vals); + Vals.clear(); + + // If there are function-local constants, emit them now. + unsigned CstStart, CstEnd; + VE.getFunctionConstantRange(CstStart, CstEnd); + writeConstants(CstStart, CstEnd, false); + + // If there is function-local metadata, emit it now. + writeFunctionMetadata(F); + + // Keep a running idea of what the instruction ID is. + unsigned InstID = CstEnd; + + bool NeedsMetadataAttachment = F.hasMetadata(); + + DILocation *LastDL = nullptr; + + // Finally, emit all the instructions, in order. + for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; + ++I) { + writeInstruction(*I, InstID, Vals); + + if (!I->getType()->isVoidTy()) + ++InstID; + + // If the instruction has metadata, write a metadata attachment later. + NeedsMetadataAttachment |= I->hasMetadataOtherThanDebugLoc(); + + // If the instruction has a debug location, emit it. + DILocation *DL = I->getDebugLoc(); + if (!DL) + continue; + + if (DL == LastDL) { + // Just repeat the same debug loc as last time. + Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC_AGAIN, Vals); + continue; + } + + Vals.push_back(DL->getLine()); + Vals.push_back(DL->getColumn()); + Vals.push_back(VE.getMetadataOrNullID(DL->getScope())); + Vals.push_back(VE.getMetadataOrNullID(DL->getInlinedAt())); + Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC, Vals); + Vals.clear(); + + LastDL = DL; + } + + // Emit names for all the instructions etc. + if (auto *Symtab = F.getValueSymbolTable()) + writeFunctionLevelValueSymbolTable(*Symtab); + + if (NeedsMetadataAttachment) + writeFunctionMetadataAttachment(F); + + writeUseListBlock(&F); + VE.purgeFunction(); + Stream.ExitBlock(); +} + +// Emit blockinfo, which defines the standard abbreviations etc. +void DXILBitcodeWriter::writeBlockInfo() { + // We only want to emit block info records for blocks that have multiple + // instances: CONSTANTS_BLOCK, FUNCTION_BLOCK and VALUE_SYMTAB_BLOCK. + // Other blocks can define their abbrevs inline. + Stream.EnterBlockInfoBlock(); + + { // 8-bit fixed-width VST_ENTRY/VST_BBENTRY strings. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_8_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + { // 7-bit fixed width VST_ENTRY strings. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_ENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_7_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // 6-bit char6 VST_ENTRY strings. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_ENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_6_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // 6-bit char6 VST_BBENTRY strings. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_BBENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_BBENTRY_6_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + { // SETTYPE abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_SETTYPE)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + VE.computeBitsRequiredForTypeIndicies())); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_SETTYPE_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + { // INTEGER abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_INTEGER)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_INTEGER_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + { // CE_CAST abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CE_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // cast opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // typeid + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id + + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_CE_CAST_Abbrev) + assert(false && "Unexpected abbrev ordering!"); + } + { // NULL abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_NULL)); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_NULL_Abbrev) + assert(false && "Unexpected abbrev ordering!"); + } + + // FIXME: This should only use space for first class types! + + { // INST_LOAD abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_LOAD)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Ptr + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // Align + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // volatile + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_LOAD_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // INST_BINOP abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // RHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_BINOP_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // INST_BINOP_FLAGS abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // RHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); // flags + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_BINOP_FLAGS_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // INST_CAST abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpVal + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_CAST_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + { // INST_RET abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_RET_VOID_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // INST_RET abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ValID + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_RET_VAL_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { // INST_UNREACHABLE abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNREACHABLE)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_UNREACHABLE_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + { + auto Abbv = std::make_shared<BitCodeAbbrev>(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_GEP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + Log2_32_Ceil(VE.getTypes().size() + 1))); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)FUNCTION_INST_GEP_ABBREV) + assert(false && "Unexpected abbrev ordering!"); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleVersion() { + // VERSION: [version#] + Stream.EmitRecord(bitc::MODULE_CODE_VERSION, ArrayRef<unsigned>{1}); +} + +/// WriteModule - Emit the specified module to the bitstream. +void DXILBitcodeWriter::write() { + // The identification block is new since llvm-3.7, but the old bitcode reader + // will skip it. + // writeIdentificationBlock(Stream); + + Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); + + // It is redundant to fully-specify this here, but nice to make it explicit + // so that it is clear the DXIL module version is different. + DXILBitcodeWriter::writeModuleVersion(); + + // Emit blockinfo, which defines the standard abbreviations etc. + writeBlockInfo(); + + // Emit information about attribute groups. + writeAttributeGroupTable(); + + // Emit information about parameter attributes. + writeAttributeTable(); + + // Emit information describing all of the types in the module. + writeTypeTable(); + + writeComdats(); + + // Emit top-level description of module, including target triple, inline asm, + // descriptors for global variables, and function prototype info. + writeModuleInfo(); + + // Emit constants. + writeModuleConstants(); + + // Emit metadata. + writeModuleMetadataKinds(); + + // Emit metadata. + writeModuleMetadata(); + + // Emit names for globals/functions etc. + // DXIL uses the same format for module-level value symbol table as for the + // function level table. + writeFunctionLevelValueSymbolTable(M.getValueSymbolTable()); + + // Emit module-level use-lists. + writeUseListBlock(nullptr); + + // Emit function bodies. + for (const Function &F : M) + if (!F.isDeclaration()) + writeFunction(F); + + Stream.ExitBlock(); +} diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.h b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.h new file mode 100644 index 000000000000..289f692f0f82 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.h @@ -0,0 +1,82 @@ +//===- Bitcode/Writer/DXILBitcodeWriter.cpp - DXIL Bitcode 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 +// +//===----------------------------------------------------------------------===// +// +// Bitcode writer implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/MemoryBufferRef.h" +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace llvm { + +class BitstreamWriter; +class Module; +class raw_ostream; + +namespace dxil { + +class BitcodeWriter { + SmallVectorImpl<char> &Buffer; + std::unique_ptr<BitstreamWriter> Stream; + + StringTableBuilder StrtabBuilder{StringTableBuilder::RAW}; + + // Owns any strings created by the irsymtab writer until we create the + // string table. + BumpPtrAllocator Alloc; + + bool WroteStrtab = false, WroteSymtab = false; + + void writeBlob(unsigned Block, unsigned Record, StringRef Blob); + + std::vector<Module *> Mods; + +public: + /// Create a BitcodeWriter that writes to Buffer. + BitcodeWriter(SmallVectorImpl<char> &Buffer, raw_fd_stream *FS = nullptr); + + ~BitcodeWriter(); + + /// Attempt to write a symbol table to the bitcode file. This must be called + /// at most once after all modules have been written. + /// + /// A reader does not require a symbol table to interpret a bitcode file; + /// the symbol table is needed only to improve link-time performance. So + /// this function may decide not to write a symbol table. It may so decide + /// if, for example, the target is unregistered or the IR is malformed. + void writeSymtab(); + + /// Write the bitcode file's string table. This must be called exactly once + /// after all modules and the optional symbol table have been written. + void writeStrtab(); + + /// Copy the string table for another module into this bitcode file. This + /// should be called after copying the module itself into the bitcode file. + void copyStrtab(StringRef Strtab); + + /// Write the specified module to the buffer specified at construction time. + void writeModule(const Module &M); +}; + +/// Write the specified module to the specified raw output stream. +/// +/// For streams where it matters, the given stream should be in "binary" +/// mode. +void WriteDXILToFile(const Module &M, raw_ostream &Out); + +} // namespace dxil + +} // namespace llvm diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp new file mode 100644 index 000000000000..08944ee3f1fe --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.cpp @@ -0,0 +1,1147 @@ +//===- ValueEnumerator.cpp - Number values and types for bitcode 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the ValueEnumerator class. +// Forked from lib/Bitcode/Writer +// +//===----------------------------------------------------------------------===// + +#include "DXILValueEnumerator.h" +#include "DXILPointerType.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" +#include "llvm/IR/GlobalObject.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Use.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstddef> +#include <iterator> +#include <tuple> + +using namespace llvm; +using namespace llvm::dxil; + +namespace { + +struct OrderMap { + DenseMap<const Value *, std::pair<unsigned, bool>> IDs; + unsigned LastGlobalConstantID = 0; + unsigned LastGlobalValueID = 0; + + OrderMap() = default; + + bool isGlobalConstant(unsigned ID) const { + return ID <= LastGlobalConstantID; + } + + bool isGlobalValue(unsigned ID) const { + return ID <= LastGlobalValueID && !isGlobalConstant(ID); + } + + unsigned size() const { return IDs.size(); } + std::pair<unsigned, bool> &operator[](const Value *V) { return IDs[V]; } + + std::pair<unsigned, bool> lookup(const Value *V) const { + return IDs.lookup(V); + } + + void index(const Value *V) { + // Explicitly sequence get-size and insert-value operations to avoid UB. + unsigned ID = IDs.size() + 1; + IDs[V].first = ID; + } +}; + +} // end anonymous namespace + +static void orderValue(const Value *V, OrderMap &OM) { + if (OM.lookup(V).first) + return; + + if (const Constant *C = dyn_cast<Constant>(V)) { + if (C->getNumOperands() && !isa<GlobalValue>(C)) { + for (const Value *Op : C->operands()) + if (!isa<BasicBlock>(Op) && !isa<GlobalValue>(Op)) + orderValue(Op, OM); + if (auto *CE = dyn_cast<ConstantExpr>(C)) + if (CE->getOpcode() == Instruction::ShuffleVector) + orderValue(CE->getShuffleMaskForBitcode(), OM); + } + } + + // Note: we cannot cache this lookup above, since inserting into the map + // changes the map's size, and thus affects the other IDs. + OM.index(V); +} + +static OrderMap orderModule(const Module &M) { + // This needs to match the order used by ValueEnumerator::ValueEnumerator() + // and ValueEnumerator::incorporateFunction(). + OrderMap OM; + + // In the reader, initializers of GlobalValues are set *after* all the + // globals have been read. Rather than awkwardly modeling this behaviour + // directly in predictValueUseListOrderImpl(), just assign IDs to + // initializers of GlobalValues before GlobalValues themselves to model this + // implicitly. + for (const GlobalVariable &G : M.globals()) + if (G.hasInitializer()) + if (!isa<GlobalValue>(G.getInitializer())) + orderValue(G.getInitializer(), OM); + for (const GlobalAlias &A : M.aliases()) + if (!isa<GlobalValue>(A.getAliasee())) + orderValue(A.getAliasee(), OM); + for (const GlobalIFunc &I : M.ifuncs()) + if (!isa<GlobalValue>(I.getResolver())) + orderValue(I.getResolver(), OM); + for (const Function &F : M) { + for (const Use &U : F.operands()) + if (!isa<GlobalValue>(U.get())) + orderValue(U.get(), OM); + } + + // As constants used in metadata operands are emitted as module-level + // constants, we must order them before other operands. Also, we must order + // these before global values, as these will be read before setting the + // global values' initializers. The latter matters for constants which have + // uses towards other constants that are used as initializers. + auto orderConstantValue = [&OM](const Value *V) { + if ((isa<Constant>(V) && !isa<GlobalValue>(V)) || isa<InlineAsm>(V)) + orderValue(V, OM); + }; + for (const Function &F : M) { + if (F.isDeclaration()) + continue; + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + for (const Value *V : I.operands()) { + if (const auto *MAV = dyn_cast<MetadataAsValue>(V)) { + if (const auto *VAM = + dyn_cast<ValueAsMetadata>(MAV->getMetadata())) { + orderConstantValue(VAM->getValue()); + } else if (const auto *AL = + dyn_cast<DIArgList>(MAV->getMetadata())) { + for (const auto *VAM : AL->getArgs()) + orderConstantValue(VAM->getValue()); + } + } + } + } + OM.LastGlobalConstantID = OM.size(); + + // Initializers of GlobalValues are processed in + // BitcodeReader::ResolveGlobalAndAliasInits(). Match the order there rather + // than ValueEnumerator, and match the code in predictValueUseListOrderImpl() + // by giving IDs in reverse order. + // + // Since GlobalValues never reference each other directly (just through + // initializers), their relative IDs only matter for determining order of + // uses in their initializers. + for (const Function &F : M) + orderValue(&F, OM); + for (const GlobalAlias &A : M.aliases()) + orderValue(&A, OM); + for (const GlobalIFunc &I : M.ifuncs()) + orderValue(&I, OM); + for (const GlobalVariable &G : M.globals()) + orderValue(&G, OM); + OM.LastGlobalValueID = OM.size(); + + for (const Function &F : M) { + if (F.isDeclaration()) + continue; + // Here we need to match the union of ValueEnumerator::incorporateFunction() + // and WriteFunction(). Basic blocks are implicitly declared before + // anything else (by declaring their size). + for (const BasicBlock &BB : F) + orderValue(&BB, OM); + for (const Argument &A : F.args()) + orderValue(&A, OM); + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) { + for (const Value *Op : I.operands()) + if ((isa<Constant>(*Op) && !isa<GlobalValue>(*Op)) || + isa<InlineAsm>(*Op)) + orderValue(Op, OM); + if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I)) + orderValue(SVI->getShuffleMaskForBitcode(), OM); + } + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + orderValue(&I, OM); + } + return OM; +} + +static void predictValueUseListOrderImpl(const Value *V, const Function *F, + unsigned ID, const OrderMap &OM, + UseListOrderStack &Stack) { + // Predict use-list order for this one. + using Entry = std::pair<const Use *, unsigned>; + SmallVector<Entry, 64> List; + for (const Use &U : V->uses()) + // Check if this user will be serialized. + if (OM.lookup(U.getUser()).first) + List.push_back(std::make_pair(&U, List.size())); + + if (List.size() < 2) + // We may have lost some users. + return; + + bool IsGlobalValue = OM.isGlobalValue(ID); + llvm::sort(List, [&](const Entry &L, const Entry &R) { + const Use *LU = L.first; + const Use *RU = R.first; + if (LU == RU) + return false; + + auto LID = OM.lookup(LU->getUser()).first; + auto RID = OM.lookup(RU->getUser()).first; + + // Global values are processed in reverse order. + // + // Moreover, initializers of GlobalValues are set *after* all the globals + // have been read (despite having earlier IDs). Rather than awkwardly + // modeling this behaviour here, orderModule() has assigned IDs to + // initializers of GlobalValues before GlobalValues themselves. + if (OM.isGlobalValue(LID) && OM.isGlobalValue(RID)) { + if (LID == RID) + return LU->getOperandNo() > RU->getOperandNo(); + return LID < RID; + } + + // If ID is 4, then expect: 7 6 5 1 2 3. + if (LID < RID) { + if (RID <= ID) + if (!IsGlobalValue) // GlobalValue uses don't get reversed. + return true; + return false; + } + if (RID < LID) { + if (LID <= ID) + if (!IsGlobalValue) // GlobalValue uses don't get reversed. + return false; + return true; + } + + // LID and RID are equal, so we have different operands of the same user. + // Assume operands are added in order for all instructions. + if (LID <= ID) + if (!IsGlobalValue) // GlobalValue uses don't get reversed. + return LU->getOperandNo() < RU->getOperandNo(); + return LU->getOperandNo() > RU->getOperandNo(); + }); + + if (llvm::is_sorted(List, [](const Entry &L, const Entry &R) { + return L.second < R.second; + })) + // Order is already correct. + return; + + // Store the shuffle. + Stack.emplace_back(V, F, List.size()); + assert(List.size() == Stack.back().Shuffle.size() && "Wrong size"); + for (size_t I = 0, E = List.size(); I != E; ++I) + Stack.back().Shuffle[I] = List[I].second; +} + +static void predictValueUseListOrder(const Value *V, const Function *F, + OrderMap &OM, UseListOrderStack &Stack) { + auto &IDPair = OM[V]; + assert(IDPair.first && "Unmapped value"); + if (IDPair.second) + // Already predicted. + return; + + // Do the actual prediction. + IDPair.second = true; + if (!V->use_empty() && std::next(V->use_begin()) != V->use_end()) + predictValueUseListOrderImpl(V, F, IDPair.first, OM, Stack); + + // Recursive descent into constants. + if (const Constant *C = dyn_cast<Constant>(V)) { + if (C->getNumOperands()) { // Visit GlobalValues. + for (const Value *Op : C->operands()) + if (isa<Constant>(Op)) // Visit GlobalValues. + predictValueUseListOrder(Op, F, OM, Stack); + if (auto *CE = dyn_cast<ConstantExpr>(C)) + if (CE->getOpcode() == Instruction::ShuffleVector) + predictValueUseListOrder(CE->getShuffleMaskForBitcode(), F, OM, + Stack); + } + } +} + +static UseListOrderStack predictUseListOrder(const Module &M) { + OrderMap OM = orderModule(M); + + // Use-list orders need to be serialized after all the users have been added + // to a value, or else the shuffles will be incomplete. Store them per + // function in a stack. + // + // Aside from function order, the order of values doesn't matter much here. + UseListOrderStack Stack; + + // We want to visit the functions backward now so we can list function-local + // constants in the last Function they're used in. Module-level constants + // have already been visited above. + for (const Function &F : llvm::reverse(M)) { + if (F.isDeclaration()) + continue; + for (const BasicBlock &BB : F) + predictValueUseListOrder(&BB, &F, OM, Stack); + for (const Argument &A : F.args()) + predictValueUseListOrder(&A, &F, OM, Stack); + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) { + for (const Value *Op : I.operands()) + if (isa<Constant>(*Op) || isa<InlineAsm>(*Op)) // Visit GlobalValues. + predictValueUseListOrder(Op, &F, OM, Stack); + if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I)) + predictValueUseListOrder(SVI->getShuffleMaskForBitcode(), &F, OM, + Stack); + } + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + predictValueUseListOrder(&I, &F, OM, Stack); + } + + // Visit globals last, since the module-level use-list block will be seen + // before the function bodies are processed. + for (const GlobalVariable &G : M.globals()) + predictValueUseListOrder(&G, nullptr, OM, Stack); + for (const Function &F : M) + predictValueUseListOrder(&F, nullptr, OM, Stack); + for (const GlobalAlias &A : M.aliases()) + predictValueUseListOrder(&A, nullptr, OM, Stack); + for (const GlobalIFunc &I : M.ifuncs()) + predictValueUseListOrder(&I, nullptr, OM, Stack); + for (const GlobalVariable &G : M.globals()) + if (G.hasInitializer()) + predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack); + for (const GlobalAlias &A : M.aliases()) + predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack); + for (const GlobalIFunc &I : M.ifuncs()) + predictValueUseListOrder(I.getResolver(), nullptr, OM, Stack); + for (const Function &F : M) { + for (const Use &U : F.operands()) + predictValueUseListOrder(U.get(), nullptr, OM, Stack); + } + + return Stack; +} + +ValueEnumerator::ValueEnumerator(const Module &M, Type *PrefixType) { + EnumerateType(PrefixType); + + UseListOrders = predictUseListOrder(M); + + // Enumerate the global variables. + for (const GlobalVariable &GV : M.globals()) { + EnumerateValue(&GV); + EnumerateType(GV.getValueType()); + } + + // Enumerate the functions. + for (const Function &F : M) { + EnumerateValue(&F); + EnumerateType(F.getValueType()); + EnumerateType( + dxil::TypedPointerType::get(F.getFunctionType(), F.getAddressSpace())); + EnumerateAttributes(F.getAttributes()); + } + + // Enumerate the aliases. + for (const GlobalAlias &GA : M.aliases()) { + EnumerateValue(&GA); + EnumerateType(GA.getValueType()); + } + + // Enumerate the ifuncs. + for (const GlobalIFunc &GIF : M.ifuncs()) { + EnumerateValue(&GIF); + EnumerateType(GIF.getValueType()); + } + + // Enumerate the global variable initializers and attributes. + for (const GlobalVariable &GV : M.globals()) { + if (GV.hasInitializer()) + EnumerateValue(GV.getInitializer()); + EnumerateType( + dxil::TypedPointerType::get(GV.getValueType(), GV.getAddressSpace())); + if (GV.hasAttributes()) + EnumerateAttributes(GV.getAttributesAsList(AttributeList::FunctionIndex)); + } + + // Enumerate the aliasees. + for (const GlobalAlias &GA : M.aliases()) + EnumerateValue(GA.getAliasee()); + + // Enumerate the ifunc resolvers. + for (const GlobalIFunc &GIF : M.ifuncs()) + EnumerateValue(GIF.getResolver()); + + // Enumerate any optional Function data. + for (const Function &F : M) + for (const Use &U : F.operands()) + EnumerateValue(U.get()); + + // Enumerate the metadata type. + // + // TODO: Move this to ValueEnumerator::EnumerateOperandType() once bitcode + // only encodes the metadata type when it's used as a value. + EnumerateType(Type::getMetadataTy(M.getContext())); + + // Insert constants and metadata that are named at module level into the slot + // pool so that the module symbol table can refer to them... + EnumerateValueSymbolTable(M.getValueSymbolTable()); + EnumerateNamedMetadata(M); + + SmallVector<std::pair<unsigned, MDNode *>, 8> MDs; + for (const GlobalVariable &GV : M.globals()) { + MDs.clear(); + GV.getAllMetadata(MDs); + for (const auto &I : MDs) + // FIXME: Pass GV to EnumerateMetadata and arrange for the bitcode writer + // to write metadata to the global variable's own metadata block + // (PR28134). + EnumerateMetadata(nullptr, I.second); + } + + // Enumerate types used by function bodies and argument lists. + for (const Function &F : M) { + for (const Argument &A : F.args()) + EnumerateType(A.getType()); + + // Enumerate metadata attached to this function. + MDs.clear(); + F.getAllMetadata(MDs); + for (const auto &I : MDs) + EnumerateMetadata(F.isDeclaration() ? nullptr : &F, I.second); + + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) { + for (const Use &Op : I.operands()) { + auto *MD = dyn_cast<MetadataAsValue>(&Op); + if (!MD) { + EnumerateOperandType(Op); + continue; + } + + // Local metadata is enumerated during function-incorporation, but + // any ConstantAsMetadata arguments in a DIArgList should be examined + // now. + if (isa<LocalAsMetadata>(MD->getMetadata())) + continue; + if (auto *AL = dyn_cast<DIArgList>(MD->getMetadata())) { + for (auto *VAM : AL->getArgs()) + if (isa<ConstantAsMetadata>(VAM)) + EnumerateMetadata(&F, VAM); + continue; + } + + EnumerateMetadata(&F, MD->getMetadata()); + } + if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I)) + EnumerateType(SVI->getShuffleMaskForBitcode()->getType()); + if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) + EnumerateType(GEP->getSourceElementType()); + if (auto *AI = dyn_cast<AllocaInst>(&I)) + EnumerateType(AI->getAllocatedType()); + EnumerateType(I.getType()); + if (const auto *Call = dyn_cast<CallBase>(&I)) { + EnumerateAttributes(Call->getAttributes()); + EnumerateType(Call->getFunctionType()); + } + + // Enumerate metadata attached with this instruction. + MDs.clear(); + I.getAllMetadataOtherThanDebugLoc(MDs); + for (unsigned i = 0, e = MDs.size(); i != e; ++i) + EnumerateMetadata(&F, MDs[i].second); + + // Don't enumerate the location directly -- it has a special record + // type -- but enumerate its operands. + if (DILocation *L = I.getDebugLoc()) + for (const Metadata *Op : L->operands()) + EnumerateMetadata(&F, Op); + } + } + + // Organize metadata ordering. + organizeMetadata(); +} + +unsigned ValueEnumerator::getInstructionID(const Instruction *Inst) const { + InstructionMapType::const_iterator I = InstructionMap.find(Inst); + assert(I != InstructionMap.end() && "Instruction is not mapped!"); + return I->second; +} + +unsigned ValueEnumerator::getComdatID(const Comdat *C) const { + unsigned ComdatID = Comdats.idFor(C); + assert(ComdatID && "Comdat not found!"); + return ComdatID; +} + +void ValueEnumerator::setInstructionID(const Instruction *I) { + InstructionMap[I] = InstructionCount++; +} + +unsigned ValueEnumerator::getValueID(const Value *V) const { + if (auto *MD = dyn_cast<MetadataAsValue>(V)) + return getMetadataID(MD->getMetadata()); + + ValueMapType::const_iterator I = ValueMap.find(V); + assert(I != ValueMap.end() && "Value not in slotcalculator!"); + return I->second - 1; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void ValueEnumerator::dump() const { + print(dbgs(), ValueMap, "Default"); + dbgs() << '\n'; + print(dbgs(), MetadataMap, "MetaData"); + dbgs() << '\n'; +} +#endif + +void ValueEnumerator::print(raw_ostream &OS, const ValueMapType &Map, + const char *Name) const { + OS << "Map Name: " << Name << "\n"; + OS << "Size: " << Map.size() << "\n"; + for (const auto &I : Map) { + const Value *V = I.first; + if (V->hasName()) + OS << "Value: " << V->getName(); + else + OS << "Value: [null]\n"; + V->print(errs()); + errs() << '\n'; + + OS << " Uses(" << V->getNumUses() << "):"; + for (const Use &U : V->uses()) { + if (&U != &*V->use_begin()) + OS << ","; + if (U->hasName()) + OS << " " << U->getName(); + else + OS << " [null]"; + } + OS << "\n\n"; + } +} + +void ValueEnumerator::print(raw_ostream &OS, const MetadataMapType &Map, + const char *Name) const { + OS << "Map Name: " << Name << "\n"; + OS << "Size: " << Map.size() << "\n"; + for (const auto &I : Map) { + const Metadata *MD = I.first; + OS << "Metadata: slot = " << I.second.ID << "\n"; + OS << "Metadata: function = " << I.second.F << "\n"; + MD->print(OS); + OS << "\n"; + } +} + +/// EnumerateValueSymbolTable - Insert all of the values in the specified symbol +/// table into the values table. +void ValueEnumerator::EnumerateValueSymbolTable(const ValueSymbolTable &VST) { + for (ValueSymbolTable::const_iterator VI = VST.begin(), VE = VST.end(); + VI != VE; ++VI) + EnumerateValue(VI->getValue()); +} + +/// Insert all of the values referenced by named metadata in the specified +/// module. +void ValueEnumerator::EnumerateNamedMetadata(const Module &M) { + for (const auto &I : M.named_metadata()) + EnumerateNamedMDNode(&I); +} + +void ValueEnumerator::EnumerateNamedMDNode(const NamedMDNode *MD) { + for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) + EnumerateMetadata(nullptr, MD->getOperand(i)); +} + +unsigned ValueEnumerator::getMetadataFunctionID(const Function *F) const { + return F ? getValueID(F) + 1 : 0; +} + +void ValueEnumerator::EnumerateMetadata(const Function *F, const Metadata *MD) { + EnumerateMetadata(getMetadataFunctionID(F), MD); +} + +void ValueEnumerator::EnumerateFunctionLocalMetadata( + const Function &F, const LocalAsMetadata *Local) { + EnumerateFunctionLocalMetadata(getMetadataFunctionID(&F), Local); +} + +void ValueEnumerator::EnumerateFunctionLocalListMetadata( + const Function &F, const DIArgList *ArgList) { + EnumerateFunctionLocalListMetadata(getMetadataFunctionID(&F), ArgList); +} + +void ValueEnumerator::dropFunctionFromMetadata( + MetadataMapType::value_type &FirstMD) { + SmallVector<const MDNode *, 64> Worklist; + auto push = [&Worklist](MetadataMapType::value_type &MD) { + auto &Entry = MD.second; + + // Nothing to do if this metadata isn't tagged. + if (!Entry.F) + return; + + // Drop the function tag. + Entry.F = 0; + + // If this is has an ID and is an MDNode, then its operands have entries as + // well. We need to drop the function from them too. + if (Entry.ID) + if (auto *N = dyn_cast<MDNode>(MD.first)) + Worklist.push_back(N); + }; + push(FirstMD); + while (!Worklist.empty()) + for (const Metadata *Op : Worklist.pop_back_val()->operands()) { + if (!Op) + continue; + auto MD = MetadataMap.find(Op); + if (MD != MetadataMap.end()) + push(*MD); + } +} + +void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) { + // It's vital for reader efficiency that uniqued subgraphs are done in + // post-order; it's expensive when their operands have forward references. + // If a distinct node is referenced from a uniqued node, it'll be delayed + // until the uniqued subgraph has been completely traversed. + SmallVector<const MDNode *, 32> DelayedDistinctNodes; + + // Start by enumerating MD, and then work through its transitive operands in + // post-order. This requires a depth-first search. + SmallVector<std::pair<const MDNode *, MDNode::op_iterator>, 32> Worklist; + if (const MDNode *N = enumerateMetadataImpl(F, MD)) + Worklist.push_back(std::make_pair(N, N->op_begin())); + + while (!Worklist.empty()) { + const MDNode *N = Worklist.back().first; + + // Enumerate operands until we hit a new node. We need to traverse these + // nodes' operands before visiting the rest of N's operands. + MDNode::op_iterator I = std::find_if( + Worklist.back().second, N->op_end(), + [&](const Metadata *MD) { return enumerateMetadataImpl(F, MD); }); + if (I != N->op_end()) { + auto *Op = cast<MDNode>(*I); + Worklist.back().second = ++I; + + // Delay traversing Op if it's a distinct node and N is uniqued. + if (Op->isDistinct() && !N->isDistinct()) + DelayedDistinctNodes.push_back(Op); + else + Worklist.push_back(std::make_pair(Op, Op->op_begin())); + continue; + } + + // All the operands have been visited. Now assign an ID. + Worklist.pop_back(); + MDs.push_back(N); + MetadataMap[N].ID = MDs.size(); + + // Flush out any delayed distinct nodes; these are all the distinct nodes + // that are leaves in last uniqued subgraph. + if (Worklist.empty() || Worklist.back().first->isDistinct()) { + for (const MDNode *N : DelayedDistinctNodes) + Worklist.push_back(std::make_pair(N, N->op_begin())); + DelayedDistinctNodes.clear(); + } + } +} + +const MDNode *ValueEnumerator::enumerateMetadataImpl(unsigned F, + const Metadata *MD) { + if (!MD) + return nullptr; + + assert( + (isa<MDNode>(MD) || isa<MDString>(MD) || isa<ConstantAsMetadata>(MD)) && + "Invalid metadata kind"); + + auto Insertion = MetadataMap.insert(std::make_pair(MD, MDIndex(F))); + MDIndex &Entry = Insertion.first->second; + if (!Insertion.second) { + // Already mapped. If F doesn't match the function tag, drop it. + if (Entry.hasDifferentFunction(F)) + dropFunctionFromMetadata(*Insertion.first); + return nullptr; + } + + // Don't assign IDs to metadata nodes. + if (auto *N = dyn_cast<MDNode>(MD)) + return N; + + // Save the metadata. + MDs.push_back(MD); + Entry.ID = MDs.size(); + + // Enumerate the constant, if any. + if (auto *C = dyn_cast<ConstantAsMetadata>(MD)) + EnumerateValue(C->getValue()); + + return nullptr; +} + +/// EnumerateFunctionLocalMetadata - Incorporate function-local metadata +/// information reachable from the metadata. +void ValueEnumerator::EnumerateFunctionLocalMetadata( + unsigned F, const LocalAsMetadata *Local) { + assert(F && "Expected a function"); + + // Check to see if it's already in! + MDIndex &Index = MetadataMap[Local]; + if (Index.ID) { + assert(Index.F == F && "Expected the same function"); + return; + } + + MDs.push_back(Local); + Index.F = F; + Index.ID = MDs.size(); + + EnumerateValue(Local->getValue()); +} + +/// EnumerateFunctionLocalListMetadata - Incorporate function-local metadata +/// information reachable from the metadata. +void ValueEnumerator::EnumerateFunctionLocalListMetadata( + unsigned F, const DIArgList *ArgList) { + assert(F && "Expected a function"); + + // Check to see if it's already in! + MDIndex &Index = MetadataMap[ArgList]; + if (Index.ID) { + assert(Index.F == F && "Expected the same function"); + return; + } + + for (ValueAsMetadata *VAM : ArgList->getArgs()) { + if (isa<LocalAsMetadata>(VAM)) { + assert(MetadataMap.count(VAM) && + "LocalAsMetadata should be enumerated before DIArgList"); + assert(MetadataMap[VAM].F == F && + "Expected LocalAsMetadata in the same function"); + } else { + assert(isa<ConstantAsMetadata>(VAM) && + "Expected LocalAsMetadata or ConstantAsMetadata"); + assert(ValueMap.count(VAM->getValue()) && + "Constant should be enumerated beforeDIArgList"); + EnumerateMetadata(F, VAM); + } + } + + MDs.push_back(ArgList); + Index.F = F; + Index.ID = MDs.size(); +} + +static unsigned getMetadataTypeOrder(const Metadata *MD) { + // Strings are emitted in bulk and must come first. + if (isa<MDString>(MD)) + return 0; + + // ConstantAsMetadata doesn't reference anything. We may as well shuffle it + // to the front since we can detect it. + auto *N = dyn_cast<MDNode>(MD); + if (!N) + return 1; + + // The reader is fast forward references for distinct node operands, but slow + // when uniqued operands are unresolved. + return N->isDistinct() ? 2 : 3; +} + +void ValueEnumerator::organizeMetadata() { + assert(MetadataMap.size() == MDs.size() && + "Metadata map and vector out of sync"); + + if (MDs.empty()) + return; + + // Copy out the index information from MetadataMap in order to choose a new + // order. + SmallVector<MDIndex, 64> Order; + Order.reserve(MetadataMap.size()); + for (const Metadata *MD : MDs) + Order.push_back(MetadataMap.lookup(MD)); + + // Partition: + // - by function, then + // - by isa<MDString> + // and then sort by the original/current ID. Since the IDs are guaranteed to + // be unique, the result of std::sort will be deterministic. There's no need + // for std::stable_sort. + llvm::sort(Order, [this](MDIndex LHS, MDIndex RHS) { + return std::make_tuple(LHS.F, getMetadataTypeOrder(LHS.get(MDs)), LHS.ID) < + std::make_tuple(RHS.F, getMetadataTypeOrder(RHS.get(MDs)), RHS.ID); + }); + + // Rebuild MDs, index the metadata ranges for each function in FunctionMDs, + // and fix up MetadataMap. + std::vector<const Metadata *> OldMDs; + MDs.swap(OldMDs); + MDs.reserve(OldMDs.size()); + for (unsigned I = 0, E = Order.size(); I != E && !Order[I].F; ++I) { + auto *MD = Order[I].get(OldMDs); + MDs.push_back(MD); + MetadataMap[MD].ID = I + 1; + if (isa<MDString>(MD)) + ++NumMDStrings; + } + + // Return early if there's nothing for the functions. + if (MDs.size() == Order.size()) + return; + + // Build the function metadata ranges. + MDRange R; + FunctionMDs.reserve(OldMDs.size()); + unsigned PrevF = 0; + for (unsigned I = MDs.size(), E = Order.size(), ID = MDs.size(); I != E; + ++I) { + unsigned F = Order[I].F; + if (!PrevF) { + PrevF = F; + } else if (PrevF != F) { + R.Last = FunctionMDs.size(); + std::swap(R, FunctionMDInfo[PrevF]); + R.First = FunctionMDs.size(); + + ID = MDs.size(); + PrevF = F; + } + + auto *MD = Order[I].get(OldMDs); + FunctionMDs.push_back(MD); + MetadataMap[MD].ID = ++ID; + if (isa<MDString>(MD)) + ++R.NumStrings; + } + R.Last = FunctionMDs.size(); + FunctionMDInfo[PrevF] = R; +} + +void ValueEnumerator::incorporateFunctionMetadata(const Function &F) { + NumModuleMDs = MDs.size(); + + auto R = FunctionMDInfo.lookup(getValueID(&F) + 1); + NumMDStrings = R.NumStrings; + MDs.insert(MDs.end(), FunctionMDs.begin() + R.First, + FunctionMDs.begin() + R.Last); +} + +void ValueEnumerator::EnumerateValue(const Value *V) { + assert(!V->getType()->isVoidTy() && "Can't insert void values!"); + assert(!isa<MetadataAsValue>(V) && "EnumerateValue doesn't handle Metadata!"); + + // Check to see if it's already in! + unsigned &ValueID = ValueMap[V]; + if (ValueID) { + // Increment use count. + Values[ValueID - 1].second++; + return; + } + + if (auto *GO = dyn_cast<GlobalObject>(V)) + if (const Comdat *C = GO->getComdat()) + Comdats.insert(C); + + // Enumerate the type of this value. + EnumerateType(V->getType()); + + if (const Constant *C = dyn_cast<Constant>(V)) { + if (isa<GlobalValue>(C)) { + // Initializers for globals are handled explicitly elsewhere. + } else if (C->getNumOperands()) { + // If a constant has operands, enumerate them. This makes sure that if a + // constant has uses (for example an array of const ints), that they are + // inserted also. + + // We prefer to enumerate them with values before we enumerate the user + // itself. This makes it more likely that we can avoid forward references + // in the reader. We know that there can be no cycles in the constants + // graph that don't go through a global variable. + for (User::const_op_iterator I = C->op_begin(), E = C->op_end(); I != E; + ++I) + if (!isa<BasicBlock>(*I)) // Don't enumerate BB operand to BlockAddress. + EnumerateValue(*I); + if (auto *CE = dyn_cast<ConstantExpr>(C)) { + if (CE->getOpcode() == Instruction::ShuffleVector) + EnumerateValue(CE->getShuffleMaskForBitcode()); + if (auto *GEP = dyn_cast<GEPOperator>(CE)) + EnumerateType(GEP->getSourceElementType()); + } + + // Finally, add the value. Doing this could make the ValueID reference be + // dangling, don't reuse it. + Values.push_back(std::make_pair(V, 1U)); + ValueMap[V] = Values.size(); + return; + } + } + + // Add the value. + Values.push_back(std::make_pair(V, 1U)); + ValueID = Values.size(); +} + +void ValueEnumerator::EnumerateType(Type *Ty) { + unsigned *TypeID = &TypeMap[Ty]; + + // We've already seen this type. + if (*TypeID) + return; + + // If it is a non-anonymous struct, mark the type as being visited so that we + // don't recursively visit it. This is safe because we allow forward + // references of these in the bitcode reader. + if (StructType *STy = dyn_cast<StructType>(Ty)) + if (!STy->isLiteral()) + *TypeID = ~0U; + + // Enumerate all of the subtypes before we enumerate this type. This ensures + // that the type will be enumerated in an order that can be directly built. + for (Type *SubTy : Ty->subtypes()) + EnumerateType(SubTy); + + // Refresh the TypeID pointer in case the table rehashed. + TypeID = &TypeMap[Ty]; + + // Check to see if we got the pointer another way. This can happen when + // enumerating recursive types that hit the base case deeper than they start. + // + // If this is actually a struct that we are treating as forward ref'able, + // then emit the definition now that all of its contents are available. + if (*TypeID && *TypeID != ~0U) + return; + + // Add this type now that its contents are all happily enumerated. + Types.push_back(Ty); + + *TypeID = Types.size(); +} + +// Enumerate the types for the specified value. If the value is a constant, +// walk through it, enumerating the types of the constant. +void ValueEnumerator::EnumerateOperandType(const Value *V) { + EnumerateType(V->getType()); + + assert(!isa<MetadataAsValue>(V) && "Unexpected metadata operand"); + + const Constant *C = dyn_cast<Constant>(V); + if (!C) + return; + + // If this constant is already enumerated, ignore it, we know its type must + // be enumerated. + if (ValueMap.count(C)) + return; + + // This constant may have operands, make sure to enumerate the types in + // them. + for (const Value *Op : C->operands()) { + // Don't enumerate basic blocks here, this happens as operands to + // blockaddress. + if (isa<BasicBlock>(Op)) + continue; + + EnumerateOperandType(Op); + } + if (auto *CE = dyn_cast<ConstantExpr>(C)) { + if (CE->getOpcode() == Instruction::ShuffleVector) + EnumerateOperandType(CE->getShuffleMaskForBitcode()); + if (CE->getOpcode() == Instruction::GetElementPtr) + EnumerateType(cast<GEPOperator>(CE)->getSourceElementType()); + } +} + +void ValueEnumerator::EnumerateAttributes(AttributeList PAL) { + if (PAL.isEmpty()) + return; // null is always 0. + + // Do a lookup. + unsigned &Entry = AttributeListMap[PAL]; + if (Entry == 0) { + // Never saw this before, add it. + AttributeLists.push_back(PAL); + Entry = AttributeLists.size(); + } + + // Do lookups for all attribute groups. + for (unsigned i : PAL.indexes()) { + AttributeSet AS = PAL.getAttributes(i); + if (!AS.hasAttributes()) + continue; + IndexAndAttrSet Pair = {i, AS}; + unsigned &Entry = AttributeGroupMap[Pair]; + if (Entry == 0) { + AttributeGroups.push_back(Pair); + Entry = AttributeGroups.size(); + + for (Attribute Attr : AS) { + if (Attr.isTypeAttribute()) + EnumerateType(Attr.getValueAsType()); + } + } + } +} + +void ValueEnumerator::incorporateFunction(const Function &F) { + InstructionCount = 0; + NumModuleValues = Values.size(); + + // Add global metadata to the function block. This doesn't include + // LocalAsMetadata. + incorporateFunctionMetadata(F); + + // Adding function arguments to the value table. + for (const auto &I : F.args()) { + EnumerateValue(&I); + if (I.hasAttribute(Attribute::ByVal)) + EnumerateType(I.getParamByValType()); + else if (I.hasAttribute(Attribute::StructRet)) + EnumerateType(I.getParamStructRetType()); + else if (I.hasAttribute(Attribute::ByRef)) + EnumerateType(I.getParamByRefType()); + } + FirstFuncConstantID = Values.size(); + + // Add all function-level constants to the value table. + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + for (const Use &OI : I.operands()) { + if ((isa<Constant>(OI) && !isa<GlobalValue>(OI)) || isa<InlineAsm>(OI)) + EnumerateValue(OI); + } + if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I)) + EnumerateValue(SVI->getShuffleMaskForBitcode()); + } + BasicBlocks.push_back(&BB); + ValueMap[&BB] = BasicBlocks.size(); + } + + // Add the function's parameter attributes so they are available for use in + // the function's instruction. + EnumerateAttributes(F.getAttributes()); + + FirstInstID = Values.size(); + + SmallVector<LocalAsMetadata *, 8> FnLocalMDVector; + SmallVector<DIArgList *, 8> ArgListMDVector; + // Add all of the instructions. + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + for (const Use &OI : I.operands()) { + if (auto *MD = dyn_cast<MetadataAsValue>(&OI)) { + if (auto *Local = dyn_cast<LocalAsMetadata>(MD->getMetadata())) { + // Enumerate metadata after the instructions they might refer to. + FnLocalMDVector.push_back(Local); + } else if (auto *ArgList = dyn_cast<DIArgList>(MD->getMetadata())) { + ArgListMDVector.push_back(ArgList); + for (ValueAsMetadata *VMD : ArgList->getArgs()) { + if (auto *Local = dyn_cast<LocalAsMetadata>(VMD)) { + // Enumerate metadata after the instructions they might refer + // to. + FnLocalMDVector.push_back(Local); + } + } + } + } + } + + if (!I.getType()->isVoidTy()) + EnumerateValue(&I); + } + } + + // Add all of the function-local metadata. + for (unsigned i = 0, e = FnLocalMDVector.size(); i != e; ++i) { + // At this point, every local values have been incorporated, we shouldn't + // have a metadata operand that references a value that hasn't been seen. + assert(ValueMap.count(FnLocalMDVector[i]->getValue()) && + "Missing value for metadata operand"); + EnumerateFunctionLocalMetadata(F, FnLocalMDVector[i]); + } + // DIArgList entries must come after function-local metadata, as it is not + // possible to forward-reference them. + for (const DIArgList *ArgList : ArgListMDVector) + EnumerateFunctionLocalListMetadata(F, ArgList); +} + +void ValueEnumerator::purgeFunction() { + /// Remove purged values from the ValueMap. + for (unsigned i = NumModuleValues, e = Values.size(); i != e; ++i) + ValueMap.erase(Values[i].first); + for (unsigned i = NumModuleMDs, e = MDs.size(); i != e; ++i) + MetadataMap.erase(MDs[i]); + for (const BasicBlock *BB : BasicBlocks) + ValueMap.erase(BB); + + Values.resize(NumModuleValues); + MDs.resize(NumModuleMDs); + BasicBlocks.clear(); + NumMDStrings = 0; +} + +static void IncorporateFunctionInfoGlobalBBIDs( + const Function *F, DenseMap<const BasicBlock *, unsigned> &IDMap) { + unsigned Counter = 0; + for (const BasicBlock &BB : *F) + IDMap[&BB] = ++Counter; +} + +/// getGlobalBasicBlockID - This returns the function-specific ID for the +/// specified basic block. This is relatively expensive information, so it +/// should only be used by rare constructs such as address-of-label. +unsigned ValueEnumerator::getGlobalBasicBlockID(const BasicBlock *BB) const { + unsigned &Idx = GlobalBasicBlockIDs[BB]; + if (Idx != 0) + return Idx - 1; + + IncorporateFunctionInfoGlobalBBIDs(BB->getParent(), GlobalBasicBlockIDs); + return getGlobalBasicBlockID(BB); +} + +uint64_t ValueEnumerator::computeBitsRequiredForTypeIndicies() const { + return Log2_32_Ceil(getTypes().size() + 1); +} diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h new file mode 100644 index 000000000000..6cf339b7a5cd --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILValueEnumerator.h @@ -0,0 +1,308 @@ +//===- DirectX/DXILWriter/ValueEnumerator.h - Number values -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This class gives values and types Unique ID's. +// Forked from lib/Bitcode/Writer +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DXILWRITER_VALUEENUMERATOR_H +#define LLVM_DXILWRITER_VALUEENUMERATOR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/UniqueVector.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/UseListOrder.h" +#include <cassert> +#include <cstdint> +#include <utility> +#include <vector> + +namespace llvm { + +class BasicBlock; +class Comdat; +class DIArgList; +class Function; +class Instruction; +class LocalAsMetadata; +class MDNode; +class Metadata; +class Module; +class NamedMDNode; +class raw_ostream; +class Type; +class Value; +class ValueSymbolTable; + +namespace dxil { + +class ValueEnumerator { +public: + using TypeList = std::vector<Type *>; + + // For each value, we remember its Value* and occurrence frequency. + using ValueList = std::vector<std::pair<const Value *, unsigned>>; + + /// Attribute groups as encoded in bitcode are almost AttributeSets, but they + /// include the AttributeList index, so we have to track that in our map. + using IndexAndAttrSet = std::pair<unsigned, AttributeSet>; + + UseListOrderStack UseListOrders; + +private: + using TypeMapType = DenseMap<Type *, unsigned>; + TypeMapType TypeMap; + TypeList Types; + + using ValueMapType = DenseMap<const Value *, unsigned>; + ValueMapType ValueMap; + ValueList Values; + + using ComdatSetType = UniqueVector<const Comdat *>; + ComdatSetType Comdats; + + std::vector<const Metadata *> MDs; + std::vector<const Metadata *> FunctionMDs; + + /// Index of information about a piece of metadata. + struct MDIndex { + unsigned F = 0; ///< The ID of the function for this metadata, if any. + unsigned ID = 0; ///< The implicit ID of this metadata in bitcode. + + MDIndex() = default; + explicit MDIndex(unsigned F) : F(F) {} + + /// Check if this has a function tag, and it's different from NewF. + bool hasDifferentFunction(unsigned NewF) const { return F && F != NewF; } + + /// Fetch the MD this references out of the given metadata array. + const Metadata *get(ArrayRef<const Metadata *> MDs) const { + assert(ID && "Expected non-zero ID"); + assert(ID <= MDs.size() && "Expected valid ID"); + return MDs[ID - 1]; + } + }; + + using MetadataMapType = DenseMap<const Metadata *, MDIndex>; + MetadataMapType MetadataMap; + + /// Range of metadata IDs, as a half-open range. + struct MDRange { + unsigned First = 0; + unsigned Last = 0; + + /// Number of strings in the prefix of the metadata range. + unsigned NumStrings = 0; + + MDRange() = default; + explicit MDRange(unsigned First) : First(First) {} + }; + SmallDenseMap<unsigned, MDRange, 1> FunctionMDInfo; + + using AttributeGroupMapType = DenseMap<IndexAndAttrSet, unsigned>; + AttributeGroupMapType AttributeGroupMap; + std::vector<IndexAndAttrSet> AttributeGroups; + + using AttributeListMapType = DenseMap<AttributeList, unsigned>; + AttributeListMapType AttributeListMap; + std::vector<AttributeList> AttributeLists; + + /// GlobalBasicBlockIDs - This map memoizes the basic block ID's referenced by + /// the "getGlobalBasicBlockID" method. + mutable DenseMap<const BasicBlock *, unsigned> GlobalBasicBlockIDs; + + using InstructionMapType = DenseMap<const Instruction *, unsigned>; + InstructionMapType InstructionMap; + unsigned InstructionCount; + + /// BasicBlocks - This contains all the basic blocks for the currently + /// incorporated function. Their reverse mapping is stored in ValueMap. + std::vector<const BasicBlock *> BasicBlocks; + + /// When a function is incorporated, this is the size of the Values list + /// before incorporation. + unsigned NumModuleValues; + + /// When a function is incorporated, this is the size of the Metadatas list + /// before incorporation. + unsigned NumModuleMDs = 0; + unsigned NumMDStrings = 0; + + unsigned FirstFuncConstantID; + unsigned FirstInstID; + +public: + ValueEnumerator(const Module &M, Type *PrefixType); + ValueEnumerator(const ValueEnumerator &) = delete; + ValueEnumerator &operator=(const ValueEnumerator &) = delete; + + void dump() const; + void print(raw_ostream &OS, const ValueMapType &Map, const char *Name) const; + void print(raw_ostream &OS, const MetadataMapType &Map, + const char *Name) const; + + unsigned getValueID(const Value *V) const; + + unsigned getMetadataID(const Metadata *MD) const { + auto ID = getMetadataOrNullID(MD); + assert(ID != 0 && "Metadata not in slotcalculator!"); + return ID - 1; + } + + unsigned getMetadataOrNullID(const Metadata *MD) const { + return MetadataMap.lookup(MD).ID; + } + + unsigned numMDs() const { return MDs.size(); } + + unsigned getTypeID(Type *T) const { + TypeMapType::const_iterator I = TypeMap.find(T); + assert(I != TypeMap.end() && "Type not in ValueEnumerator!"); + return I->second - 1; + } + + unsigned getInstructionID(const Instruction *I) const; + void setInstructionID(const Instruction *I); + + unsigned getAttributeListID(AttributeList PAL) const { + if (PAL.isEmpty()) + return 0; // Null maps to zero. + AttributeListMapType::const_iterator I = AttributeListMap.find(PAL); + assert(I != AttributeListMap.end() && "Attribute not in ValueEnumerator!"); + return I->second; + } + + unsigned getAttributeGroupID(IndexAndAttrSet Group) const { + if (!Group.second.hasAttributes()) + return 0; // Null maps to zero. + AttributeGroupMapType::const_iterator I = AttributeGroupMap.find(Group); + assert(I != AttributeGroupMap.end() && "Attribute not in ValueEnumerator!"); + return I->second; + } + + /// getFunctionConstantRange - Return the range of values that corresponds to + /// function-local constants. + void getFunctionConstantRange(unsigned &Start, unsigned &End) const { + Start = FirstFuncConstantID; + End = FirstInstID; + } + + const ValueList &getValues() const { return Values; } + + /// Check whether the current block has any metadata to emit. + bool hasMDs() const { return NumModuleMDs < MDs.size(); } + + /// Get the MDString metadata for this block. + ArrayRef<const Metadata *> getMDStrings() const { + return makeArrayRef(MDs).slice(NumModuleMDs, NumMDStrings); + } + + /// Get the non-MDString metadata for this block. + ArrayRef<const Metadata *> getNonMDStrings() const { + return makeArrayRef(MDs).slice(NumModuleMDs).slice(NumMDStrings); + } + + const TypeList &getTypes() const { return Types; } + + const std::vector<const BasicBlock *> &getBasicBlocks() const { + return BasicBlocks; + } + + const std::vector<AttributeList> &getAttributeLists() const { + return AttributeLists; + } + + const std::vector<IndexAndAttrSet> &getAttributeGroups() const { + return AttributeGroups; + } + + const ComdatSetType &getComdats() const { return Comdats; } + unsigned getComdatID(const Comdat *C) const; + + /// getGlobalBasicBlockID - This returns the function-specific ID for the + /// specified basic block. This is relatively expensive information, so it + /// should only be used by rare constructs such as address-of-label. + unsigned getGlobalBasicBlockID(const BasicBlock *BB) const; + + /// incorporateFunction/purgeFunction - If you'd like to deal with a function, + /// use these two methods to get its data into the ValueEnumerator! + void incorporateFunction(const Function &F); + + void purgeFunction(); + uint64_t computeBitsRequiredForTypeIndicies() const; + + void EnumerateType(Type *T); + +private: + + /// Reorder the reachable metadata. + /// + /// This is not just an optimization, but is mandatory for emitting MDString + /// correctly. + void organizeMetadata(); + + /// Drop the function tag from the transitive operands of the given node. + void dropFunctionFromMetadata(MetadataMapType::value_type &FirstMD); + + /// Incorporate the function metadata. + /// + /// This should be called before enumerating LocalAsMetadata for the + /// function. + void incorporateFunctionMetadata(const Function &F); + + /// Enumerate a single instance of metadata with the given function tag. + /// + /// If \c MD has already been enumerated, check that \c F matches its + /// function tag. If not, call \a dropFunctionFromMetadata(). + /// + /// Otherwise, mark \c MD as visited. Assign it an ID, or just return it if + /// it's an \a MDNode. + const MDNode *enumerateMetadataImpl(unsigned F, const Metadata *MD); + + unsigned getMetadataFunctionID(const Function *F) const; + + /// Enumerate reachable metadata in (almost) post-order. + /// + /// Enumerate all the metadata reachable from MD. We want to minimize the + /// cost of reading bitcode records, and so the primary consideration is that + /// operands of uniqued nodes are resolved before the nodes are read. This + /// avoids re-uniquing them on the context and factors away RAUW support. + /// + /// This algorithm guarantees that subgraphs of uniqued nodes are in + /// post-order. Distinct subgraphs reachable only from a single uniqued node + /// will be in post-order. + /// + /// \note The relative order of a distinct and uniqued node is irrelevant. + /// \a organizeMetadata() will later partition distinct nodes ahead of + /// uniqued ones. + ///{ + void EnumerateMetadata(const Function *F, const Metadata *MD); + void EnumerateMetadata(unsigned F, const Metadata *MD); + ///} + + void EnumerateFunctionLocalMetadata(const Function &F, + const LocalAsMetadata *Local); + void EnumerateFunctionLocalMetadata(unsigned F, const LocalAsMetadata *Local); + void EnumerateFunctionLocalListMetadata(const Function &F, + const DIArgList *ArgList); + void EnumerateFunctionLocalListMetadata(unsigned F, const DIArgList *Arglist); + void EnumerateNamedMDNode(const NamedMDNode *NMD); + void EnumerateValue(const Value *V); + void EnumerateOperandType(const Value *V); + void EnumerateAttributes(AttributeList PAL); + + void EnumerateValueSymbolTable(const ValueSymbolTable &ST); + void EnumerateNamedMetadata(const Module &M); +}; + +} // end namespace dxil +} // end namespace llvm + +#endif // LLVM_DXILWRITER_VALUEENUMERATOR_H diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp new file mode 100644 index 000000000000..c1f9f4aec672 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp @@ -0,0 +1,100 @@ +//===- DXILWriterPass.cpp - Bitcode writing pass --------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// DXILWriterPass implementation. +// +//===----------------------------------------------------------------------===// + +#include "DXILWriterPass.h" +#include "DXILBitcodeWriter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/ModuleSummaryAnalysis.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; +using namespace llvm::dxil; + +namespace { +class WriteDXILPass : public llvm::ModulePass { + raw_ostream &OS; // raw_ostream to print on + +public: + static char ID; // Pass identification, replacement for typeid + WriteDXILPass() : ModulePass(ID), OS(dbgs()) { + initializeWriteDXILPassPass(*PassRegistry::getPassRegistry()); + } + + explicit WriteDXILPass(raw_ostream &o) : ModulePass(ID), OS(o) { + initializeWriteDXILPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "Bitcode Writer"; } + + bool runOnModule(Module &M) override { + WriteDXILToFile(M, OS); + return false; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +class EmbedDXILPass : public llvm::ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + EmbedDXILPass() : ModulePass(ID) { + initializeEmbedDXILPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "DXIL Embedder"; } + + bool runOnModule(Module &M) override { + std::string Data; + llvm::raw_string_ostream OS(Data); + WriteDXILToFile(M, OS); + + Constant *ModuleConstant = + ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data)); + auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true, + GlobalValue::PrivateLinkage, + ModuleConstant, "dx.dxil"); + GV->setSection("DXIL"); + GV->setAlignment(Align(4)); + appendToCompilerUsed(M, {GV}); + return true; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; +} // namespace + +char WriteDXILPass::ID = 0; +INITIALIZE_PASS_BEGIN(WriteDXILPass, "write-bitcode", "Write Bitcode", false, + true) +INITIALIZE_PASS_DEPENDENCY(ModuleSummaryIndexWrapperPass) +INITIALIZE_PASS_END(WriteDXILPass, "write-bitcode", "Write Bitcode", false, + true) + +ModulePass *llvm::createDXILWriterPass(raw_ostream &Str) { + return new WriteDXILPass(Str); +} + +char EmbedDXILPass::ID = 0; +INITIALIZE_PASS(EmbedDXILPass, "dxil-embed", "Embed DXIL", false, true) + +ModulePass *llvm::createDXILEmbedderPass() { return new EmbedDXILPass(); } diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.h b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.h new file mode 100644 index 000000000000..2c9c12178677 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.h @@ -0,0 +1,37 @@ +//===-- DXILWriterPass.h - Bitcode writing pass --------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides a bitcode writing pass. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BITCODE_DXILWriterPass_H +#define LLVM_BITCODE_DXILWriterPass_H + +#include "DirectX.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { +class Module; +class raw_ostream; + +/// Create and return a pass that writes the module to the specified +/// ostream. Note that this pass is designed for use with the legacy pass +/// manager. +ModulePass *createDXILWriterPass(raw_ostream &Str); + +/// Create and return a pass that writes the module to a global variable in the +/// module for later emission in the MCStreamer. Note that this pass is designed +/// for use with the legacy pass manager because it is run in CodeGen only. +ModulePass *createDXILEmbedderPass(); + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h new file mode 100644 index 000000000000..3883e4ba4621 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectX.h @@ -0,0 +1,43 @@ +//===- DirectXTargetMachine.h - DirectX Target Implementation ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_DIRECTX_DIRECTX_H +#define LLVM_LIB_TARGET_DIRECTX_DIRECTX_H + +namespace llvm { +class ModulePass; +class PassRegistry; + +/// Initializer for dxil writer pass +void initializeWriteDXILPassPass(PassRegistry &); + +/// Initializer for dxil embedder pass +void initializeEmbedDXILPassPass(PassRegistry &); + +/// Initializer for DXIL-prepare +void initializeDXILPrepareModulePass(PassRegistry &); + +/// Pass to convert modules into DXIL-compatable modules +ModulePass *createDXILPrepareModulePass(); + +/// Initializer for DXILOpLowering +void initializeDXILOpLoweringLegacyPass(PassRegistry &); + +/// Pass to lowering LLVM intrinsic call to DXIL op function call. +ModulePass *createDXILOpLoweringLegacyPass(); + +/// Initializer for DXILTranslateMetadata. +void initializeDXILTranslateMetadataPass(PassRegistry &); + +/// Pass to emit metadata for DXIL. +ModulePass *createDXILTranslateMetadataPass(); +} // namespace llvm + +#endif // LLVM_LIB_TARGET_DIRECTX_DIRECTX_H diff --git a/llvm/lib/Target/DirectX/DirectX.td b/llvm/lib/Target/DirectX/DirectX.td new file mode 100644 index 000000000000..4d1d45b84a68 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectX.td @@ -0,0 +1,54 @@ +//- DirectX.td - Describe the DirectX Target Machine ----------*- tablegen -*-// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This is a target description file for the DirectX target +/// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces which we are implementing +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" +include "DXILStubs.td" + +//===----------------------------------------------------------------------===// +// DirectX Subtarget features. +//===----------------------------------------------------------------------===// + +def DirectXInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// DirectX Processors supported. +//===----------------------------------------------------------------------===// + +def : ProcessorModel<"generic", NoSchedModel, []>; + + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def DirectXAsmParser : AsmParser { + // The physical register names are not in the binary format or asm text + let ShouldEmitMatchRegisterName = 0; +} + +def DirectXAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + int PassSubtarget = 0; + int Variant = 0; + bit isMCAsmWriter = 1; +} + +def DirectX : Target { + let InstructionSet = DirectXInstrInfo; + let AssemblyParsers = [DirectXAsmParser]; + let AssemblyWriters = [DirectXAsmWriter]; +} diff --git a/llvm/lib/Target/DirectX/DirectXAsmPrinter.cpp b/llvm/lib/Target/DirectX/DirectXAsmPrinter.cpp new file mode 100644 index 000000000000..cea3283f6756 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXAsmPrinter.cpp @@ -0,0 +1,57 @@ +//===-- DirectXAsmPrinter.cpp - DirectX assembly writer --------*- C++ -*--===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains AsmPrinters for the DirectX backend. +// +//===----------------------------------------------------------------------===// + +#include "TargetInfo/DirectXTargetInfo.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Target/TargetLoweringObjectFile.h" + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { + +// The DXILAsmPrinter is mostly a stub because DXIL is just LLVM bitcode which +// gets embedded into a DXContainer file. +class DXILAsmPrinter : public AsmPrinter { +public: + explicit DXILAsmPrinter(TargetMachine &TM, + std::unique_ptr<MCStreamer> Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + + StringRef getPassName() const override { return "DXIL Assembly Printer"; } + void emitGlobalVariable(const GlobalVariable *GV) override; + bool runOnMachineFunction(MachineFunction &MF) override { return false; } +}; +} // namespace + +void DXILAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { + // If there is no initializer or the section is implicit, do nothing + if (!GV->hasInitializer() || GV->hasImplicitSection()) + return; + // Skip the LLVM metadata + if (GV->getSection() == "llvm.metadata") + return; + SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM); + MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, TM); + OutStreamer->switchSection(TheSection); + emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXAsmPrinter() { + RegisterAsmPrinter<DXILAsmPrinter> X(getTheDirectXTarget()); +} diff --git a/llvm/lib/Target/DirectX/DirectXFrameLowering.h b/llvm/lib/Target/DirectX/DirectXFrameLowering.h new file mode 100644 index 000000000000..76a1450054be --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXFrameLowering.h @@ -0,0 +1,35 @@ +//===-- DirectXFrameLowering.h - Frame lowering for DirectX --*- C++ ---*--===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This class implements DirectX-specific bits of TargetFrameLowering class. +// This is just a stub because the current DXIL backend does not actually lower +// through the MC layer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXFRAMELOWERING_H +#define LLVM_DIRECTX_DIRECTXFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/Support/Alignment.h" + +namespace llvm { +class DirectXSubtarget; + +class DirectXFrameLowering : public TargetFrameLowering { +public: + explicit DirectXFrameLowering(const DirectXSubtarget &STI) + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(8), 0) {} + + void emitPrologue(MachineFunction &, MachineBasicBlock &) const override {} + void emitEpilogue(MachineFunction &, MachineBasicBlock &) const override {} + + bool hasFP(const MachineFunction &) const override { return false; } +}; +} // namespace llvm +#endif // LLVM_DIRECTX_DIRECTXFRAMELOWERING_H diff --git a/llvm/lib/Target/DirectX/DirectXInstrInfo.cpp b/llvm/lib/Target/DirectX/DirectXInstrInfo.cpp new file mode 100644 index 000000000000..07b68648f16c --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXInstrInfo.cpp @@ -0,0 +1,20 @@ +//===-- DirectXInstrInfo.cpp - InstrInfo for DirectX -*- C++ ------------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the DirectX specific subclass of TargetInstrInfo. +// +//===----------------------------------------------------------------------===// + +#include "DirectXInstrInfo.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "DirectXGenInstrInfo.inc" + +using namespace llvm; + +DirectXInstrInfo::~DirectXInstrInfo() {} diff --git a/llvm/lib/Target/DirectX/DirectXInstrInfo.h b/llvm/lib/Target/DirectX/DirectXInstrInfo.h new file mode 100644 index 000000000000..4fe79ee547fe --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXInstrInfo.h @@ -0,0 +1,30 @@ +//===-- DirectXInstrInfo.h - Define InstrInfo for DirectX -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the DirectX specific subclass of TargetInstrInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXINSTRINFO_H +#define LLVM_DIRECTX_DIRECTXINSTRINFO_H + +#include "DirectXRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "DirectXGenInstrInfo.inc" + +namespace llvm { +struct DirectXInstrInfo : public DirectXGenInstrInfo { + explicit DirectXInstrInfo() : DirectXGenInstrInfo() {} + + ~DirectXInstrInfo() override; +}; +} // namespace llvm + +#endif // LLVM_DIRECTX_DIRECTXINSTRINFO_H diff --git a/llvm/lib/Target/DirectX/DirectXRegisterInfo.cpp b/llvm/lib/Target/DirectX/DirectXRegisterInfo.cpp new file mode 100644 index 000000000000..c54b494f3730 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXRegisterInfo.cpp @@ -0,0 +1,24 @@ +//===-- DirectXRegisterInfo.cpp - RegisterInfo for DirectX -*- C++ ------*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the DirectX specific subclass of TargetRegisterInfo. +// +//===----------------------------------------------------------------------===// + +#include "DirectXRegisterInfo.h" +#include "DirectXFrameLowering.h" +#include "MCTargetDesc/DirectXMCTargetDesc.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" + +#define GET_REGINFO_TARGET_DESC +#include "DirectXGenRegisterInfo.inc" + +using namespace llvm; + +DirectXRegisterInfo::~DirectXRegisterInfo() {} diff --git a/llvm/lib/Target/DirectX/DirectXRegisterInfo.h b/llvm/lib/Target/DirectX/DirectXRegisterInfo.h new file mode 100644 index 000000000000..023c5c3ef337 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXRegisterInfo.h @@ -0,0 +1,28 @@ +//===-- DirectXRegisterInfo.h - Define RegisterInfo for DirectX -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the DirectX specific subclass of TargetRegisterInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DXILREGISTERINFO_H +#define LLVM_DIRECTX_DXILREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "DirectXGenRegisterInfo.inc" + +namespace llvm { +struct DirectXRegisterInfo : public DirectXGenRegisterInfo { + DirectXRegisterInfo() : DirectXGenRegisterInfo(0) {} + ~DirectXRegisterInfo(); +}; +} // namespace llvm + +#endif // LLVM_DIRECTX_DXILREGISTERINFO_H diff --git a/llvm/lib/Target/DirectX/DirectXSubtarget.cpp b/llvm/lib/Target/DirectX/DirectXSubtarget.cpp new file mode 100644 index 000000000000..526b7d29fb13 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXSubtarget.cpp @@ -0,0 +1,29 @@ +//===-- DirectXSubtarget.cpp - DirectX Subtarget Information --------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the DirectX-specific subclass of TargetSubtarget. +/// +//===----------------------------------------------------------------------===// + +#include "DirectXSubtarget.h" +#include "DirectXTargetLowering.h" + +using namespace llvm; + +#define DEBUG_TYPE "directx-subtarget" + +#define GET_SUBTARGETINFO_CTOR +#define GET_SUBTARGETINFO_TARGET_DESC +#include "DirectXGenSubtargetInfo.inc" + +DirectXSubtarget::DirectXSubtarget(const Triple &TT, StringRef CPU, + StringRef FS, const DirectXTargetMachine &TM) + : DirectXGenSubtargetInfo(TT, CPU, CPU, FS), FL(*this), TL(TM, *this) {} + +void DirectXSubtarget::anchor() {} diff --git a/llvm/lib/Target/DirectX/DirectXSubtarget.h b/llvm/lib/Target/DirectX/DirectXSubtarget.h new file mode 100644 index 000000000000..464d05a0e1ff --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXSubtarget.h @@ -0,0 +1,56 @@ +//===-- DirectXSubtarget.h - Define Subtarget for DirectX -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the DirectX specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXSUBTARGET_H +#define LLVM_DIRECTX_DIRECTXSUBTARGET_H + +#include "DirectXFrameLowering.h" +#include "DirectXInstrInfo.h" +#include "DirectXTargetLowering.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "DirectXGenSubtargetInfo.inc" + +namespace llvm { + +class DirectXTargetMachine; + +class DirectXSubtarget : public DirectXGenSubtargetInfo { + DirectXFrameLowering FL; + DirectXTargetLowering TL; + DirectXInstrInfo InstrInfo; + + virtual void anchor(); // virtual anchor method + +public: + DirectXSubtarget(const Triple &TT, StringRef CPU, StringRef FS, + const DirectXTargetMachine &TM); + + /// Parses a subtarget feature string, setting appropriate options. + /// \note Definition of function is auto generated by `tblgen`. + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + + const DirectXTargetLowering *getTargetLowering() const override { + return &TL; + } + + const DirectXFrameLowering *getFrameLowering() const override { return &FL; } + + const DirectXInstrInfo *getInstrInfo() const override { return &InstrInfo; } +}; + +} // end namespace llvm + +#endif // LLVM_DIRECTX_DIRECTXSUBTARGET_H diff --git a/llvm/lib/Target/DirectX/DirectXTargetLowering.h b/llvm/lib/Target/DirectX/DirectXTargetLowering.h new file mode 100644 index 000000000000..dc19894ab165 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXTargetLowering.h @@ -0,0 +1,31 @@ +//===-- DirectXTargetLowering.h - Define DX TargetLowering -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the DirectX specific subclass of TargetLowering. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXTARGETLOWERING_H +#define LLVM_DIRECTX_DIRECTXTARGETLOWERING_H + +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { + +class DirectXSubtarget; +class DirectXTargetMachine; + +class DirectXTargetLowering : public TargetLowering { +public: + explicit DirectXTargetLowering(const DirectXTargetMachine &TM, + const DirectXSubtarget &STI); +}; + +} // end namespace llvm + +#endif // LLVM_DIRECTX_DIRECTXTARGETLOWERING_H diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp new file mode 100644 index 000000000000..44bef80ea6fb --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -0,0 +1,144 @@ +//===- DirectXTargetMachine.cpp - DirectX Target Implementation -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains DirectX target initializer. +/// +//===----------------------------------------------------------------------===// + +#include "DirectXTargetMachine.h" +#include "DXILWriter/DXILWriterPass.h" +#include "DirectX.h" +#include "DirectXSubtarget.h" +#include "DirectXTargetTransformInfo.h" +#include "TargetInfo/DirectXTargetInfo.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/MC/MCSectionDXContainer.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetLoweringObjectFile.h" + +using namespace llvm; + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() { + RegisterTargetMachine<DirectXTargetMachine> X(getTheDirectXTarget()); + auto *PR = PassRegistry::getPassRegistry(); + initializeDXILPrepareModulePass(*PR); + initializeEmbedDXILPassPass(*PR); + initializeDXILOpLoweringLegacyPass(*PR); + initializeDXILTranslateMetadataPass(*PR); +} + +class DXILTargetObjectFile : public TargetLoweringObjectFile { +public: + DXILTargetObjectFile() = default; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override { + return getContext().getDXContainerSection(GO->getSection(), Kind); + } + +protected: + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override { + llvm_unreachable("Not supported!"); + } +}; + +class DirectXPassConfig : public TargetPassConfig { +public: + DirectXPassConfig(DirectXTargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + DirectXTargetMachine &getDirectXTargetMachine() const { + return getTM<DirectXTargetMachine>(); + } + + FunctionPass *createTargetRegisterAllocator(bool) override { return nullptr; } +}; + +DirectXTargetMachine::DirectXTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional<Reloc::Model> RM, + Optional<CodeModel::Model> CM, + CodeGenOpt::Level OL, bool JIT) + : LLVMTargetMachine(T, + "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", + TT, CPU, FS, Options, Reloc::Static, CodeModel::Small, + OL), + TLOF(std::make_unique<DXILTargetObjectFile>()), + Subtarget(std::make_unique<DirectXSubtarget>(TT, CPU, FS, *this)) { + initAsmInfo(); +} + +DirectXTargetMachine::~DirectXTargetMachine() {} + +bool DirectXTargetMachine::addPassesToEmitFile( + PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, + CodeGenFileType FileType, bool DisableVerify, + MachineModuleInfoWrapperPass *MMIWP) { + PM.add(createDXILOpLoweringLegacyPass()); + PM.add(createDXILPrepareModulePass()); + PM.add(createDXILTranslateMetadataPass()); + if (TargetPassConfig::willCompleteCodeGenPipeline()) { + PM.add(createDXILEmbedderPass()); + } + switch (FileType) { + case CGFT_AssemblyFile: + PM.add(createPrintModulePass(Out, "", true)); + break; + case CGFT_ObjectFile: + if (TargetPassConfig::willCompleteCodeGenPipeline()) { + if (!MMIWP) + MMIWP = new MachineModuleInfoWrapperPass(this); + PM.add(MMIWP); + if (addAsmPrinter(PM, Out, DwoOut, FileType, + MMIWP->getMMI().getContext())) + return true; + } else + PM.add(createDXILWriterPass(Out)); + break; + case CGFT_Null: + break; + } + return false; +} + +bool DirectXTargetMachine::addPassesToEmitMC(PassManagerBase &PM, + MCContext *&Ctx, + raw_pwrite_stream &Out, + bool DisableVerify) { + return true; +} + +TargetPassConfig *DirectXTargetMachine::createPassConfig(PassManagerBase &PM) { + return new DirectXPassConfig(*this, PM); +} + +const DirectXSubtarget * +DirectXTargetMachine::getSubtargetImpl(const Function &) const { + return Subtarget.get(); +} + +TargetTransformInfo +DirectXTargetMachine::getTargetTransformInfo(const Function &F) const { + return TargetTransformInfo(DirectXTTIImpl(this, F)); +} + +DirectXTargetLowering::DirectXTargetLowering(const DirectXTargetMachine &TM, + const DirectXSubtarget &STI) + : TargetLowering(TM) {} diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.h b/llvm/lib/Target/DirectX/DirectXTargetMachine.h new file mode 100644 index 000000000000..ae41638b6acf --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.h @@ -0,0 +1,51 @@ +//===- DirectXTargetMachine.h - DirectX Target Implementation ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXTARGETMACHINE_H +#define LLVM_DIRECTX_DIRECTXTARGETMACHINE_H + +#include "DirectXSubtarget.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class Function; +class DirectXTargetMachine : public LLVMTargetMachine { + std::unique_ptr<TargetLoweringObjectFile> TLOF; + std::unique_ptr<DirectXSubtarget> Subtarget; + +public: + DirectXTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, + CodeGenOpt::Level OL, bool JIT); + + ~DirectXTargetMachine() override; + + bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out, + raw_pwrite_stream *DwoOut, CodeGenFileType FileType, + bool DisableVerify, + MachineModuleInfoWrapperPass *MMIWP) override; + + bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx, + raw_pwrite_stream &Out, bool DisableVerify) override; + + const DirectXSubtarget *getSubtargetImpl(const Function &) const override; + + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } + + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; +}; +} // namespace llvm + +#endif // LLVM_DIRECTX_DIRECTXTARGETMACHINE_H diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h new file mode 100644 index 000000000000..90beb386fa44 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h @@ -0,0 +1,39 @@ +//===- DirectXTargetTransformInfo.h - DirectX TTI ---------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXTARGETTRANSFORMINFO_H +#define LLVM_DIRECTX_DIRECTXTARGETTRANSFORMINFO_H + +#include "DirectXSubtarget.h" +#include "DirectXTargetMachine.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/IR/Function.h" + +namespace llvm { +class DirectXTTIImpl : public BasicTTIImplBase<DirectXTTIImpl> { + using BaseT = BasicTTIImplBase<DirectXTTIImpl>; + using TTI = TargetTransformInfo; + + friend BaseT; + + const DirectXSubtarget *ST; + const DirectXTargetLowering *TLI; + + const DirectXSubtarget *getST() const { return ST; } + const DirectXTargetLowering *getTLI() const { return TLI; } + +public: + explicit DirectXTTIImpl(const DirectXTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} +}; +} // namespace llvm + +#endif // LLVM_DIRECTX_DIRECTXTARGETTRANSFORMINFO_H diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp new file mode 100644 index 000000000000..78ccbc444bce --- /dev/null +++ b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp @@ -0,0 +1,28 @@ +//===-- DirectXContainerObjectWriter.cpp - DX object writer ----*- C++ -*--===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains DXContainer object writers for the DirectX backend. +// +//===----------------------------------------------------------------------===// + +#include "DirectXContainerObjectWriter.h" +#include "llvm/MC/MCDXContainerWriter.h" + +using namespace llvm; + +namespace { +class DirectXContainerObjectWriter : public MCDXContainerTargetWriter { +public: + DirectXContainerObjectWriter() : MCDXContainerTargetWriter() {} +}; +} // namespace + +std::unique_ptr<MCObjectTargetWriter> +llvm::createDXContainerTargetObjectWriter() { + return std::make_unique<DirectXContainerObjectWriter>(); +} diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h new file mode 100644 index 000000000000..a6fbdc865f7d --- /dev/null +++ b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h @@ -0,0 +1,24 @@ +//===-- DirectXContainerObjectWriter.h - DX object writer ------*- C++ -*--===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains DXContainer object writers for the DirectX backend. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H +#define LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" + +namespace llvm { + +std::unique_ptr<MCObjectTargetWriter> createDXContainerTargetObjectWriter(); + +} + +#endif // LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.cpp b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.cpp new file mode 100644 index 000000000000..0c97ab62a37b --- /dev/null +++ b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.cpp @@ -0,0 +1,152 @@ +//===- DirectXMCTargetDesc.cpp - DirectX Target Implementation --*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains DirectX target initializer. +/// +//===----------------------------------------------------------------------===// + +#include "DirectXMCTargetDesc.h" +#include "DirectXContainerObjectWriter.h" +#include "TargetInfo/DirectXTargetInfo.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/LaneBitmask.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCDXContainerWriter.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSchedule.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Compiler.h" +#include <memory> + +using namespace llvm; + +#define GET_INSTRINFO_MC_DESC +#define GET_INSTRINFO_MC_HELPERS +#include "DirectXGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "DirectXGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "DirectXGenRegisterInfo.inc" + +namespace { + +// DXILInstPrinter is a null stub because DXIL instructions aren't printed. +class DXILInstPrinter : public MCInstPrinter { +public: + DXILInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override {} + + std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override { + return std::make_pair<const char *, uint64_t>("", 0ull); + } + +private: +}; + +class DXILMCCodeEmitter : public MCCodeEmitter { +public: + DXILMCCodeEmitter() {} + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const override {} +}; + +class DXILAsmBackend : public MCAsmBackend { + +public: + DXILAsmBackend(const MCSubtargetInfo &STI) : MCAsmBackend(support::little) {} + ~DXILAsmBackend() override = default; + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef<char> Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override {} + + std::unique_ptr<MCObjectTargetWriter> + createObjectTargetWriter() const override { + return createDXContainerTargetObjectWriter(); + } + + unsigned getNumFixupKinds() const override { return 0; } + + bool writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const override { + return true; + } + + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return true; + } +}; + +class DirectXMCAsmInfo : public MCAsmInfo { +public: + explicit DirectXMCAsmInfo(const Triple &TT, const MCTargetOptions &Options) + : MCAsmInfo() {} +}; + +} // namespace + +static MCInstPrinter *createDXILMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + if (SyntaxVariant == 0) + return new DXILInstPrinter(MAI, MII, MRI); + return nullptr; +} + +MCCodeEmitter *createDXILMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new DXILMCCodeEmitter(); +} + +MCAsmBackend *createDXILMCAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + return new DXILAsmBackend(STI); +} + +static MCSubtargetInfo * +createDirectXMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + return createDirectXMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, FS); +} + +static MCRegisterInfo *createDirectXMCRegisterInfo(const Triple &Triple) { + return new MCRegisterInfo(); +} + +static MCInstrInfo *createDirectXMCInstrInfo() { return new MCInstrInfo(); } + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTargetMC() { + Target &T = getTheDirectXTarget(); + RegisterMCAsmInfo<DirectXMCAsmInfo> X(T); + TargetRegistry::RegisterMCInstrInfo(T, createDirectXMCInstrInfo); + TargetRegistry::RegisterMCInstPrinter(T, createDXILMCInstPrinter); + TargetRegistry::RegisterMCRegInfo(T, createDirectXMCRegisterInfo); + TargetRegistry::RegisterMCSubtargetInfo(T, createDirectXMCSubtargetInfo); + TargetRegistry::RegisterMCCodeEmitter(T, createDXILMCCodeEmitter); + TargetRegistry::RegisterMCAsmBackend(T, createDXILMCAsmBackend); +} diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.h b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.h new file mode 100644 index 000000000000..0c3873a24417 --- /dev/null +++ b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.h @@ -0,0 +1,29 @@ +//===- DirectXMCTargetDesc.h - DirectX Target Interface ---------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains DirectX target interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_DIRECTXMCTARGETDESC_H +#define LLVM_DIRECTX_DIRECTXMCTARGETDESC_H + +// Include DirectX stub register info +#define GET_REGINFO_ENUM +#include "DirectXGenRegisterInfo.inc" + +// Include DirectX stub instruction info +#define GET_INSTRINFO_ENUM +#define GET_INSTRINFO_MC_HELPER_DECLS +#include "DirectXGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "DirectXGenSubtargetInfo.inc" + +#endif // LLVM_DIRECTX_DIRECTXMCTARGETDESC_H diff --git a/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp b/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp new file mode 100644 index 000000000000..1d536bbd0011 --- /dev/null +++ b/llvm/lib/Target/DirectX/PointerTypeAnalysis.cpp @@ -0,0 +1,119 @@ +//===- Target/DirectX/PointerTypeAnalisis.cpp - PointerType analysis ------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Analysis pass to assign types to opaque pointers. +// +//===----------------------------------------------------------------------===// + +#include "PointerTypeAnalysis.h" +#include "llvm/IR/Instructions.h" + +using namespace llvm; +using namespace llvm::dxil; + +namespace { + +// Classifies the type of the value passed in by walking the value's users to +// find a typed instruction to materialize a type from. +TypedPointerType *classifyPointerType(const Value *V) { + assert(V->getType()->isOpaquePointerTy() && + "classifyPointerType called with non-opaque pointer"); + Type *PointeeTy = nullptr; + if (auto *Inst = dyn_cast<GetElementPtrInst>(V)) { + if (!Inst->getResultElementType()->isOpaquePointerTy()) + PointeeTy = Inst->getResultElementType(); + } else if (auto *Inst = dyn_cast<AllocaInst>(V)) { + PointeeTy = Inst->getAllocatedType(); + } + for (const auto *User : V->users()) { + Type *NewPointeeTy = nullptr; + if (const auto *Inst = dyn_cast<LoadInst>(User)) { + NewPointeeTy = Inst->getType(); + } else if (const auto *Inst = dyn_cast<StoreInst>(User)) { + NewPointeeTy = Inst->getValueOperand()->getType(); + } else if (const auto *Inst = dyn_cast<GetElementPtrInst>(User)) { + NewPointeeTy = Inst->getSourceElementType(); + } + if (NewPointeeTy) { + // HLSL doesn't support pointers, so it is unlikely to get more than one + // or two levels of indirection in the IR. Because of this, recursion is + // pretty safe. + if (NewPointeeTy->isOpaquePointerTy()) + return TypedPointerType::get(classifyPointerType(User), + V->getType()->getPointerAddressSpace()); + if (!PointeeTy) + PointeeTy = NewPointeeTy; + else if (PointeeTy != NewPointeeTy) + PointeeTy = Type::getInt8Ty(V->getContext()); + } + } + // If we were unable to determine the pointee type, set to i8 + if (!PointeeTy) + PointeeTy = Type::getInt8Ty(V->getContext()); + return TypedPointerType::get(PointeeTy, + V->getType()->getPointerAddressSpace()); +} + +// This function constructs a function type accepting typed pointers. It only +// handles function arguments and return types, and assigns the function type to +// the function's value in the type map. +void classifyFunctionType(const Function &F, PointerTypeMap &Map) { + SmallVector<Type *, 8> NewArgs; + bool HasOpaqueTy = false; + Type *RetTy = F.getReturnType(); + if (RetTy->isOpaquePointerTy()) { + RetTy = nullptr; + for (const auto &B : F) { + for (const auto &I : B) { + if (const auto *RetInst = dyn_cast_or_null<ReturnInst>(&I)) { + Type *NewRetTy = classifyPointerType(RetInst->getReturnValue()); + if (!RetTy) + RetTy = NewRetTy; + else if (RetTy != NewRetTy) + RetTy = TypedPointerType::get( + Type::getInt8Ty(I.getContext()), + F.getReturnType()->getPointerAddressSpace()); + } + } + } + } + for (auto &A : F.args()) { + Type *ArgTy = A.getType(); + if (ArgTy->isOpaquePointerTy()) { + 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); +} +} // anonymous namespace + +PointerTypeMap PointerTypeAnalysis::run(const Module &M) { + PointerTypeMap Map; + for (auto &G : M.globals()) { + if (G.getType()->isOpaquePointerTy()) + Map[&G] = classifyPointerType(&G); + } + for (auto &F : M) { + classifyFunctionType(F, Map); + + for (const auto &B : F) { + for (const auto &I : B) { + if (I.getType()->isOpaquePointerTy()) + Map[&I] = classifyPointerType(&I); + } + } + } + + return Map; +} diff --git a/llvm/lib/Target/DirectX/PointerTypeAnalysis.h b/llvm/lib/Target/DirectX/PointerTypeAnalysis.h new file mode 100644 index 000000000000..c4164b6bf359 --- /dev/null +++ b/llvm/lib/Target/DirectX/PointerTypeAnalysis.h @@ -0,0 +1,43 @@ +//===- Target/DirectX/PointerTypeAnalysis.h - PointerType analysis --------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Analysis pass to assign types to opaque pointers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_DIRECTX_POINTERTYPEANALYSIS_H +#define LLVM_TARGET_DIRECTX_POINTERTYPEANALYSIS_H + +#include "DXILPointerType.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +namespace dxil { + +// Store the underlying type and the number of pointer indirections +using PointerTypeMap = DenseMap<const Value *, Type *>; + +/// An analysis to compute the \c PointerTypes for pointers in a \c Module. +/// Since this analysis is only run during codegen and the new pass manager +/// doesn't support codegen passes, this is wrtten as a function in a namespace. +/// It is very simple to transform it into a proper analysis pass. +/// This code relies on typed pointers existing as LLVM types, but could be +/// migrated to a custom Type if PointerType loses typed support. +namespace PointerTypeAnalysis { + +/// Compute the \c PointerTypeMap for the module \c M. +PointerTypeMap run(const Module &M); +} // namespace PointerTypeAnalysis + +} // namespace dxil + +} // namespace llvm + +#endif // LLVM_TARGET_DIRECTX_POINTERTYPEANALYSIS_H diff --git a/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.cpp b/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.cpp new file mode 100644 index 000000000000..54c577debc34 --- /dev/null +++ b/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.cpp @@ -0,0 +1,30 @@ +//===- DirectXTargetInfo.cpp - DirectX Target Implementation ----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains DirectX target initializer. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +Target &getTheDirectXTarget() { + static Target TheDirectXTarget; + return TheDirectXTarget; +} +} // namespace llvm + +using namespace llvm; + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTargetInfo() { + RegisterTarget<Triple::dxil, /*HasJIT=*/false> X( + getTheDirectXTarget(), "dxil", "DirectX Intermediate Language", "DXIL"); +} diff --git a/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.h b/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.h new file mode 100644 index 000000000000..a860c430f81a --- /dev/null +++ b/llvm/lib/Target/DirectX/TargetInfo/DirectXTargetInfo.h @@ -0,0 +1,18 @@ +//===-- DirectXTargetInfo.h - DircetX Target Implementation -----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DIRECTX_TARGETINFO_DIRECTXTARGETINFO_H +#define LLVM_DIRECTX_TARGETINFO_DIRECTXTARGETINFO_H + +namespace llvm { +class Target; + +Target &getTheDirectXTarget(); +} // namespace llvm + +#endif // LLVM_DIRECTX_TARGETINFO_DIRECTXTARGETINFO_H |