From 60d2327f3e00b3454ea0c5921c338e3570ef5472 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 7 Jun 2024 11:51:16 +0200 Subject: [PATCH] Support for emitting typed LLVM 5.0 IR from opaque pointers. (#5) --- llvm/lib/Bitcode/Writer50/BitcodeWriter50.cpp | 82 ++++- llvm/lib/Bitcode/Writer50/CMakeLists.txt | 1 + .../lib/Bitcode/Writer50/ModuleRewriter50.cpp | 16 +- llvm/lib/Bitcode/Writer50/ModuleRewriter50.h | 6 +- llvm/lib/Bitcode/Writer50/PointerRewriter.cpp | 312 ++++++++++++++++++ llvm/lib/Bitcode/Writer50/PointerRewriter.h | 42 +++ .../Bitcode/Writer50/ValueEnumerator50.cpp | 8 + llvm/lib/Bitcode/Writer50/ValueEnumerator50.h | 4 +- 8 files changed, 449 insertions(+), 22 deletions(-) create mode 100644 llvm/lib/Bitcode/Writer50/PointerRewriter.cpp create mode 100644 llvm/lib/Bitcode/Writer50/PointerRewriter.h diff --git a/llvm/lib/Bitcode/Writer50/BitcodeWriter50.cpp b/llvm/lib/Bitcode/Writer50/BitcodeWriter50.cpp index e526e27d6aea07..6d379323b201cf 100644 --- a/llvm/lib/Bitcode/Writer50/BitcodeWriter50.cpp +++ b/llvm/lib/Bitcode/Writer50/BitcodeWriter50.cpp @@ -14,6 +14,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "ValueEnumerator50.h" #include "ModuleRewriter50.h" +#include "PointerRewriter.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitstream/BitstreamWriter.h" @@ -26,6 +27,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/TypedPointerType.h" #include "llvm/IR/UseListOrder.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/MC/StringTableBuilder.h" @@ -136,6 +138,8 @@ class ModuleBitcodeWriter50 : public BitcodeWriterBase50 { /// backpatched with the offset of the actual VST. uint64_t VSTOffsetPlaceholder = 0; + PointerTypeMap PointerMap; + public: /// Constructs a ModuleBitcodeWriter50 object for the given Module, /// writing to the provided \p Buffer. @@ -148,6 +152,14 @@ class ModuleBitcodeWriter50 : public BitcodeWriterBase50 { VE(M, ShouldPreserveUseListOrder), Index(Index), GenerateHash(GenerateHash), ModHash(ModHash), BitcodeStartBit(Stream.GetCurrentBitNo()) { + + // Enumerate typed pointers + if (!M.getContext().supportsTypedPointers()) { + PointerMap = PointerRewriter::buildPointerMap(M); + for (auto El : PointerMap) + VE.EnumerateType(El.second); + } + // imitate Metal by having one llvm.dbg.cu entry per DISubprogram if (auto dbg_cu = M.getNamedMetadata("llvm.dbg.cu"); dbg_cu) { uint32_t subprogram_count = 0; @@ -283,7 +295,7 @@ class ModuleBitcodeWriter50 : public BitcodeWriterBase50 { void writeConstants(unsigned FirstVal, unsigned LastVal, bool isGlobal); void writeModuleConstants(); bool pushValueAndType(const Value *V, unsigned InstID, - SmallVectorImpl &Vals); + SmallVectorImpl &Vals, Type *Ty = nullptr); void writeOperandBundles(const CallBase &CB, unsigned InstID); void pushValue(const Value *V, unsigned InstID, SmallVectorImpl &Vals); @@ -813,12 +825,36 @@ void ModuleBitcodeWriter50::writeTypeTable() { break; case Type::PointerTyID: { PointerType *PTy = cast(T); + unsigned AddressSpace = PTy->getAddressSpace(); + if (PTy->isOpaque()) { + // OPAQUE_POINTER: [address space] + // unsupported, so emit as + // POINTER: [opaque element type, address space] + Code = bitc::TYPE_CODE_POINTER; + auto ET = StructType::get(PTy->getContext()); + TypeVals.push_back(VE.getTypeID(ET)); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; + } else { + // POINTER: [pointee type, address space] + Code = bitc::TYPE_CODE_POINTER; + TypeVals.push_back(VE.getTypeID(PTy->getNonOpaquePointerElementType())); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; + } + break; + } + case Type::TypedPointerTyID: { + TypedPointerType *PTy = cast(T); + unsigned AddressSpace = PTy->getAddressSpace(); // POINTER: [pointee type, address space] Code = bitc::TYPE_CODE_POINTER; - TypeVals.push_back(VE.getTypeID(PTy->getNonOpaquePointerElementType())); - unsigned AddressSpace = PTy->getAddressSpace(); + TypeVals.push_back(VE.getTypeID(PTy->getElementType())); TypeVals.push_back(AddressSpace); - if (AddressSpace == 0) AbbrevToUse = PtrAbbrev; + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; break; } case Type::FunctionTyID: { @@ -885,8 +921,6 @@ void ModuleBitcodeWriter50::writeTypeTable() { case Type::X86_AMXTyID: report_fatal_error("AMX types are not supported with LLVM 5.0"); break; - case Type::DXILPointerTyID: - report_fatal_error("DXIL pointers cannot be added to IR modules"); } // Emit the finished record. @@ -1223,7 +1257,10 @@ void ModuleBitcodeWriter50::writeModuleInfo() { // prefixdata, personalityfn] Vals.push_back(addToStrtab(F.getName())); Vals.push_back(F.getName().size()); - Vals.push_back(VE.getTypeID(F.getFunctionType())); + Type *FTy = F.getFunctionType(); + if (auto Ty = PointerMap.lookup(&F)) + FTy = cast(Ty->getElementType()); + Vals.push_back(VE.getTypeID(FTy)); Vals.push_back(F.getCallingConv()); Vals.push_back(F.isDeclaration()); Vals.push_back(getEncodedLinkage(F)); @@ -1317,7 +1354,12 @@ void ModuleBitcodeWriter50::writeValueAsMetadata( const ValueAsMetadata *MD, SmallVectorImpl &Record) { // Mimic an MDNode with a value as one operand. Value *V = MD->getValue(); - Record.push_back(VE.getTypeID(V->getType())); + Type *Ty = V->getType(); + if (Function *F = dyn_cast(V)) + Ty = TypedPointerType::get(F->getFunctionType(), F->getAddressSpace()); + else if (GlobalVariable *GV = dyn_cast(V)) + Ty = TypedPointerType::get(GV->getValueType(), GV->getAddressSpace()); + Record.push_back(VE.getTypeID(Ty)); Record.push_back(VE.getValueID(V)); Stream.EmitRecord(bitc::METADATA_VALUE, Record, 0); Record.clear(); @@ -2423,12 +2465,15 @@ void ModuleBitcodeWriter50::writeModuleConstants() { /// 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 ModuleBitcodeWriter50::pushValueAndType(const Value *V, unsigned InstID, - SmallVectorImpl &Vals) { + SmallVectorImpl &Vals, + Type *Ty) { unsigned ValID = VE.getValueID(V); // Make encoding relative to the InstID. Vals.push_back(InstID - ValID); if (ValID >= InstID) { - Vals.push_back(VE.getTypeID(V->getType())); + if (!Ty) + Ty = V->getType(); + Vals.push_back(VE.getTypeID(Ty)); return true; } return false; @@ -2477,9 +2522,15 @@ void ModuleBitcodeWriter50::writeInstruction(const Instruction &I, default: if (Instruction::isCast(I.getOpcode())) { Code = bitc::FUNC_CODE_INST_CAST; - if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + Type *OpTy = I.getOperand(0)->getType(); + if (PointerMap.find(I.getOperand(0)) != PointerMap.end()) + OpTy = PointerMap[I.getOperand(0)]; + if (!pushValueAndType(I.getOperand(0), InstID, Vals, OpTy)) AbbrevToUse = FUNCTION_INST_CAST_ABBREV; - Vals.push_back(VE.getTypeID(I.getType())); + Type *Ty = I.getType(); + if (PointerMap.find(&I) != PointerMap.end()) + Ty = PointerMap[&I]; + Vals.push_back(VE.getTypeID(Ty)); Vals.push_back(getEncodedCastOpcode(I.getOpcode())); } else { assert(isa(I) && "Unknown instruction!"); @@ -2817,6 +2868,13 @@ void ModuleBitcodeWriter50::writeInstruction(const Instruction &I, const CallInst &CI = cast(I); FunctionType *FTy = CI.getFunctionType(); + // Rewrite function types to match incoming arguments + if (CI.getCalledFunction()) { + auto F = CI.getCalledFunction(); + if (auto Ty = PointerMap.lookup(F)) + FTy = cast(Ty->getElementType()); + } + if (CI.hasOperandBundles()) writeOperandBundles(CI, InstID); diff --git a/llvm/lib/Bitcode/Writer50/CMakeLists.txt b/llvm/lib/Bitcode/Writer50/CMakeLists.txt index d047b787c8fcc6..f30b05df2f2818 100644 --- a/llvm/lib/Bitcode/Writer50/CMakeLists.txt +++ b/llvm/lib/Bitcode/Writer50/CMakeLists.txt @@ -4,6 +4,7 @@ add_llvm_component_library(LLVMBitWriter50 BitcodeWriterPass50.cpp ValueEnumerator50.cpp ModuleRewriter50.cpp + PointerRewriter.cpp DEPENDS intrinsics_gen diff --git a/llvm/lib/Bitcode/Writer50/ModuleRewriter50.cpp b/llvm/lib/Bitcode/Writer50/ModuleRewriter50.cpp index 5581457f950767..3c8f0f58be1224 100644 --- a/llvm/lib/Bitcode/Writer50/ModuleRewriter50.cpp +++ b/llvm/lib/Bitcode/Writer50/ModuleRewriter50.cpp @@ -12,15 +12,12 @@ //===----------------------------------------------------------------------===// #include "ModuleRewriter50.h" +#include "PointerRewriter.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" using namespace llvm; -void ModuleRewriter50::run() { - removeFreeze(); -} - -bool ModuleRewriter50::removeFreeze() { +bool removeFreeze(Module &M) { // Find freeze instructions SmallVector Worklist; for (Function &F : M) { @@ -42,3 +39,12 @@ bool ModuleRewriter50::removeFreeze() { } return true; } + +bool ModuleRewriter50::run() { + bool Changed = removeFreeze(M); + + PointerRewriter PR(M); + Changed |= PR.run(); + + return Changed; +} diff --git a/llvm/lib/Bitcode/Writer50/ModuleRewriter50.h b/llvm/lib/Bitcode/Writer50/ModuleRewriter50.h index 19342cb5c6c3ef..38d32e41814795 100644 --- a/llvm/lib/Bitcode/Writer50/ModuleRewriter50.h +++ b/llvm/lib/Bitcode/Writer50/ModuleRewriter50.h @@ -22,12 +22,10 @@ class ModuleRewriter50 { public: ModuleRewriter50(Module &M) : M(M) {} - void run(); + bool run(); private: - Module &M; - - bool removeFreeze(); + Module &M; }; diff --git a/llvm/lib/Bitcode/Writer50/PointerRewriter.cpp b/llvm/lib/Bitcode/Writer50/PointerRewriter.cpp new file mode 100644 index 00000000000000..0e6a6108f9ab3e --- /dev/null +++ b/llvm/lib/Bitcode/Writer50/PointerRewriter.cpp @@ -0,0 +1,312 @@ +//===- PointerRewriter.cpp - Rewrite opaque pointers for typed IR ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PointerRewriter class. +// +//===----------------------------------------------------------------------===// + +// Old LLVM versions do not support opaque pointers, so we need to emit typed +// instructions when writing the bitcode. This is hard, as the element type +// information is lost. We deal with this by surrounding all known typed pointer +// uses and definitions with bitcasts to a custom opaque pointer type. Since we +// cannot represent typed pointers in IR (it is illegal to cast to +// TypedPointerTypes), these casts are emitted by the bitcode writer. However, +// to make that easier, we already emit no-op bitcasts here so that the +// ValueEnumerator reserves instruction IDs correctly. +// +// To expose the element type information to the bitcode writer, we provide a +// pointer map that maps values to their typed pointer types. +// +// All this is similar to LLVM's PointerTypeAnalysis pass for DXIL. That pass +// tries to infer the element type of opaque pointers by looking at the uses of +// a pointer, and subsequently the DXIL module writer tries to keep values typed +// for much longer time. This turns out to be fragile, breaking / requiring +// special handling for many more instructions (like select or phi), while also +// not correctly handling multiple (but differently typed) uses of the same +// opaque pointer. To avoid that complexity, we simply emit a bitcase +// surrounding every use or definition of a typed value, keeping pointers opaque +// for the rest of the function. +// +// We also support front-ends customizing element type information, i.e., to +// indicate that operands to certain function calls need to be typed, the +// analysis supports !arg_eltypes metadata on function declarations, containing +// pairs of operand indices and null values representing the element type of the +// operand. This is very useful for custom intrinsics whose type information +// cannot be inferred from the IR. + +#include "PointerRewriter.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/TypedPointerType.h" +using namespace llvm; + +// Demote all constant expressions that produce pointers, to their +// corresponding instructions so that we can more easily rewrite them. +bool demotePointerConstexprs(Module &M) { + SmallVector, 8> Worklist; + for (Function &F : M) + for (BasicBlock &BB : F) + for (Instruction &I : BB) + for (const Use &Op : I.operands()) + if (auto *CE = dyn_cast(Op)) + Worklist.push_back({&I, Op.getOperandNo()}); + if (Worklist.empty()) + return false; + + for (auto Item : Worklist) { + Instruction *I = Item.first; + int OpIdx = Item.second; + ConstantExpr *CE = cast(I->getOperand(OpIdx)); + Instruction *NewI = CE->getAsInstruction(); + NewI->insertBefore(I); + I->setOperand(OpIdx, NewI); + } + return true; +} + +// determine the typed function type based on !arg_eltypes metadata +static FunctionType *getTypedFunctionType(const Function *F) { + auto *FTy = F->getFunctionType(); + MDNode *MD = F->getMetadata("arg_eltypes"); + if (!MD) + return FTy; + + auto Args = FTy->params().vec(); + for (unsigned i = 0; i < MD->getNumOperands(); i += 2) { + auto IdxConstant = cast(MD->getOperand(i))->getValue(); + int Idx = cast(IdxConstant)->getZExtValue(); + Type *ElTy = + cast(MD->getOperand(i + 1))->getValue()->getType(); + + auto OpaquePtrTy = cast(Args[Idx]); + auto TypedPtrTy = + TypedPointerType::get(ElTy, OpaquePtrTy->getAddressSpace()); + Args[Idx] = TypedPtrTy; + } + return FunctionType::get(FTy->getReturnType(), Args, FTy->isVarArg()); +} + +static bool isNoopCast(const Value *V) { + auto I = cast(V); + if (I->getOpcode() != Instruction::BitCast) + return false; + return I->getOperand(0)->getType() == I->getType(); +} + +// prepend a single instruction's operand with a no-op bitcast +static void prependOperandBitcast(Module &M, Instruction *I, int Idx) { + Value *V = I->getOperand(Idx); + assert(V->getType()->isPointerTy() && "Expected a pointer operand"); + + // Insert no-op bitcast + Value *Cast = CastInst::Create(Instruction::BitCast, V, V->getType(), "", I); + I->setOperand(Idx, Cast); +} + +// prepend all uses of a value with no-op bitcasts +static void prependBitcasts(Module &M, Value *V) { + assert(V->getType()->isPointerTy() && "Expected a pointer value"); + + // Find all uses + SmallVector, 8> Worklist; + for (Use &Use : V->uses()) { + auto User = Use.getUser(); + if (auto *I = dyn_cast(User)) + Worklist.push_back({I, Use.getOperandNo()}); + } + + // Insert no-op bitcasts + for (auto Item : Worklist) { + Instruction *I = Item.first; + int Idx = Item.second; + prependOperandBitcast(M, I, Idx); + } +} + +// append a single instruction's return value with a no-op bitcast +static void appendBitcast(Module &M, Instruction *I) { + assert(I->getType()->isPointerTy() && + "Expected a pointer-returning instruction"); + + // Insert no-op bitcast + Instruction *Cast = CastInst::Create(Instruction::BitCast, I, I->getType(), + "", I->getNextNode()); + I->replaceAllUsesWith(Cast); + // HACK: undo the RAUW which messed with our input argument too + Cast->setOperand(0, I); +} + +// bitcast uses of globals, for which we can infer the element type based on the +// global's type +bool bitcastGlobals(Module &M) { + // Find all globals + SmallVector Worklist; + for (GlobalVariable &GV : M.globals()) + Worklist.push_back(&GV); + if (Worklist.empty()) + return false; + + // Insert bitcasts + for (GlobalVariable *GV : Worklist) { + prependBitcasts(M, GV); + } + + return true; +} + +// bitcast operands to instructions, by infering the element type by inspecting +// the instruction +bool bitcastInstructionOperands(Module &M) { + // Find all instructions with pointer inputs or outputs + SmallVector Worklist; + for (Function &F : M) { + for (BasicBlock &BB : F) { + for (Instruction &I : BB) { + if (auto *LI = dyn_cast(&I)) + Worklist.push_back(LI); + else if (auto *SI = dyn_cast(&I)) + Worklist.push_back(SI); + else if (auto *GEP = dyn_cast(&I)) + Worklist.push_back(GEP); + else if (auto *AI = dyn_cast(&I)) + Worklist.push_back(AI); + } + } + } + if (Worklist.empty()) + return false; + + // Add no-op bitcasts + for (Instruction *I : Worklist) { + if (auto *LI = dyn_cast(I)) { + prependBitcasts(M, LI->getPointerOperand()); + } else if (auto *SI = dyn_cast(I)) { + prependBitcasts(M, SI->getPointerOperand()); + } else if (auto *GEP = dyn_cast(I)) { + prependBitcasts(M, GEP->getPointerOperand()); + appendBitcast(M, GEP); + } else if (auto *AI = dyn_cast(I)) { + appendBitcast(M, AI); + } else + llvm_unreachable("Unhandled instruction"); + } + + return true; +} + +// bitcast operands to calls, whose type can be altered by metadata attached to +// the function +bool bitcastFunctionOperands(Module &M) { + for (Function &F : M) { + auto *FTy = F.getFunctionType(); + auto *NewFTy = getTypedFunctionType(&F); + if (FTy == NewFTy) + continue; + + // convert calls to this function + for (User *U : F.users()) { + if (auto *CI = dyn_cast(U)) { + for (unsigned Idx = 0; Idx < CI->arg_size(); Idx++) { + auto OldTy = FTy->getParamType(Idx); + auto NewTy = NewFTy->getParamType(Idx); + if (OldTy == NewTy) + continue; + + prependOperandBitcast(M, CI, Idx); + } + } + } + } + + return false; +} + +// build a map of values to typed pointer types +PointerTypeMap PointerRewriter::buildPointerMap(const Module &M) { + PointerTypeMap PointerMap; + + // globals + for (const GlobalVariable &GV : M.globals()) { + Type *ElTy = GV.getValueType(); + unsigned AS = GV.getAddressSpace(); + auto TypedPtrTy = TypedPointerType::get(ElTy, AS); + PointerMap[&GV] = TypedPtrTy; + } + + // instructions + for (const Function &F : M) { + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + if (auto *LI = dyn_cast(&I)) { + assert(isNoopCast(LI->getPointerOperand())); + PointerMap[LI->getPointerOperand()] = TypedPointerType::get( + LI->getType(), LI->getPointerAddressSpace()); + } else if (auto *SI = dyn_cast(&I)) { + assert(isNoopCast(SI->getPointerOperand())); + PointerMap[SI->getPointerOperand()] = TypedPointerType::get( + SI->getValueOperand()->getType(), SI->getPointerAddressSpace()); + } else if (auto *GEP = dyn_cast(&I)) { + assert(isNoopCast(GEP->getPointerOperand())); + PointerMap[GEP->getPointerOperand()] = TypedPointerType::get( + GEP->getSourceElementType(), GEP->getAddressSpace()); + assert(GEP->hasOneUse() && isNoopCast(GEP->user_back())); + PointerMap[GEP] = TypedPointerType::get(GEP->getResultElementType(), + GEP->getAddressSpace()); + } else if (auto *AI = dyn_cast(&I)) { + assert(AI->hasOneUse() && isNoopCast(AI->user_back())); + PointerMap[AI] = TypedPointerType::get(AI->getAllocatedType(), + AI->getAddressSpace()); + } + } + } + } + + // functions + for (const Function &F : M) { + auto *FTy = F.getFunctionType(); + auto *NewFTy = getTypedFunctionType(&F); + PointerMap[&F] = TypedPointerType::get(NewFTy, F.getAddressSpace()); + if (FTy == NewFTy) + continue; + + for (unsigned int i = 0; i < FTy->getNumParams(); i++) { + auto OldTy = FTy->getParamType(i); + auto NewTy = NewFTy->getParamType(i); + if (OldTy == NewTy) + continue; + + for (const User *U : F.users()) { + if (auto *CI = dyn_cast(U)) { + assert(isNoopCast(CI->getArgOperand(i))); + PointerMap[CI->getArgOperand(i)] = cast(NewTy); + } + } + } + } + + return PointerMap; +} + +bool PointerRewriter::run() { + if (M.getContext().supportsTypedPointers()) + return false; + + // get rid of constant expressions so that we can more easily rewrite them + bool Changed = demotePointerConstexprs(M); + + // insert no-op bitcasts surrounding pointer values + Changed |= bitcastGlobals(M); + Changed |= bitcastInstructionOperands(M); + Changed |= bitcastFunctionOperands(M); + + // TODO: remove double bitcasts? + + return Changed; +} diff --git a/llvm/lib/Bitcode/Writer50/PointerRewriter.h b/llvm/lib/Bitcode/Writer50/PointerRewriter.h new file mode 100644 index 00000000000000..3fa66ac7bfc1d9 --- /dev/null +++ b/llvm/lib/Bitcode/Writer50/PointerRewriter.h @@ -0,0 +1,42 @@ +//===-- Bitcode/Writer50/PointerRewriter.h - Rewrite pointers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class supports writing opaque pointers in typed IR. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_BITCODE_WRITER50_POINTERREWRITER_H +#define LLVM_LIB_BITCODE_WRITER50_POINTERREWRITER_H + +#include "llvm/ADT/DenseMap.h" + +namespace llvm { + +class Value; +class Module; +class TypedPointerType; + +using PointerTypeMap = DenseMap; + +class PointerRewriter { +public: + PointerRewriter(Module &M) : M(M) {} + + bool run(); + + static PointerTypeMap buildPointerMap(const Module &M); + +private: + Module &M; +}; + + +} // End llvm namespace + +#endif diff --git a/llvm/lib/Bitcode/Writer50/ValueEnumerator50.cpp b/llvm/lib/Bitcode/Writer50/ValueEnumerator50.cpp index d0002e8571665e..fb0cbfe4d6db6c 100644 --- a/llvm/lib/Bitcode/Writer50/ValueEnumerator50.cpp +++ b/llvm/lib/Bitcode/Writer50/ValueEnumerator50.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ValueEnumerator50.h" +#include "ModuleRewriter50.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Constants.h" @@ -293,6 +294,13 @@ ValueEnumerator50::ValueEnumerator50(const Module &M, if (ShouldPreserveUseListOrder) UseListOrders = predictUseListOrder(M); + // Special types are needed when the context is opaque + if (!M.getContext().supportsTypedPointers()) { + // We'll encode pointers as {}*, so ensure the opaque type is available + Type *OpaquePtrTy = StructType::get(M.getContext()); + EnumerateType(OpaquePtrTy); + } + // Enumerate the global variables. for (const GlobalVariable &GV : M.globals()) EnumerateValue(&GV); diff --git a/llvm/lib/Bitcode/Writer50/ValueEnumerator50.h b/llvm/lib/Bitcode/Writer50/ValueEnumerator50.h index 39badbca6d11c7..09a3b3449c1974 100644 --- a/llvm/lib/Bitcode/Writer50/ValueEnumerator50.h +++ b/llvm/lib/Bitcode/Writer50/ValueEnumerator50.h @@ -297,12 +297,14 @@ class ValueEnumerator50 { void EnumerateFunctionLocalMetadata(unsigned F, const LocalAsMetadata *Local); void EnumerateNamedMDNode(const NamedMDNode *NMD); void EnumerateValue(const Value *V); - void EnumerateType(Type *T); void EnumerateOperandType(const Value *V); void EnumerateAttributes(AttributeList PAL); void EnumerateValueSymbolTable(const ValueSymbolTable &ST); void EnumerateNamedMetadata(const Module &M); + +public: + void EnumerateType(Type *T); }; } // End llvm namespace