bool Encode(uchar symbol, Output& result) { if(symbol == ' ') { LoadFromAddress(AddressOf(Space), result); return true; } if(!ConvertSymbol(symbol, symbol)) { return false; } LoadFromAddress(AddressOf(MorseTable[symbol - '0']), result); return true; }
Operand* ConstantFolder::HandleLoad(Operand* sourceOp) { // Handle cases when we know the result is undefined. // load undef -> undef // load nullptr -> undef if(sourceOp->IsUndefinedConstant()) { return sourceOp; } else if(sourceOp->IsNullConstant()) { return GetUndefined(sourceOp); } // Handle first the simple cases when we load directly from a global variable. auto loadType = sourceOp->GetType()->As<PointerType>()->PointeeType(); if(auto variableRef = sourceOp->IsVariableReference()) { return LoadFromGlobal(sourceOp, loadType, 0 /* start offset */); } // Try to load from an 'addr', 'index' or 'elem' instruction that index into // a global variable (for example, 'a[i]', 'a.b', 'a.c[i].d', '*(p + 2)', etc.). return LoadFromAddress(sourceOp, loadType, 0 /* start offset */); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Operand* ConstantFolder::LoadFromAddress(Operand* op, const Type* loadType, __int64 offset) { // If the operand has a defining instruction then we try to compute // the offset from which we should load. If it's a variable reference // we try to load from the offset that was already computed. if(op->HasDefiningInstruction() == false) { return LoadFromGlobal(op, loadType, offset); } auto instr = op->DefiningInstruction(); switch(instr->GetOpcode()) { case Instr_Index: { // If the index operand is not a constant give up. auto indexInstr = instr->As<IndexInstr>(); auto indexConst = indexInstr->IndexOp()->As<IntConstant>(); if(indexConst == nullptr) { return nullptr; } // The type of the base is 'pointer-to-array', so we need to strip the pointer. auto elementType = indexInstr->GetElementType(); __int64 index = indexConst->Value(); __int64 elemSize = TypeInfo::GetSize(elementType, target_); // The offset is incremented by the index multiplied with the element size. __int64 newOffset = offset + (index * elemSize); return LoadFromAddress(indexInstr->BaseOp(), loadType, newOffset); } case Instr_Element: { auto elemInstr = instr->As<ElementInstr>(); __int64 index = elemInstr->GetFieldIndex(); // The type of the base is 'pointer-to-record', // so we need to strip the pointer. auto recordType = elemInstr->GetRecordType(); // Obtain the offset of the selected field. // The new offset is the old one added with the field offset. __int64 fieldOffset = recordType->Fields()[index].FieldOffset; __int64 newOffset = offset + fieldOffset; return LoadFromAddress(elemInstr->BaseOp(), loadType, newOffset); } case Instr_Address: { // If the index operand is not a constant give up. auto addrInstr = instr->As<AddressInstr>(); auto indexConst = addrInstr->IndexOp()->As<IntConstant>(); if(indexConst == nullptr) { return nullptr; } // The type of the base is 'pointer-to-object', // so we need to strip the pointer. auto objectType = addrInstr->GetPointeeType(); __int64 index = indexConst->Value(); __int64 elemSize = TypeInfo::GetSize(objectType, target_); // The offset is incremented by the index multiplied with the object size. __int64 newOffset = offset + (index * elemSize); return LoadFromAddress(addrInstr->BaseOp(), loadType, newOffset); } case Instr_Ptop: { // This instruction is ignored (the previous recursion step // has already taken care about its effects). auto ptopInstr = instr->As<PtopInstr>(); auto targetInstr = ptopInstr->TargetOp()->DefiningInstruction(); return LoadFromAddress(ptopInstr->TargetOp(), loadType, offset); } case Instr_Load: { // This happens when the variable is a pointer. auto loadInstr = instr->As<LoadInstr>(); return LoadFromAddress(loadInstr->SourceOp(), loadType, offset); } default: { // All other cases don't lead to a constant operand. return nullptr; } } }