X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FBytecode%2FWriter%2FInstructionWriter.cpp;h=faa576ecb46592e02501f403b8f66045eee41cd4;hb=b576c94c15af9a440f69d9d03c2afead7971118c;hp=c7c04efb731bd5b6fd791ab4e22e3d592a3e2c15;hpb=009505452b713ed2e3a8e99c5545a6e721c65495;p=oota-llvm.git diff --git a/lib/Bytecode/Writer/InstructionWriter.cpp b/lib/Bytecode/Writer/InstructionWriter.cpp index c7c04efb731..faa576ecb46 100644 --- a/lib/Bytecode/Writer/InstructionWriter.cpp +++ b/lib/Bytecode/Writer/InstructionWriter.cpp @@ -1,23 +1,27 @@ -//===-- WriteInst.cpp - Functions for writing instructions -------*- C++ -*--=// +//===-- InstructionWriter.cpp - Functions for writing instructions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// // // This file implements the routines for encoding instruction opcodes to a // bytecode stream. // -// Note that the performance of this library is not terribly important, because -// it shouldn't be used by JIT type applications... so it is not a huge focus -// at least. :) -// //===----------------------------------------------------------------------===// #include "WriterInternals.h" #include "llvm/Module.h" -#include "llvm/Method.h" -#include "llvm/BasicBlock.h" -#include "llvm/Instruction.h" #include "llvm/DerivedTypes.h" -#include "llvm/Tools/DataTypes.h" +#include "llvm/Instructions.h" +#include "Support/Statistic.h" #include +static Statistic<> +NumInstrs("bytecodewriter", "Number of instructions"); + typedef unsigned char uchar; // outputInstructionFormat0 - Output those wierd instructions that have a large @@ -25,21 +29,88 @@ typedef unsigned char uchar; // // Format: [opcode] [type] [numargs] [arg0] [arg1] ... [arg] // -static void outputInstructionFormat0(const Instruction *I, +static void outputInstructionFormat0(const Instruction *I, unsigned Opcode, const SlotCalculator &Table, - unsigned Type, vector &Out) { + unsigned Type, std::deque &Out) { // Opcode must have top two bits clear... - output_vbr(I->getInstType(), Out); // Instruction Opcode ID + output_vbr(Opcode << 2, Out); // Instruction Opcode ID output_vbr(Type, Out); // Result type - unsigned NumArgs; // Count the number of arguments to the instruction - for (NumArgs = 0; I->getOperand(NumArgs); NumArgs++) /*empty*/; - output_vbr(NumArgs, Out); + unsigned NumArgs = I->getNumOperands(); + output_vbr(NumArgs + (isa(I) || isa(I) || + isa(I)), Out); - for (unsigned i = 0; const Value *N = I->getOperand(i); i++) { - assert(i < NumArgs && "Count of arguments failed!"); + for (unsigned i = 0; i < NumArgs; ++i) { + int Slot = Table.getSlot(I->getOperand(i)); + assert(Slot >= 0 && "No slot number for value!?!?"); + output_vbr((unsigned)Slot, Out); + } - int Slot = Table.getValSlot(N); + if (isa(I) || isa(I)) { + int Slot = Table.getSlot(I->getType()); + assert(Slot != -1 && "Cast return type unknown?"); + output_vbr((unsigned)Slot, Out); + } else if (const VANextInst *VAI = dyn_cast(I)) { + int Slot = Table.getSlot(VAI->getArgType()); + assert(Slot != -1 && "VarArg argument type unknown?"); + output_vbr((unsigned)Slot, Out); + } + + align32(Out); // We must maintain correct alignment! +} + + +// outputInstrVarArgsCall - Output the absurdly annoying varargs function calls. +// This are more annoying than most because the signature of the call does not +// tell us anything about the types of the arguments in the varargs portion. +// Because of this, we encode (as type 0) all of the argument types explicitly +// before the argument value. This really sucks, but you shouldn't be using +// varargs functions in your code! *death to printf*! +// +// Format: [opcode] [type] [numargs] [arg0] [arg1] ... [arg] +// +static void outputInstrVarArgsCall(const Instruction *I, unsigned Opcode, + const SlotCalculator &Table, unsigned Type, + std::deque &Out) { + assert(isa(I) || isa(I)); + // Opcode must have top two bits clear... + output_vbr(Opcode << 2, Out); // Instruction Opcode ID + output_vbr(Type, Out); // Result type (varargs type) + + const PointerType *PTy = cast(I->getOperand(0)->getType()); + const FunctionType *FTy = cast(PTy->getElementType()); + unsigned NumParams = FTy->getNumParams(); + + unsigned NumFixedOperands; + if (isa(I)) { + // Output an operand for the callee and each fixed argument, then two for + // each variable argument. + NumFixedOperands = 1+NumParams; + } else { + assert(isa(I) && "Not call or invoke??"); + // Output an operand for the callee and destinations, then two for each + // variable argument. + NumFixedOperands = 3+NumParams; + } + output_vbr(2 * I->getNumOperands()-NumFixedOperands, Out); + + // The type for the function has already been emitted in the type field of the + // instruction. Just emit the slot # now. + for (unsigned i = 0; i != NumFixedOperands; ++i) { + int Slot = Table.getSlot(I->getOperand(i)); + assert(Slot >= 0 && "No slot number for value!?!?"); + output_vbr((unsigned)Slot, Out); + } + + for (unsigned i = NumFixedOperands, e = I->getNumOperands(); i != e; ++i) { + // Output Arg Type ID + int Slot = Table.getSlot(I->getOperand(i)->getType()); + assert(Slot >= 0 && "No slot number for value!?!?"); + output_vbr((unsigned)Slot, Out); + + // Output arg ID itself + Slot = Table.getSlot(I->getOperand(i)); + assert(Slot >= 0 && "No slot number for value!?!?"); output_vbr((unsigned)Slot, Out); } align32(Out); // We must maintain correct alignment! @@ -49,86 +120,86 @@ static void outputInstructionFormat0(const Instruction *I, // outputInstructionFormat1 - Output one operand instructions, knowing that no // operand index is >= 2^12. // -static void outputInstructionFormat1(const Instruction *I, +static void outputInstructionFormat1(const Instruction *I, unsigned Opcode, const SlotCalculator &Table, int *Slots, - unsigned Type, vector &Out) { - unsigned IType = I->getInstType(); // Instruction Opcode ID - + unsigned Type, std::deque &Out) { // bits Instruction format: // -------------------------- - // 31-30: Opcode type, fixed to 1. - // 29-24: Opcode - // 23-12: Resulting type plane - // 11- 0: Operand #1 (if set to (2^12-1), then zero operands) + // 01-00: Opcode type, fixed to 1. + // 07-02: Opcode + // 19-08: Resulting type plane + // 31-20: Operand #1 (if set to (2^12-1), then zero operands) // - unsigned Opcode = (1 << 30) | (IType << 24) | (Type << 12) | Slots[0]; + unsigned Bits = 1 | (Opcode << 2) | (Type << 8) | (Slots[0] << 20); // cerr << "1 " << IType << " " << Type << " " << Slots[0] << endl; - output(Opcode, Out); + output(Bits, Out); } // outputInstructionFormat2 - Output two operand instructions, knowing that no // operand index is >= 2^8. // -static void outputInstructionFormat2(const Instruction *I, +static void outputInstructionFormat2(const Instruction *I, unsigned Opcode, const SlotCalculator &Table, int *Slots, - unsigned Type, vector &Out) { - unsigned IType = I->getInstType(); // Instruction Opcode ID - + unsigned Type, std::deque &Out) { // bits Instruction format: // -------------------------- - // 31-30: Opcode type, fixed to 2. - // 29-24: Opcode - // 23-16: Resulting type plane - // 15- 8: Operand #1 - // 7- 0: Operand #2 + // 01-00: Opcode type, fixed to 2. + // 07-02: Opcode + // 15-08: Resulting type plane + // 23-16: Operand #1 + // 31-24: Operand #2 // - unsigned Opcode = (2 << 30) | (IType << 24) | (Type << 16) | - (Slots[0] << 8) | (Slots[1] << 0); + unsigned Bits = 2 | (Opcode << 2) | (Type << 8) | + (Slots[0] << 16) | (Slots[1] << 24); // cerr << "2 " << IType << " " << Type << " " << Slots[0] << " " // << Slots[1] << endl; - output(Opcode, Out); + output(Bits, Out); } // outputInstructionFormat3 - Output three operand instructions, knowing that no // operand index is >= 2^6. // -static void outputInstructionFormat3(const Instruction *I, +static void outputInstructionFormat3(const Instruction *I, unsigned Opcode, const SlotCalculator &Table, int *Slots, - unsigned Type, vector &Out) { - unsigned IType = I->getInstType(); // Instruction Opcode ID - + unsigned Type, std::deque &Out) { // bits Instruction format: // -------------------------- - // 31-30: Opcode type, fixed to 3 - // 29-24: Opcode - // 23-18: Resulting type plane - // 17-12: Operand #1 - // 11- 6: Operand #2 - // 5- 0: Operand #3 + // 01-00: Opcode type, fixed to 3. + // 07-02: Opcode + // 13-08: Resulting type plane + // 19-14: Operand #1 + // 25-20: Operand #2 + // 31-26: Operand #3 // - unsigned Opcode = (3 << 30) | (IType << 24) | (Type << 18) | - (Slots[0] << 12) | (Slots[1] << 6) | (Slots[2] << 0); - // cerr << "3 " << IType << " " << Type << " " << Slots[0] << " " - // << Slots[1] << " " << Slots[2] << endl; - output(Opcode, Out); + unsigned Bits = 3 | (Opcode << 2) | (Type << 8) | + (Slots[0] << 14) | (Slots[1] << 20) | (Slots[2] << 26); + //cerr << "3 " << IType << " " << Type << " " << Slots[0] << " " + // << Slots[1] << " " << Slots[2] << endl; + output(Bits, Out); } -bool BytecodeWriter::processInstruction(const Instruction *I) { - assert(I->getInstType() < 64 && "Opcode too big???"); +void BytecodeWriter::processInstruction(const Instruction &I) { + assert(I.getOpcode() < 62 && "Opcode too big???"); + unsigned Opcode = I.getOpcode(); - unsigned NumOperands = 0; + // Encode 'volatile load' as 62 and 'volatile store' as 63. + if (isa(I) && cast(I).isVolatile()) + Opcode = 62; + if (isa(I) && cast(I).isVolatile()) + Opcode = 63; + + unsigned NumOperands = I.getNumOperands(); int MaxOpSlot = 0; - int Slots[3]; Slots[0] = (1 << 12)-1; + int Slots[3]; Slots[0] = (1 << 12)-1; // Marker to signify 0 operands - const Value *Def; - while ((Def = I->getOperand(NumOperands))) { - int slot = Table.getValSlot(Def); + for (unsigned i = 0; i < NumOperands; ++i) { + const Value *Def = I.getOperand(i); + int slot = Table.getSlot(Def); assert(slot != -1 && "Broken bytecode!"); if (slot > MaxOpSlot) MaxOpSlot = slot; - if (NumOperands < 3) Slots[NumOperands] = slot; - NumOperands++; + if (i < 3) Slots[i] = slot; } // Figure out which type to encode with the instruction. Typically we want @@ -137,18 +208,59 @@ bool BytecodeWriter::processInstruction(const Instruction *I) { // the first param is actually interesting). But if we have no arguments // we take the type of the instruction itself. // - const Type *Ty; - if (NumOperands) - Ty = I->getOperand(0)->getType(); - else - Ty = I->getType(); + switch (I.getOpcode()) { + case Instruction::Malloc: + case Instruction::Alloca: + Ty = I.getType(); // Malloc & Alloca ALWAYS want to encode the return type + break; + case Instruction::Store: + Ty = I.getOperand(1)->getType(); // Encode the pointer type... + assert(isa(Ty) && "Store to nonpointer type!?!?"); + break; + default: // Otherwise use the default behavior... + Ty = NumOperands ? I.getOperand(0)->getType() : I.getType(); + break; + } unsigned Type; - int Slot = Table.getValSlot(Ty); + int Slot = Table.getSlot(Ty); assert(Slot != -1 && "Type not available!!?!"); Type = (unsigned)Slot; + // Make sure that we take the type number into consideration. We don't want + // to overflow the field size for the instruction format we select. + // + if (Slot > MaxOpSlot) MaxOpSlot = Slot; + + // Handle the special case for cast... + if (isa(I) || isa(I)) { + // Cast has to encode the destination type as the second argument in the + // packet, or else we won't know what type to cast to! + Slots[1] = Table.getSlot(I.getType()); + assert(Slots[1] != -1 && "Cast return type unknown?"); + if (Slots[1] > MaxOpSlot) MaxOpSlot = Slots[1]; + NumOperands++; + } else if (const VANextInst *VANI = dyn_cast(&I)) { + Slots[1] = Table.getSlot(VANI->getArgType()); + assert(Slots[1] != -1 && "va_next return type unknown?"); + if (Slots[1] > MaxOpSlot) MaxOpSlot = Slots[1]; + NumOperands++; + } else if (const CallInst *CI = dyn_cast(&I)){// Handle VarArg calls + const PointerType *Ty = cast(CI->getCalledValue()->getType()); + if (cast(Ty->getElementType())->isVarArg()) { + outputInstrVarArgsCall(CI, Opcode, Table, Type, Out); + return; + } + } else if (const InvokeInst *II = dyn_cast(&I)) {// ... & Invokes + const PointerType *Ty = cast(II->getCalledValue()->getType()); + if (cast(Ty->getElementType())->isVarArg()) { + outputInstrVarArgsCall(II, Opcode, Table, Type, Out); + return; + } + } + + ++NumInstrs; // Decide which instruction encoding to use. This is determined primarily by // the number of operands, and secondarily by whether or not the max operand @@ -159,26 +271,27 @@ bool BytecodeWriter::processInstruction(const Instruction *I) { case 0: case 1: if (MaxOpSlot < (1 << 12)-1) { // -1 because we use 4095 to indicate 0 ops - outputInstructionFormat1(I, Table, Slots, Type, Out); - return false; + outputInstructionFormat1(&I, Opcode, Table, Slots, Type, Out); + return; } break; case 2: if (MaxOpSlot < (1 << 8)) { - outputInstructionFormat2(I, Table, Slots, Type, Out); - return false; + outputInstructionFormat2(&I, Opcode, Table, Slots, Type, Out); + return; } break; case 3: if (MaxOpSlot < (1 << 6)) { - outputInstructionFormat3(I, Table, Slots, Type, Out); - return false; + outputInstructionFormat3(&I, Opcode, Table, Slots, Type, Out); + return; } break; } - outputInstructionFormat0(I, Table, Type, Out); - return false; + // If we weren't handled before here, we either have a large number of + // operands or a large operand index that we are referring to. + outputInstructionFormat0(&I, Opcode, Table, Type, Out); }