X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FBitcode%2FWriter%2FBitcodeWriter.cpp;h=931e944a410d1dc13f9abe128a4b5b95771cfb2f;hp=92475fc9e81b405b3660f2aa14f97974460ce4d0;hb=d9b4a5f859188cbb168c223071b413e58c53c925;hpb=cb3d91b05b36a144dd0f3103ce4fda4cab356ad6 diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 92475fc9e81..931e944a410 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Chris Lattner and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -17,12 +17,14 @@ #include "ValueEnumerator.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" +#include "llvm/InlineAsm.h" #include "llvm/Instructions.h" #include "llvm/Module.h" -#include "llvm/ParameterAttributes.h" #include "llvm/TypeSymbolTable.h" #include "llvm/ValueSymbolTable.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/Streams.h" +#include "llvm/System/Program.h" using namespace llvm; /// These are manifest constants used by the bitcode writer. They do not need to @@ -43,7 +45,12 @@ enum { CONSTANTS_NULL_Abbrev, // FUNCTION_BLOCK abbrev id's. - FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV + FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV, + FUNCTION_INST_BINOP_ABBREV, + FUNCTION_INST_CAST_ABBREV, + FUNCTION_INST_RET_VOID_ABBREV, + FUNCTION_INST_RET_VAL_ABBREV, + FUNCTION_INST_UNREACHABLE_ABBREV }; @@ -103,17 +110,18 @@ static void WriteStringRecord(unsigned Code, const std::string &Str, // Emit information about parameter attributes. static void WriteParamAttrTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { - const std::vector &Attrs = VE.getParamAttrs(); + const std::vector &Attrs = VE.getParamAttrs(); if (Attrs.empty()) return; Stream.EnterSubblock(bitc::PARAMATTR_BLOCK_ID, 3); SmallVector Record; for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { - const ParamAttrsList *A = Attrs[i]; - for (unsigned op = 0, e = A->size(); op != e; ++op) { - Record.push_back(A->getParamIndex(op)); - Record.push_back(A->getParamAttrsAtIndex(op)); + const PAListPtr &A = Attrs[i]; + for (unsigned i = 0, e = A.getNumSlots(); i != e; ++i) { + const ParamAttrsWithIndex &PAWI = A.getSlot(i); + Record.push_back(PAWI.Index); + Record.push_back(PAWI.Attrs); } Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record); @@ -135,14 +143,14 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_POINTER)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, Log2_32_Ceil(VE.getTypes().size()+1))); + Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0 unsigned PtrAbbrev = Stream.EmitAbbrev(Abbv); // Abbrev for TYPE_CODE_FUNCTION. Abbv = new BitCodeAbbrev(); Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isvararg - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, - Log2_32_Ceil(VE.getParamAttrs().size()+1))); + Abbv->Add(BitCodeAbbrevOp(0)); // FIXME: DEAD value, remove in LLVM 3.0 Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, Log2_32_Ceil(VE.getTypes().size()+1))); @@ -177,11 +185,13 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { unsigned Code = 0; switch (T->getTypeID()) { - case Type::PackedStructTyID: // FIXME: Delete Type::PackedStructTyID. default: assert(0 && "Unknown type!"); case Type::VoidTyID: Code = bitc::TYPE_CODE_VOID; 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::OpaqueTyID: Code = bitc::TYPE_CODE_OPAQUE; break; case Type::IntegerTyID: @@ -189,19 +199,22 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { Code = bitc::TYPE_CODE_INTEGER; TypeVals.push_back(cast(T)->getBitWidth()); break; - case Type::PointerTyID: - // POINTER: [pointee type] + case Type::PointerTyID: { + const PointerType *PTy = cast(T); + // POINTER: [pointee type, address space] Code = bitc::TYPE_CODE_POINTER; - TypeVals.push_back(VE.getTypeID(cast(T)->getElementType())); - AbbrevToUse = PtrAbbrev; + TypeVals.push_back(VE.getTypeID(PTy->getElementType())); + unsigned AddressSpace = PTy->getAddressSpace(); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) AbbrevToUse = PtrAbbrev; break; - + } case Type::FunctionTyID: { const FunctionType *FT = cast(T); // FUNCTION: [isvararg, attrid, retty, paramty x N] Code = bitc::TYPE_CODE_FUNCTION; TypeVals.push_back(FT->isVarArg()); - TypeVals.push_back(VE.getParamAttrID(FT->getParamAttrs())); + TypeVals.push_back(0); // FIXME: DEAD: remove in llvm 3.0 TypeVals.push_back(VE.getTypeID(FT->getReturnType())); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) TypeVals.push_back(VE.getTypeID(FT->getParamType(i))); @@ -250,6 +263,7 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { static unsigned getEncodedLinkage(const GlobalValue *GV) { switch (GV->getLinkage()) { default: assert(0 && "Invalid linkage!"); + case GlobalValue::GhostLinkage: // Map ghost linkage onto external. case GlobalValue::ExternalLinkage: return 0; case GlobalValue::WeakLinkage: return 1; case GlobalValue::AppendingLinkage: return 2; @@ -258,6 +272,7 @@ static unsigned getEncodedLinkage(const GlobalValue *GV) { case GlobalValue::DLLImportLinkage: return 5; case GlobalValue::DLLExportLinkage: return 6; case GlobalValue::ExternalWeakLinkage: return 7; + case GlobalValue::CommonLinkage: return 8; } } @@ -289,9 +304,10 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, WriteStringRecord(bitc::MODULE_CODE_ASM, M->getModuleInlineAsm(), 0/*TODO*/, Stream); - // Emit information about sections, computing how many there are. Also + // Emit information about sections and GC, computing how many there are. Also // compute the maximum alignment value. std::map SectionMap; + std::map GCMap; unsigned MaxAlignment = 0; unsigned MaxGlobalType = 0; for (Module::const_global_iterator GV = M->global_begin(),E = M->global_end(); @@ -309,13 +325,24 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, } for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) { MaxAlignment = std::max(MaxAlignment, F->getAlignment()); - if (!F->hasSection()) continue; - // Give section names unique ID's. - unsigned &Entry = SectionMap[F->getSection()]; - if (Entry != 0) continue; - WriteStringRecord(bitc::MODULE_CODE_SECTIONNAME, F->getSection(), - 0/*TODO*/, Stream); - Entry = SectionMap.size(); + if (F->hasSection()) { + // Give section names unique ID's. + unsigned &Entry = SectionMap[F->getSection()]; + if (!Entry) { + WriteStringRecord(bitc::MODULE_CODE_SECTIONNAME, F->getSection(), + 0/*TODO*/, Stream); + Entry = SectionMap.size(); + } + } + if (F->hasGC()) { + // Same for GC names. + unsigned &Entry = GCMap[F->getGC()]; + if (!Entry) { + WriteStringRecord(bitc::MODULE_CODE_GCNAME, F->getGC(), + 0/*TODO*/, Stream); + Entry = GCMap.size(); + } + } } // Emit abbrev for globals, now that we know # sections and max alignment. @@ -328,7 +355,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, Log2_32_Ceil(MaxGlobalType+1))); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constant. Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Initializer. - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage. + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // Linkage. if (MaxAlignment == 0) // Alignment. Abbv->Add(BitCodeAbbrevOp(0)); else { @@ -374,15 +401,17 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, // Emit the function proto information. for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) { - // FUNCTION: [type, callingconv, isproto, linkage, alignment, section, - // visibility] + // FUNCTION: [type, callingconv, isproto, paramattr, + // linkage, alignment, section, visibility, gc] Vals.push_back(VE.getTypeID(F->getType())); Vals.push_back(F->getCallingConv()); Vals.push_back(F->isDeclaration()); Vals.push_back(getEncodedLinkage(F)); + Vals.push_back(VE.getParamAttrID(F->getParamAttrs())); Vals.push_back(Log2_32(F->getAlignment())+1); Vals.push_back(F->hasSection() ? SectionMap[F->getSection()] : 0); Vals.push_back(getEncodedVisibility(F)); + Vals.push_back(F->hasGC() ? GCMap[F->getGC()] : 0); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); @@ -396,6 +425,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, Vals.push_back(VE.getTypeID(AI->getType())); Vals.push_back(VE.getValueID(AI->getAliasee())); Vals.push_back(getEncodedLinkage(AI)); + Vals.push_back(getEncodedVisibility(AI)); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse); Vals.clear(); @@ -443,9 +473,6 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, CString6Abbrev = Stream.EmitAbbrev(Abbv); } - // FIXME: Install and use abbrevs to reduce size. Install them globally so - // they don't need to be reemitted for each function body. - SmallVector Record; const ValueEnumerator::ValueList &Vals = VE.getValues(); @@ -462,7 +489,21 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, } if (const InlineAsm *IA = dyn_cast(V)) { - assert(0 && IA && "FIXME: Inline asm writing unimp!"); + Record.push_back(unsigned(IA->hasSideEffects())); + + // Add the asm string. + const std::string &AsmStr = IA->getAsmString(); + Record.push_back(AsmStr.size()); + for (unsigned i = 0, e = AsmStr.size(); i != e; ++i) + Record.push_back(AsmStr[i]); + + // Add the constraint string. + const std::string &ConstraintStr = IA->getConstraintString(); + Record.push_back(ConstraintStr.size()); + for (unsigned i = 0, e = ConstraintStr.size(); i != e; ++i) + Record.push_back(ConstraintStr[i]); + Stream.EmitRecord(bitc::CST_CODE_INLINEASM, Record); + Record.clear(); continue; } const Constant *C = cast(V); @@ -499,11 +540,22 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, } } else if (const ConstantFP *CFP = dyn_cast(C)) { Code = bitc::CST_CODE_FLOAT; - if (CFP->getType() == Type::FloatTy) { - Record.push_back(FloatToBits((float)CFP->getValue())); + const Type *Ty = CFP->getType(); + if (Ty == Type::FloatTy || Ty == Type::DoubleTy) { + Record.push_back(CFP->getValueAPF().convertToAPInt().getZExtValue()); + } else if (Ty == Type::X86_FP80Ty) { + // api needed to prevent premature destruction + APInt api = CFP->getValueAPF().convertToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back(p[0]); + Record.push_back((uint16_t)p[1]); + } else if (Ty == Type::FP128Ty || Ty == Type::PPC_FP128Ty) { + APInt api = CFP->getValueAPF().convertToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back(p[0]); + Record.push_back(p[1]); } else { - assert (CFP->getType() == Type::DoubleTy && "Unknown FP type!"); - Record.push_back(DoubleToBits((double)CFP->getValue())); + assert (0 && "Unknown FP type!"); } } else if (isa(C) && cast(C)->isString()) { // Emit constant strings specially. @@ -586,7 +638,16 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, break; case Instruction::ICmp: case Instruction::FCmp: - Code = bitc::CST_CODE_CE_CMP; + case Instruction::VICmp: + case Instruction::VFCmp: + if (isa(C->getOperand(0)->getType()) + && (CE->getOpcode() == Instruction::ICmp + || CE->getOpcode() == Instruction::FCmp)) { + // compare returning vector of Int1Ty + assert(0 && "Unsupported constant!"); + } else { + Code = bitc::CST_CODE_CE_CMP; + } Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); Record.push_back(VE.getValueID(C->getOperand(0))); Record.push_back(VE.getValueID(C->getOperand(1))); @@ -647,13 +708,15 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, default: if (Instruction::isCast(I.getOpcode())) { Code = bitc::FUNC_CODE_INST_CAST; - PushValueAndType(I.getOperand(0), InstID, Vals, VE); + if (!PushValueAndType(I.getOperand(0), InstID, Vals, VE)) + AbbrevToUse = FUNCTION_INST_CAST_ABBREV; Vals.push_back(VE.getTypeID(I.getType())); Vals.push_back(GetEncodedCastOpcode(I.getOpcode())); } else { assert(isa(I) && "Unknown instruction!"); Code = bitc::FUNC_CODE_INST_BINOP; - PushValueAndType(I.getOperand(0), InstID, Vals, VE); + if (!PushValueAndType(I.getOperand(0), InstID, Vals, VE)) + AbbrevToUse = FUNCTION_INST_BINOP_ABBREV; Vals.push_back(VE.getValueID(I.getOperand(1))); Vals.push_back(GetEncodedBinaryOpcode(I.getOpcode())); } @@ -664,11 +727,28 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) PushValueAndType(I.getOperand(i), InstID, Vals, VE); break; + case Instruction::ExtractValue: { + Code = bitc::FUNC_CODE_INST_EXTRACTVAL; + PushValueAndType(I.getOperand(0), InstID, Vals, VE); + const ExtractValueInst *EVI = cast(&I); + for (const unsigned *i = EVI->idx_begin(), *e = EVI->idx_end(); i != e; ++i) + Vals.push_back(*i); + break; + } + case Instruction::InsertValue: { + Code = bitc::FUNC_CODE_INST_INSERTVAL; + PushValueAndType(I.getOperand(0), InstID, Vals, VE); + PushValueAndType(I.getOperand(1), InstID, Vals, VE); + const InsertValueInst *IVI = cast(&I); + for (const unsigned *i = IVI->idx_begin(), *e = IVI->idx_end(); i != e; ++i) + Vals.push_back(*i); + break; + } case Instruction::Select: - Code = bitc::FUNC_CODE_INST_SELECT; + Code = bitc::FUNC_CODE_INST_VSELECT; PushValueAndType(I.getOperand(1), InstID, Vals, VE); Vals.push_back(VE.getValueID(I.getOperand(2))); - Vals.push_back(VE.getValueID(I.getOperand(0))); + PushValueAndType(I.getOperand(0), InstID, Vals, VE); break; case Instruction::ExtractElement: Code = bitc::FUNC_CODE_INST_EXTRACTELT; @@ -689,16 +769,34 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, break; case Instruction::ICmp: case Instruction::FCmp: - Code = bitc::FUNC_CODE_INST_CMP; + case Instruction::VICmp: + case Instruction::VFCmp: + if (I.getOpcode() == Instruction::ICmp + || I.getOpcode() == Instruction::FCmp) { + // compare returning Int1Ty or vector of Int1Ty + Code = bitc::FUNC_CODE_INST_CMP2; + } else { + Code = bitc::FUNC_CODE_INST_CMP; + } PushValueAndType(I.getOperand(0), InstID, Vals, VE); Vals.push_back(VE.getValueID(I.getOperand(1))); Vals.push_back(cast(I).getPredicate()); break; - case Instruction::Ret: - Code = bitc::FUNC_CODE_INST_RET; - if (I.getNumOperands()) - PushValueAndType(I.getOperand(0), InstID, Vals, VE); + case Instruction::Ret: + { + Code = bitc::FUNC_CODE_INST_RET; + unsigned NumOperands = I.getNumOperands(); + if (NumOperands == 0) + AbbrevToUse = FUNCTION_INST_RET_VOID_ABBREV; + else if (NumOperands == 1) { + if (!PushValueAndType(I.getOperand(0), InstID, Vals, VE)) + AbbrevToUse = FUNCTION_INST_RET_VAL_ABBREV; + } else { + for (unsigned i = 0, e = NumOperands; i != e; ++i) + PushValueAndType(I.getOperand(i), InstID, Vals, VE); + } + } break; case Instruction::Br: Code = bitc::FUNC_CODE_INST_BR; @@ -715,15 +813,18 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Vals.push_back(VE.getValueID(I.getOperand(i))); break; case Instruction::Invoke: { + const PointerType *PTy = cast(I.getOperand(0)->getType()); + const FunctionType *FTy = cast(PTy->getElementType()); Code = bitc::FUNC_CODE_INST_INVOKE; - Vals.push_back(cast(I).getCallingConv()); + + const InvokeInst *II = cast(&I); + Vals.push_back(VE.getParamAttrID(II->getParamAttrs())); + Vals.push_back(II->getCallingConv()); Vals.push_back(VE.getValueID(I.getOperand(1))); // normal dest Vals.push_back(VE.getValueID(I.getOperand(2))); // unwind dest PushValueAndType(I.getOperand(0), InstID, Vals, VE); // callee // Emit value #'s for the fixed parameters. - const PointerType *PTy = cast(I.getOperand(0)->getType()); - const FunctionType *FTy = cast(PTy->getElementType()); for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) Vals.push_back(VE.getValueID(I.getOperand(i+3))); // fixed param. @@ -740,6 +841,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, break; case Instruction::Unreachable: Code = bitc::FUNC_CODE_INST_UNREACHABLE; + AbbrevToUse = FUNCTION_INST_UNREACHABLE_ABBREV; break; case Instruction::PHI: @@ -777,21 +879,24 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Vals.push_back(cast(I).isVolatile()); break; case Instruction::Store: - Code = bitc::FUNC_CODE_INST_STORE; - PushValueAndType(I.getOperand(0), InstID, Vals, VE); // val. - Vals.push_back(VE.getValueID(I.getOperand(1))); // ptr. + Code = bitc::FUNC_CODE_INST_STORE2; + PushValueAndType(I.getOperand(1), InstID, Vals, VE); // ptrty + ptr + Vals.push_back(VE.getValueID(I.getOperand(0))); // val. Vals.push_back(Log2_32(cast(I).getAlignment())+1); Vals.push_back(cast(I).isVolatile()); break; case Instruction::Call: { + const PointerType *PTy = cast(I.getOperand(0)->getType()); + const FunctionType *FTy = cast(PTy->getElementType()); + Code = bitc::FUNC_CODE_INST_CALL; - Vals.push_back((cast(I).getCallingConv() << 1) | - cast(I).isTailCall()); - PushValueAndType(I.getOperand(0), InstID, Vals, VE); // Callee + + const CallInst *CI = cast(&I); + Vals.push_back(VE.getParamAttrID(CI->getParamAttrs())); + Vals.push_back((CI->getCallingConv() << 1) | unsigned(CI->isTailCall())); + PushValueAndType(CI->getOperand(0), InstID, Vals, VE); // Callee // Emit value #'s for the fixed parameters. - const PointerType *PTy = cast(I.getOperand(0)->getType()); - const FunctionType *FTy = cast(PTy->getElementType()); for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) Vals.push_back(VE.getValueID(I.getOperand(i+1))); // fixed param. @@ -877,7 +982,7 @@ static void WriteValueSymbolTable(const ValueSymbolTable &VST, /// WriteFunction - Emit a function body to the module stream. static void WriteFunction(const Function &F, ValueEnumerator &VE, BitstreamWriter &Stream) { - Stream.EnterSubblock(bitc::FUNCTION_BLOCK_ID, 3); + Stream.EnterSubblock(bitc::FUNCTION_BLOCK_ID, 4); VE.incorporateFunction(F); SmallVector Vals; @@ -888,8 +993,6 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE, Stream.EmitRecord(bitc::FUNC_CODE_DECLAREBLOCKS, Vals); Vals.clear(); - // FIXME: Function attributes? - // If there are function-local constants, emit them now. unsigned CstStart, CstEnd; VE.getFunctionConstantRange(CstStart, CstEnd); @@ -1056,6 +1159,50 @@ static void WriteBlockInfo(const ValueEnumerator &VE, BitstreamWriter &Stream) { Abbv) != FUNCTION_INST_LOAD_ABBREV) assert(0 && "Unexpected abbrev ordering!"); } + { // INST_BINOP abbrev for FUNCTION_BLOCK. + BitCodeAbbrev *Abbv = new 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, + Abbv) != FUNCTION_INST_BINOP_ABBREV) + assert(0 && "Unexpected abbrev ordering!"); + } + { // INST_CAST abbrev for FUNCTION_BLOCK. + BitCodeAbbrev *Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpVal + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + Log2_32_Ceil(VE.getTypes().size()+1))); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, + Abbv) != FUNCTION_INST_CAST_ABBREV) + assert(0 && "Unexpected abbrev ordering!"); + } + + { // INST_RET abbrev for FUNCTION_BLOCK. + BitCodeAbbrev *Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, + Abbv) != FUNCTION_INST_RET_VOID_ABBREV) + assert(0 && "Unexpected abbrev ordering!"); + } + { // INST_RET abbrev for FUNCTION_BLOCK. + BitCodeAbbrev *Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ValID + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, + Abbv) != FUNCTION_INST_RET_VAL_ABBREV) + assert(0 && "Unexpected abbrev ordering!"); + } + { // INST_UNREACHABLE abbrev for FUNCTION_BLOCK. + BitCodeAbbrev *Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNREACHABLE)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, + Abbv) != FUNCTION_INST_UNREACHABLE_ABBREV) + assert(0 && "Unexpected abbrev ordering!"); + } Stream.ExitBlock(); } @@ -1115,6 +1262,70 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) { Stream.ExitBlock(); } +/// EmitDarwinBCHeader - If generating a bc file on darwin, we have to emit a +/// header and trailer to make it compatible with the system archiver. To do +/// this we emit the following header, and then emit a trailer that pads the +/// file out to be a multiple of 16 bytes. +/// +/// struct bc_header { +/// uint32_t Magic; // 0x0B17C0DE +/// uint32_t Version; // Version, currently always 0. +/// uint32_t BitcodeOffset; // Offset to traditional bitcode file. +/// uint32_t BitcodeSize; // Size of traditional bitcode file. +/// uint32_t CPUType; // CPU specifier. +/// ... potentially more later ... +/// }; +enum { + DarwinBCSizeFieldOffset = 3*4, // Offset to bitcode_size. + DarwinBCHeaderSize = 5*4 +}; + +static void EmitDarwinBCHeader(BitstreamWriter &Stream, + const std::string &TT) { + unsigned CPUType = ~0U; + + // Match x86_64-*, i[3-9]86-*, powerpc-*, powerpc64-*. The CPUType is a + // magic number from /usr/include/mach/machine.h. It is ok to reproduce the + // specific constants here because they are implicitly part of the Darwin ABI. + enum { + DARWIN_CPU_ARCH_ABI64 = 0x01000000, + DARWIN_CPU_TYPE_X86 = 7, + DARWIN_CPU_TYPE_POWERPC = 18 + }; + + if (TT.find("x86_64-") == 0) + CPUType = DARWIN_CPU_TYPE_X86 | DARWIN_CPU_ARCH_ABI64; + else if (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && + TT[4] == '-' && TT[1] - '3' < 6) + CPUType = DARWIN_CPU_TYPE_X86; + else if (TT.find("powerpc-") == 0) + CPUType = DARWIN_CPU_TYPE_POWERPC; + else if (TT.find("powerpc64-") == 0) + CPUType = DARWIN_CPU_TYPE_POWERPC | DARWIN_CPU_ARCH_ABI64; + + // Traditional Bitcode starts after header. + unsigned BCOffset = DarwinBCHeaderSize; + + Stream.Emit(0x0B17C0DE, 32); + Stream.Emit(0 , 32); // Version. + Stream.Emit(BCOffset , 32); + Stream.Emit(0 , 32); // Filled in later. + Stream.Emit(CPUType , 32); +} + +/// EmitDarwinBCTrailer - Emit the darwin epilog after the bitcode file and +/// finalize the header. +static void EmitDarwinBCTrailer(BitstreamWriter &Stream, unsigned BufferSize) { + // Update the size field in the header. + Stream.BackpatchWord(DarwinBCSizeFieldOffset, BufferSize-DarwinBCHeaderSize); + + // If the file is not a multiple of 16 bytes, insert dummy padding. + while (BufferSize & 15) { + Stream.Emit(0, 8); + ++BufferSize; + } +} + /// WriteBitcodeToFile - Write the specified module to the specified output /// stream. @@ -1124,6 +1335,11 @@ void llvm::WriteBitcodeToFile(const Module *M, std::ostream &Out) { Buffer.reserve(256*1024); + // If this is darwin, emit a file header and trailer if needed. + bool isDarwin = M->getTargetTriple().find("-darwin") != std::string::npos; + if (isDarwin) + EmitDarwinBCHeader(Stream, M->getTargetTriple()); + // Emit the file header. Stream.Emit((unsigned)'B', 8); Stream.Emit((unsigned)'C', 8); @@ -1134,7 +1350,18 @@ void llvm::WriteBitcodeToFile(const Module *M, std::ostream &Out) { // Emit the module. WriteModule(M, Stream); + + if (isDarwin) + EmitDarwinBCTrailer(Stream, Buffer.size()); + + // If writing to stdout, set binary mode. + if (llvm::cout == Out) + sys::Program::ChangeStdoutToBinary(); + // Write the generated bitstream to "Out". Out.write((char*)&Buffer.front(), Buffer.size()); + + // Make sure it hits disk now. + Out.flush(); }