handle function-level forward references, read binops.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@36620 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2007-05-01 07:01:57 +00:00
parent 6f7c8ffd9a
commit a7c49aac98
2 changed files with 145 additions and 20 deletions

View File

@ -15,6 +15,7 @@
#include "BitcodeReader.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MathExtras.h"
@ -125,10 +126,9 @@ Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
NumOperands = Idx+1;
}
if (Uses[Idx]) {
assert(Ty == getOperand(Idx)->getType() &&
"Type mismatch in constant table!");
return cast<Constant>(getOperand(Idx));
if (Value *V = Uses[Idx]) {
assert(Ty == V->getType() && "Type mismatch in constant table!");
return cast<Constant>(V);
}
// Create and return a placeholder, which will later be RAUW'd.
@ -137,6 +137,25 @@ Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
return C;
}
Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, const Type *Ty) {
if (Idx >= size()) {
// Insert a bunch of null values.
Uses.resize(Idx+1);
OperandList = &Uses[0];
NumOperands = Idx+1;
}
if (Value *V = Uses[Idx]) {
assert((Ty == 0 || Ty == V->getType()) && "Type mismatch in value table!");
return V;
}
// Create and return a placeholder, which will later be RAUW'd.
Value *V = new Argument(Ty);
Uses[Idx].init(V, this);
return V;
}
const Type *BitcodeReader::getTypeByID(unsigned ID, bool isTypeTable) {
// If the TypeID is in range, return it.
@ -151,7 +170,6 @@ const Type *BitcodeReader::getTypeByID(unsigned ID, bool isTypeTable) {
return TypeList.back().get();
}
bool BitcodeReader::ParseTypeTable() {
if (Stream.EnterSubBlock())
return Error("Malformed block record");
@ -643,18 +661,7 @@ bool BitcodeReader::ParseConstants() {
}
}
if (NextCstNo == ValueList.size())
ValueList.push_back(V);
else if (ValueList[NextCstNo] == 0)
ValueList.initVal(NextCstNo, V);
else {
// If there was a forward reference to this constant,
Value *OldV = ValueList[NextCstNo];
ValueList.setOperand(NextCstNo, V);
OldV->replaceAllUsesWith(V);
delete OldV;
}
ValueList.AssignValue(V, NextCstNo);
++NextCstNo;
}
}
@ -998,6 +1005,8 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I)
ValueList.push_back(I);
unsigned NextValueNo = ValueList.size();
// Read all the records.
SmallVector<uint64_t, 64> Record;
while (1) {
@ -1016,6 +1025,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
break;
case bitc::CONSTANTS_BLOCK_ID:
if (ParseConstants()) return true;
NextValueNo = ValueList.size();
break;
case bitc::VALUE_SYMTAB_BLOCK_ID:
if (ParseValueSymbolTable()) return true;
@ -1031,19 +1041,115 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
// Read a record.
Record.clear();
Instruction *I = 0;
BasicBlock *CurBB = 0;
unsigned CurBBNo = 0;
switch (Stream.ReadRecord(Code, Record)) {
default: // Default behavior: unknown constant
default: // Default behavior: reject
return Error("Unknown instruction");
case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks]
if (Record.size() < 1)
return Error("Invalid FUNC_CODE_DECLAREBLOCKS record");
if (Record.size() < 1 || Record[0] == 0)
return Error("Invalid DECLAREBLOCKS record");
// Create all the basic blocks for the function.
FunctionBBs.resize(Record.size());
for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i)
FunctionBBs[i] = new BasicBlock("", F);
CurBB = FunctionBBs[0];
continue;
case bitc::FUNC_CODE_INST_BINOP: {
// BINOP: [opcode, ty, opval, opval]
if (Record.size() < 4) return Error("Invalid BINOP record");
const Type *Ty = getTypeByID(Record[1]);
int Opc = GetDecodedBinaryOpcode(Record[0], Ty);
Value *LHS = getFnValueByID(Record[2], Ty);
Value *RHS = getFnValueByID(Record[3], Ty);
if (Opc == -1 || Ty == 0 || LHS == 0 || RHS == 0)
return Error("Invalid BINOP record");
I = BinaryOperator::create((Instruction::BinaryOps)Opc, LHS, RHS);
break;
}
#if 0
case bitc::FUNC_CODE_INST_CAST:
// CAST: [opcode, ty, opty, opval]
case bitc::FUNC_CODE_INST_GEP:
// GEP: [n, n x operands]
case bitc::FUNC_CODE_INST_SELECT:
// SELECT: [ty, opval, opval, opval]
case bitc::FUNC_CODE_INST_EXTRACTELT:
// EXTRACTELT: [opty, opval, opval]
case bitc::FUNC_CODE_INST_INSERTELT:
// INSERTELT: [ty, opval, opval, opval]
case bitc::FUNC_CODE_INST_SHUFFLEVEC:
// SHUFFLEVEC: [ty, opval, opval, opval]
case bitc::FUNC_CODE_INST_CMP:
// CMP: [opty, opval, opval, pred]
case bitc::FUNC_CODE_INST_RET:
// RET: [opty,opval<optional>]
case bitc::FUNC_CODE_INST_BR:
// BR: [opval, bb#, bb#] or [bb#]
case bitc::FUNC_CODE_INST_SWITCH:
// SWITCH: [opty, opval, n, n x ops]
case bitc::FUNC_CODE_INST_INVOKE:
// INVOKE: [fnty, op0,op1,op2, ...]
case bitc::FUNC_CODE_INST_UNWIND:
// UNWIND
case bitc::FUNC_CODE_INST_UNREACHABLE:
// UNREACHABLE
case bitc::FUNC_CODE_INST_PHI:
// PHI: [ty, #ops, val0,bb0, ...]
case bitc::FUNC_CODE_INST_MALLOC:
// MALLOC: [instty, op, align]
case bitc::FUNC_CODE_INST_FREE:
// FREE: [opty, op]
case bitc::FUNC_CODE_INST_ALLOCA:
// ALLOCA: [instty, op, align]
case bitc::FUNC_CODE_INST_LOAD:
// LOAD: [opty, op, align, vol]
case bitc::FUNC_CODE_INST_STORE:
// STORE: [ptrty,val,ptr, align, vol]
case bitc::FUNC_CODE_INST_CALL:
// CALL: [fnty, fnid, arg0, arg1...]
case bitc::FUNC_CODE_INST_VAARG:
// VAARG: [valistty, valist, instty]
break;
#endif
}
// Add instruction to end of current BB. If there is no current BB, reject
// this file.
if (CurBB == 0) {
delete I;
return Error("Invalid instruction with no BB");
}
CurBB->getInstList().push_back(I);
// If this was a terminator instruction, move to the next block.
if (isa<TerminatorInst>(I)) {
++CurBBNo;
CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : 0;
}
// Non-void values get registered in the value table for future use.
if (I && I->getType() != Type::VoidTy)
ValueList.AssignValue(I, NextValueNo++);
}
// Check the function list for unresolved values.
if (Argument *A = dyn_cast<Argument>(ValueList.back())) {
if (A->getParent() == 0) {
// We found at least one unresolved value. Nuke them all to avoid leaks.
for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){
if ((A = dyn_cast<Argument>(ValueList.back())) && A->getParent() == 0) {
A->replaceAllUsesWith(UndefValue::get(A->getType()));
delete A;
}
}
}
return Error("Never resolved value found in function!");
}
// Trim the value list down to the size it was before we parsed this function.
ValueList.shrinkTo(ModuleValueListSize);

View File

@ -51,6 +51,22 @@ public:
virtual void print(std::ostream&) const {}
Constant *getConstantFwdRef(unsigned Idx, const Type *Ty);
Value *getValueFwdRef(unsigned Idx, const Type *Ty);
void AssignValue(Value *V, unsigned Idx) {
if (Idx == size()) {
push_back(V);
} else if (Value *OldV = getOperand(Idx)) {
// If there was a forward reference to this value, replace it.
setOperand(Idx, V);
OldV->replaceAllUsesWith(V);
delete OldV;
} else {
initVal(Idx, V);
}
}
private:
void initVal(unsigned Idx, Value *V) {
assert(Uses[Idx] == 0 && "Cannot init an already init'd Use!");
Uses[Idx].init(V, this);
@ -113,6 +129,9 @@ public:
bool ParseBitcode();
private:
const Type *getTypeByID(unsigned ID, bool isTypeTable = false);
Value *getFnValueByID(unsigned ID, const Type *Ty) {
return ValueList.getValueFwdRef(ID, Ty);
}
bool ParseModule(const std::string &ModuleID);
bool ParseTypeTable();