<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

IR::Instr *Lowerer::PreLowerPeepInstr(IR::Instr *instr, IR::Instr **pInstrPrev)
{
    if (PHASE_OFF(Js::PreLowererPeepsPhase, this->m_func))
    {
        return instr;
    }

    switch (instr->m_opcode)
    {
#if defined(_M_IX86) || defined(_M_X64)
        // this sort of addressing mode magic only applies to x86 platforms
    case Js::OpCode::Add_I4:
        instr = this->PeepShiftAdd(instr);
        *pInstrPrev = instr->m_prev;
        break;
#endif
    case Js::OpCode::Shl_I4:
        instr = this->PeepShl(instr);
        *pInstrPrev = instr->m_prev;
        break;

    case Js::OpCode::BrTrue_I4:
    case Js::OpCode::BrFalse_I4:
        instr = this->PeepBrBool(instr);
        *pInstrPrev = instr->m_prev;
        break;
    }

    return instr;
}

IR::Instr *
Lowerer::TryShiftAdd(IR::Instr *instrAdd, IR::Opnd * opndFold, IR::Opnd * opndAdd)
{
    Assert(instrAdd->m_opcode == Js::OpCode::Add_I4);
    if (!opndFold->GetIsDead())
    {
        return instrAdd;
    }

    if (!(opndAdd->IsRegOpnd() || (opndAdd->IsInt32() && opndAdd->IsIntConstOpnd())))
    {
        return instrAdd;
    }

    if (!opndFold->IsRegOpnd() || !opndFold->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrAdd;
    }

    IR::Instr * instrDef = opndFold->AsRegOpnd()->m_sym->GetInstrDef();

    if ((instrDef->m_opcode != Js::OpCode::Shl_I4 && instrDef->m_opcode != Js::OpCode::Mul_I4) || !instrDef->GetSrc1()->IsRegOpnd()  || !instrDef->GetSrc2()->IsIntConstOpnd())
    {
        return instrAdd;
    }

    if (instrDef->HasBailOutInfo())
    {
        return instrAdd;
    }

    byte scale = 0;
    IntConstType constVal = instrDef->GetSrc2()->AsIntConstOpnd()->GetValue();
    if (instrDef->m_opcode == Js::OpCode::Shl_I4)
    {
        if (constVal < 0 || constVal > 3)
        {
            return instrAdd;
        }
        scale = (byte)constVal;
    }
    else
    {
        Assert(instrDef->m_opcode == Js::OpCode::Mul_I4);
        switch (constVal)
        {
        case 1:
            scale = 0;
            break;
        case 2:
            scale = 1;
            break;
        case 4:
            scale = 2;
            break;
        case 8:
            scale = 3;
            break;
        default:
            return instrAdd;
        }
    }

    StackSym * defSrc1Sym = instrDef->GetSrc1()->AsRegOpnd()->m_sym;
    StackSym * foldSym = opndFold->AsRegOpnd()->m_sym;
    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrAdd->m_prev)
    {
        // if any branch between def-use, don't do peeps on it because branch target might depend on the def
        if (instrIter->IsBranchInstr())
        {
            return instrAdd;
        }
        if (instrIter->HasBailOutInfo())
        {
            return instrAdd;
        }
        if (instrIter->FindRegDef(defSrc1Sym))
        {
            return instrAdd;
        }
        if (instrIter->FindRegUse(foldSym))
        {
            return instrAdd;
        }
    } NEXT_INSTR_IN_RANGE;

#if DBG_DUMP
    if (PHASE_TRACE(Js::PreLowererPeepsPhase, instrAdd->m_func))
    {
        Output::Print(_u("PeepShiftAdd : %s (%d) : folding:\n"), instrAdd->m_func->GetJITFunctionBody()->GetDisplayName(), instrAdd->m_func->GetFunctionNumber());
        instrDef->Dump();
        instrAdd->Dump();
    }
#endif

    IR::IndirOpnd * leaOpnd = nullptr;
    if (opndAdd->IsRegOpnd())
    {
        leaOpnd = IR::IndirOpnd::New(opndAdd->AsRegOpnd(), instrDef->UnlinkSrc1()->AsRegOpnd(), scale, opndFold->GetType(), instrAdd->m_func);
    }
    else
    {
        Assert(opndAdd->IsInt32() && opndAdd->IsIntConstOpnd());
        leaOpnd = IR::IndirOpnd::New(instrDef->UnlinkSrc1()->AsRegOpnd(), opndAdd->AsIntConstOpnd()->AsInt32(), scale, opndFold->GetType(), instrAdd->m_func);
    }

    IR::Instr * leaInstr = InsertLea(instrAdd->UnlinkDst()->AsRegOpnd(), leaOpnd, instrAdd);

#if DBG_DUMP
    if (PHASE_TRACE(Js::PreLowererPeepsPhase, instrAdd->m_func))
    {
        Output::Print(_u("into:\n"), instrAdd->m_func->GetJITFunctionBody()->GetDisplayName(), instrAdd->m_func->GetFunctionNumber());
        leaInstr->Dump();
    }
#endif

    instrAdd->Remove();
    instrDef->Remove();

    return leaInstr;
}

IR::Instr *
Lowerer::PeepShiftAdd(IR::Instr *instrAdd)
{
    Assert(instrAdd->m_opcode == Js::OpCode::Add_I4);

    // Peep:
    //    t1 = SHL X, 0|1|2|3    / t1 = MUL X, 1|2|4|8
    //    t2 = ADD t1, Y
    //
    // Into:
    //    t2 = LEA [X * scale + Y]

    if (instrAdd->HasBailOutInfo())
    {
        return instrAdd;
    }

    if (!instrAdd->GetDst()->IsRegOpnd())
    {
        return instrAdd;
    }

    IR::Opnd * src2 = instrAdd->GetSrc2();
    IR::Opnd * src1 = instrAdd->GetSrc1();
    IR::Instr * resultInstr = TryShiftAdd(instrAdd, src1, src2);
    if (resultInstr->m_opcode == Js::OpCode::Add_I4)
    {
        resultInstr = TryShiftAdd(instrAdd, src2, src1);
    }
    return resultInstr;

}

IR::Instr *Lowerer::PeepShl(IR::Instr *instrShl)
{
    IR::Opnd *src1;
    IR::Opnd *src2;
    IR::Instr *instrDef;

    src1 = instrShl->GetSrc1();
    src2 = instrShl->GetSrc2();

    // Peep:
    //    t1 = SHR X, cst
    //    t2 = SHL t1, cst
    //
    // Into:
    //    t2 = AND X, mask

    if (!src1->IsRegOpnd() || !src2->IsIntConstOpnd())
    {
        return instrShl;
    }
    if (!src1->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrShl;
    }
    if (instrShl->HasBailOutInfo())
    {
        return instrShl;
    }
    instrDef = src1->AsRegOpnd()->m_sym->GetInstrDef();
    if (instrDef->m_opcode != Js::OpCode::Shr_I4 || !instrDef->GetSrc2()->IsIntConstOpnd()
        || instrDef->GetSrc2()->AsIntConstOpnd()->GetValue() != src2->AsIntConstOpnd()->GetValue()
        || !instrDef->GetSrc1()->IsRegOpnd())
    {
        return instrShl;
    }
    if (!src1->GetIsDead())
    {
        return instrShl;
    }
    if (instrDef->HasBailOutInfo())
    {
        return instrShl;
    }

    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrShl->m_prev)
    {
        if (instrIter->HasBailOutInfo())
        {
            return instrShl;
        }
        if (instrIter->FindRegDef(instrDef->GetSrc1()->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        if (instrIter->FindRegUse(src1->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        // if any branch between def-use, don't do peeps on it because branch target might depend on the def
        if (instrIter->IsBranchInstr())
        {
            return instrShl;
        }
    } NEXT_INSTR_IN_RANGE;

    instrShl->FreeSrc1();
    instrShl->SetSrc1(instrDef->UnlinkSrc1());
    instrDef->Remove();

    IntConstType oldValue = src2->AsIntConstOpnd()->GetValue();

    // Left shift operator (<<) on arm32 is implemented by LSL which doesn't discard bits beyond lowerest 5-bit.
    // Need to discard such bits to conform to << in JavaScript. This is not a problem for x86 and x64 because
    // behavior of SHL is consistent with JavaScript but keep the below line for clarity.
    oldValue %= sizeof(int32) * 8;

    oldValue = ~((1 << oldValue) - 1);
    src2->AsIntConstOpnd()->SetValue(oldValue);

    instrShl->m_opcode = Js::OpCode::And_I4;

    return instrShl;
}

IR::Instr *Lowerer::PeepBrBool(IR::Instr *instrBr)
{
    IR::Opnd *src1;
    IR::Instr *instrBinOp, *instrCm1, *instrCm2;

    // Peep:
    //    t1 = CmCC_I4 a, b
    //    t2 = CmCC_i4 c, d
    //    t3 = AND/OR t1, t2
    //    BrTrue/False t3, $L_true
    //
    // Into:
    //    BrCC a, b,  $L_true/false
    //    BrCC c, d,  $L_true
    //$L_false:

    src1 = instrBr->GetSrc1();
    if (!src1->IsRegOpnd())
    {
        return instrBr;
    }
    Assert(!instrBr->HasBailOutInfo());

    instrBinOp = instrBr->GetPrevRealInstrOrLabel();
    if (instrBinOp->m_opcode != Js::OpCode::And_I4 && instrBinOp->m_opcode != Js::OpCode::Or_I4)
    {
        return instrBr;
    }
    if (!instrBinOp->GetDst()->IsEqual(src1))
    {
        return instrBr;
    }
    IR::RegOpnd *src1Reg = src1->AsRegOpnd();
    if (!src1Reg->m_sym->IsSingleDef() || !src1Reg->GetIsDead())
    {
        return instrBr;
    }
    Assert(!instrBinOp->HasBailOutInfo());

    instrCm2 = instrBinOp->GetPrevRealInstrOrLabel();
    if (!instrCm2->IsCmCC_I4())
    {
        return instrBr;
    }
    IR::RegOpnd *cm2DstReg = instrCm2->GetDst()->AsRegOpnd();
    if (!cm2DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm2DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm2DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm2->HasBailOutInfo());

    instrCm1 = instrCm2->GetPrevRealInstrOrLabel();
    if (!instrCm1->IsCmCC_I4())
    {
        return instrBr;
    }
    Assert(!instrCm1->GetDst()->IsEqual(instrCm2->GetDst()));

    IR::RegOpnd *cm1DstReg = instrCm1->GetDst()->AsRegOpnd();
    if (!cm1DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm1DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm1DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm1->HasBailOutInfo());

    IR::LabelInstr *falseLabel = instrBr->AsBranchInstr()->GetTarget();
    IR::LabelInstr *trueLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
    instrBr->InsertAfter(trueLabel);
    IR::BranchInstr *instrBr1;
    IR::BranchInstr *instrBr2;

    if (instrBinOp->m_opcode == Js::OpCode::And_I4)
    {
        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrFalse_I4 ? falseLabel : trueLabel);
        instrBr1->Invert();
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }
    else
    {
        Assert(instrBinOp->m_opcode == Js::OpCode::Or_I4);

        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrTrue_I4 ? falseLabel : trueLabel);
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }

    instrBinOp->Remove();
    instrBr->Remove();

    return instrBr2;
}
<commit_msg>fix ShiftAdd peep in case src1 == src2<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

IR::Instr *Lowerer::PreLowerPeepInstr(IR::Instr *instr, IR::Instr **pInstrPrev)
{
    if (PHASE_OFF(Js::PreLowererPeepsPhase, this->m_func))
    {
        return instr;
    }

    switch (instr->m_opcode)
    {
#if defined(_M_IX86) || defined(_M_X64)
        // this sort of addressing mode magic only applies to x86 platforms
    case Js::OpCode::Add_I4:
        instr = this->PeepShiftAdd(instr);
        *pInstrPrev = instr->m_prev;
        break;
#endif
    case Js::OpCode::Shl_I4:
        instr = this->PeepShl(instr);
        *pInstrPrev = instr->m_prev;
        break;

    case Js::OpCode::BrTrue_I4:
    case Js::OpCode::BrFalse_I4:
        instr = this->PeepBrBool(instr);
        *pInstrPrev = instr->m_prev;
        break;
    }

    return instr;
}

IR::Instr *
Lowerer::TryShiftAdd(IR::Instr *instrAdd, IR::Opnd * opndFold, IR::Opnd * opndAdd)
{
    Assert(instrAdd->m_opcode == Js::OpCode::Add_I4);
    if (!opndFold->GetIsDead())
    {
        return instrAdd;
    }

    if (!(opndAdd->IsRegOpnd() || (opndAdd->IsInt32() && opndAdd->IsIntConstOpnd())))
    {
        return instrAdd;
    }

    if (!opndFold->IsRegOpnd() || !opndFold->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrAdd;
    }

    IR::Instr * instrDef = opndFold->AsRegOpnd()->m_sym->GetInstrDef();

    if ((instrDef->m_opcode != Js::OpCode::Shl_I4 && instrDef->m_opcode != Js::OpCode::Mul_I4) || !instrDef->GetSrc1()->IsRegOpnd()  || !instrDef->GetSrc2()->IsIntConstOpnd())
    {
        return instrAdd;
    }

    if (instrDef->HasBailOutInfo())
    {
        return instrAdd;
    }

    byte scale = 0;
    IntConstType constVal = instrDef->GetSrc2()->AsIntConstOpnd()->GetValue();
    if (instrDef->m_opcode == Js::OpCode::Shl_I4)
    {
        if (constVal < 0 || constVal > 3)
        {
            return instrAdd;
        }
        scale = (byte)constVal;
    }
    else
    {
        Assert(instrDef->m_opcode == Js::OpCode::Mul_I4);
        switch (constVal)
        {
        case 1:
scale = 0;
break;
        case 2:
            scale = 1;
            break;
        case 4:
            scale = 2;
            break;
        case 8:
            scale = 3;
            break;
        default:
            return instrAdd;
        }
    }

    StackSym * defSrc1Sym = instrDef->GetSrc1()->AsRegOpnd()->m_sym;
    StackSym * foldSym = opndFold->AsRegOpnd()->m_sym;
    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrAdd->m_prev)
    {
        // if any branch between def-use, don't do peeps on it because branch target might depend on the def
        if (instrIter->IsBranchInstr())
        {
            return instrAdd;
        }
        if (instrIter->HasBailOutInfo())
        {
            return instrAdd;
        }
        if (instrIter->FindRegDef(defSrc1Sym))
        {
            return instrAdd;
        }
        if (instrIter->FindRegUse(foldSym))
        {
            return instrAdd;
        }
    } NEXT_INSTR_IN_RANGE;

#if DBG_DUMP
    if (PHASE_TRACE(Js::PreLowererPeepsPhase, instrAdd->m_func))
    {
        Output::Print(_u("PeepShiftAdd : %s (%d) : folding:\n"), instrAdd->m_func->GetJITFunctionBody()->GetDisplayName(), instrAdd->m_func->GetFunctionNumber());
        instrDef->Dump();
        instrAdd->Dump();
    }
#endif

    IR::IndirOpnd * leaOpnd = nullptr;
    if (opndAdd->IsRegOpnd())
    {
        leaOpnd = IR::IndirOpnd::New(opndAdd->AsRegOpnd(), instrDef->UnlinkSrc1()->AsRegOpnd(), scale, opndFold->GetType(), instrAdd->m_func);
    }
    else
    {
        Assert(opndAdd->IsInt32() && opndAdd->IsIntConstOpnd());
        leaOpnd = IR::IndirOpnd::New(instrDef->UnlinkSrc1()->AsRegOpnd(), opndAdd->AsIntConstOpnd()->AsInt32(), scale, opndFold->GetType(), instrAdd->m_func);
    }

    IR::Instr * leaInstr = InsertLea(instrAdd->UnlinkDst()->AsRegOpnd(), leaOpnd, instrAdd);

#if DBG_DUMP
    if (PHASE_TRACE(Js::PreLowererPeepsPhase, instrAdd->m_func))
    {
        Output::Print(_u("into:\n"), instrAdd->m_func->GetJITFunctionBody()->GetDisplayName(), instrAdd->m_func->GetFunctionNumber());
        leaInstr->Dump();
    }
#endif

    instrAdd->Remove();
    instrDef->Remove();

    return leaInstr;
}

IR::Instr *
Lowerer::PeepShiftAdd(IR::Instr *instrAdd)
{
    Assert(instrAdd->m_opcode == Js::OpCode::Add_I4);

    // Peep:
    //    t1 = SHL X, 0|1|2|3    / t1 = MUL X, 1|2|4|8
    //    t2 = ADD t1, Y
    //
    // Into:
    //    t2 = LEA [X * scale + Y]

    if (instrAdd->HasBailOutInfo())
    {
        return instrAdd;
    }

    if (!instrAdd->GetDst()->IsRegOpnd())
    {
        return instrAdd;
    }

    IR::Opnd * src2 = instrAdd->GetSrc2();
    IR::Opnd * src1 = instrAdd->GetSrc1();

    // we can't remove t1 in case both srcs are uses of t1
    if (src1->IsEqual(src2))
    {
        return instrAdd;
    }
    IR::Instr * resultInstr = TryShiftAdd(instrAdd, src1, src2);
    if (resultInstr->m_opcode == Js::OpCode::Add_I4)
    {
        resultInstr = TryShiftAdd(instrAdd, src2, src1);
    }
    return resultInstr;

}

IR::Instr *Lowerer::PeepShl(IR::Instr *instrShl)
{
    IR::Opnd *src1;
    IR::Opnd *src2;
    IR::Instr *instrDef;

    src1 = instrShl->GetSrc1();
    src2 = instrShl->GetSrc2();

    // Peep:
    //    t1 = SHR X, cst
    //    t2 = SHL t1, cst
    //
    // Into:
    //    t2 = AND X, mask

    if (!src1->IsRegOpnd() || !src2->IsIntConstOpnd())
    {
        return instrShl;
    }
    if (!src1->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrShl;
    }
    if (instrShl->HasBailOutInfo())
    {
        return instrShl;
    }
    instrDef = src1->AsRegOpnd()->m_sym->GetInstrDef();
    if (instrDef->m_opcode != Js::OpCode::Shr_I4 || !instrDef->GetSrc2()->IsIntConstOpnd()
        || instrDef->GetSrc2()->AsIntConstOpnd()->GetValue() != src2->AsIntConstOpnd()->GetValue()
        || !instrDef->GetSrc1()->IsRegOpnd())
    {
        return instrShl;
    }
    if (!src1->GetIsDead())
    {
        return instrShl;
    }
    if (instrDef->HasBailOutInfo())
    {
        return instrShl;
    }

    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrShl->m_prev)
    {
        if (instrIter->HasBailOutInfo())
        {
            return instrShl;
        }
        if (instrIter->FindRegDef(instrDef->GetSrc1()->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        if (instrIter->FindRegUse(src1->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        // if any branch between def-use, don't do peeps on it because branch target might depend on the def
        if (instrIter->IsBranchInstr())
        {
            return instrShl;
        }
    } NEXT_INSTR_IN_RANGE;

    instrShl->FreeSrc1();
    instrShl->SetSrc1(instrDef->UnlinkSrc1());
    instrDef->Remove();

    IntConstType oldValue = src2->AsIntConstOpnd()->GetValue();

    // Left shift operator (<<) on arm32 is implemented by LSL which doesn't discard bits beyond lowerest 5-bit.
    // Need to discard such bits to conform to << in JavaScript. This is not a problem for x86 and x64 because
    // behavior of SHL is consistent with JavaScript but keep the below line for clarity.
    oldValue %= sizeof(int32) * 8;

    oldValue = ~((1 << oldValue) - 1);
    src2->AsIntConstOpnd()->SetValue(oldValue);

    instrShl->m_opcode = Js::OpCode::And_I4;

    return instrShl;
}

IR::Instr *Lowerer::PeepBrBool(IR::Instr *instrBr)
{
    IR::Opnd *src1;
    IR::Instr *instrBinOp, *instrCm1, *instrCm2;

    // Peep:
    //    t1 = CmCC_I4 a, b
    //    t2 = CmCC_i4 c, d
    //    t3 = AND/OR t1, t2
    //    BrTrue/False t3, $L_true
    //
    // Into:
    //    BrCC a, b,  $L_true/false
    //    BrCC c, d,  $L_true
    //$L_false:

    src1 = instrBr->GetSrc1();
    if (!src1->IsRegOpnd())
    {
        return instrBr;
    }
    Assert(!instrBr->HasBailOutInfo());

    instrBinOp = instrBr->GetPrevRealInstrOrLabel();
    if (instrBinOp->m_opcode != Js::OpCode::And_I4 && instrBinOp->m_opcode != Js::OpCode::Or_I4)
    {
        return instrBr;
    }
    if (!instrBinOp->GetDst()->IsEqual(src1))
    {
        return instrBr;
    }
    IR::RegOpnd *src1Reg = src1->AsRegOpnd();
    if (!src1Reg->m_sym->IsSingleDef() || !src1Reg->GetIsDead())
    {
        return instrBr;
    }
    Assert(!instrBinOp->HasBailOutInfo());

    instrCm2 = instrBinOp->GetPrevRealInstrOrLabel();
    if (!instrCm2->IsCmCC_I4())
    {
        return instrBr;
    }
    IR::RegOpnd *cm2DstReg = instrCm2->GetDst()->AsRegOpnd();
    if (!cm2DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm2DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm2DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm2->HasBailOutInfo());

    instrCm1 = instrCm2->GetPrevRealInstrOrLabel();
    if (!instrCm1->IsCmCC_I4())
    {
        return instrBr;
    }
    Assert(!instrCm1->GetDst()->IsEqual(instrCm2->GetDst()));

    IR::RegOpnd *cm1DstReg = instrCm1->GetDst()->AsRegOpnd();
    if (!cm1DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm1DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm1DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm1->HasBailOutInfo());

    IR::LabelInstr *falseLabel = instrBr->AsBranchInstr()->GetTarget();
    IR::LabelInstr *trueLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
    instrBr->InsertAfter(trueLabel);
    IR::BranchInstr *instrBr1;
    IR::BranchInstr *instrBr2;

    if (instrBinOp->m_opcode == Js::OpCode::And_I4)
    {
        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrFalse_I4 ? falseLabel : trueLabel);
        instrBr1->Invert();
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }
    else
    {
        Assert(instrBinOp->m_opcode == Js::OpCode::Or_I4);

        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrTrue_I4 ? falseLabel : trueLabel);
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }

    instrBinOp->Remove();
    instrBr->Remove();

    return instrBr2;
}
<|endoftext|>


<commit_before>/**
 * @file   tile_io.cc
 *
 * @section LICENSE
 *
 * The MIT License
 *
 * @copyright Copyright (c) 2017-2018 TileDB, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * This file implements class TileIO.
 */

#include "tiledb/sm/tile/tile_io.h"
#include "tiledb/sm/filter/compression_filter.h"
#include "tiledb/sm/filter/encryption_aes256gcm_filter.h"
#include "tiledb/sm/misc/logger.h"
#include "tiledb/sm/misc/parallel_functions.h"
#include "tiledb/sm/misc/stats.h"

/* ****************************** */
/*             MACROS             */
/* ****************************** */

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

namespace tiledb {
namespace sm {

/* ****************************** */
/*   CONSTRUCTORS & DESTRUCTORS   */
/* ****************************** */

TileIO::TileIO(StorageManager* storage_manager, const URI& uri)
    : storage_manager_(storage_manager)
    , uri_(uri) {
  file_size_ = 0;
}

/* ****************************** */
/*               API              */
/* ****************************** */

uint64_t TileIO::file_size() const {
  return file_size_;
}

Status TileIO::is_generic_tile(
    const StorageManager* sm, const URI& uri, bool* is_generic_tile) {
  STATS_FUNC_IN(tileio_is_generic_tile);

  *is_generic_tile = false;

  bool is_file;
  RETURN_NOT_OK(sm->vfs()->is_file(uri, &is_file));
  if (!is_file)
    return Status::Ok();

  uint64_t file_size;
  RETURN_NOT_OK(sm->vfs()->file_size(uri, &file_size));
  if (file_size < GenericTileHeader::BASE_SIZE)
    return Status::Ok();

  GenericTileHeader header;
  RETURN_NOT_OK(read_generic_tile_header(sm, uri, 0, &header));

  auto expected_size = GenericTileHeader::BASE_SIZE +
                       header.filter_pipeline_size + header.persisted_size;
  if (file_size != expected_size)
    return Status::Ok();

  *is_generic_tile = true;
  return Status::Ok();

  STATS_FUNC_OUT(tileio_is_generic_tile);
}

Status TileIO::read_generic(
    Tile** tile, uint64_t file_offset, const EncryptionKey& encryption_key) {
  STATS_FUNC_IN(tileio_read_generic);

  GenericTileHeader header;
  RETURN_NOT_OK(
      read_generic_tile_header(storage_manager_, uri_, file_offset, &header));

  if (encryption_key.encryption_type() !=
      (EncryptionType)header.encryption_type)
    return LOG_STATUS(Status::Error(
        "Error reading generic tile; tile is encrypted with " +
        encryption_type_str((EncryptionType)header.encryption_type) +
        " but given key is for " +
        encryption_type_str(encryption_key.encryption_type())));

  RETURN_NOT_OK(configure_encryption_filter(&header, encryption_key));

  *tile = new Tile();
  RETURN_NOT_OK_ELSE(
      (*tile)->init(
          header.version_number,
          (Datatype)header.datatype,
          header.cell_size,
          0),
      delete *tile);

  auto tile_data_offset =
      GenericTileHeader::BASE_SIZE + header.filter_pipeline_size;

  // Try the cache first.
  bool cache_hit;
  RETURN_NOT_OK(storage_manager_->read_from_cache(
      uri_,
      file_offset + tile_data_offset,
      (*tile)->buffer(),
      header.tile_size,
      &cache_hit));

  // Read from disk and add to cache if it missed.
  if (!cache_hit) {
    RETURN_NOT_OK_ELSE(
        storage_manager_->read(
            uri_,
            file_offset + tile_data_offset,
            (*tile)->buffer(),
            header.persisted_size),
        delete *tile);

    // Filter
    RETURN_NOT_OK_ELSE(header.filters.run_reverse(*tile), delete *tile);

    file_size_ = header.persisted_size;
    STATS_COUNTER_ADD(tileio_read_num_bytes_read, header.persisted_size);
    STATS_COUNTER_ADD(tileio_read_num_resulting_bytes, (*tile)->size());

    RETURN_NOT_OK(storage_manager_->write_to_cache(
        uri_, file_offset + tile_data_offset, (*tile)->buffer()));
  }

  return Status::Ok();

  STATS_FUNC_OUT(tileio_read_generic);
}

Status TileIO::read_generic_tile_header(
    const StorageManager* sm,
    const URI& uri,
    uint64_t file_offset,
    GenericTileHeader* header) {
  // Read the fixed-sized part of the header from file
  std::unique_ptr<Buffer> header_buff(new Buffer());
  RETURN_NOT_OK(sm->read(
      uri, file_offset, header_buff.get(), GenericTileHeader::BASE_SIZE));

  // Read header individual values
  RETURN_NOT_OK(header_buff->read(&header->version_number, sizeof(uint32_t)));
  RETURN_NOT_OK(header_buff->read(&header->persisted_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->tile_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->datatype, sizeof(uint8_t)));
  RETURN_NOT_OK(header_buff->read(&header->cell_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->encryption_type, sizeof(uint8_t)));
  RETURN_NOT_OK(
      header_buff->read(&header->filter_pipeline_size, sizeof(uint32_t)));

  // Read header filter pipeline.
  header_buff->reset_size();
  header_buff->reset_offset();
  RETURN_NOT_OK(sm->read(
      uri,
      file_offset + GenericTileHeader::BASE_SIZE,
      header_buff.get(),
      header->filter_pipeline_size));
  ConstBuffer cbuf(header_buff->data(), header_buff->size());
  RETURN_NOT_OK(header->filters.deserialize(&cbuf));

  STATS_COUNTER_ADD(
      tileio_read_num_bytes_read,
      GenericTileHeader::BASE_SIZE + header->filter_pipeline_size);

  return Status::Ok();
}

Status TileIO::write_generic(Tile* tile, const EncryptionKey& encryption_key) {
  STATS_FUNC_IN(tileio_write_generic);

  // Reset the tile and buffer offset
  tile->reset_offset();

  STATS_COUNTER_ADD(tileio_write_num_input_bytes, tile->size());

  // Create a header
  GenericTileHeader header;
  RETURN_NOT_OK(init_generic_tile_header(tile, &header, encryption_key));

  // Filter tile
  RETURN_NOT_OK(header.filters.run_forward(tile));
  header.persisted_size = tile->buffer()->size();

  RETURN_NOT_OK(write_generic_tile_header(&header));
  RETURN_NOT_OK(storage_manager_->write(uri_, tile->buffer()));

  file_size_ = header.persisted_size;
  STATS_COUNTER_ADD(tileio_write_num_bytes_written, header.persisted_size);

  return Status::Ok();

  STATS_FUNC_OUT(tileio_write_generic);
}

Status TileIO::write_generic_tile_header(GenericTileHeader* header) {
  // Write to buffer
  auto buff = new Buffer();
  RETURN_NOT_OK_ELSE(
      buff->write(&header->version_number, sizeof(uint32_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->persisted_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->tile_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->datatype, sizeof(uint8_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->cell_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->encryption_type, sizeof(uint8_t)), delete buff);

  // Write placeholder value for pipeline size.
  uint64_t pipeline_size_offset = buff->offset();
  RETURN_NOT_OK_ELSE(
      buff->write(&header->filter_pipeline_size, sizeof(uint32_t)),
      delete buff);

  // Write pipeline to buffer
  auto orig_size = buff->size();
  RETURN_NOT_OK_ELSE(header->filters.serialize(buff), delete buff);

  // Write actual pipeline size over placeholder.
  header->filter_pipeline_size =
      static_cast<uint32_t>(buff->size() - orig_size);
  *(static_cast<uint32_t*>(buff->value_ptr(pipeline_size_offset))) =
      header->filter_pipeline_size;

  // Write buffer to file
  Status st = storage_manager_->write(uri_, buff);

  STATS_COUNTER_ADD(tileio_write_num_input_bytes, buff->size());
  STATS_COUNTER_ADD(tileio_write_num_bytes_written, buff->size());

  delete buff;

  return st;
}

Status TileIO::configure_encryption_filter(
    GenericTileHeader* header, const EncryptionKey& encryption_key) const {
  switch ((EncryptionType)header->encryption_type) {
    case EncryptionType::NO_ENCRYPTION:
      // Do nothing.
      break;
    case EncryptionType::AES_256_GCM: {
      auto* f = header->filters.get_filter<EncryptionAES256GCMFilter>();
      if (f == nullptr)
        return Status::Error(
            "Error getting generic tile; no encryption filter.");
      RETURN_NOT_OK(f->set_key(encryption_key));
      break;
    }
    default:
      return Status::Error(
          "Error getting generic tile; invalid encryption type.");
  }

  return Status::Ok();
}

Status TileIO::init_generic_tile_header(
    Tile* tile,
    GenericTileHeader* header,
    const EncryptionKey& encryption_key) const {
  header->tile_size = tile->size();
  header->datatype = (uint8_t)tile->type();
  header->cell_size = tile->cell_size();
  header->encryption_type = (uint8_t)encryption_key.encryption_type();

  RETURN_NOT_OK(header->filters.add_filter(CompressionFilter(
      constants::generic_tile_compressor,
      constants::generic_tile_compression_level)));

  RETURN_NOT_OK(FilterPipeline::append_encryption_filter(
      &header->filters, encryption_key));

  return Status::Ok();
}

}  // namespace sm
}  // namespace tiledb
<commit_msg>Remove use of tile cache from TileIO class.<commit_after>/**
 * @file   tile_io.cc
 *
 * @section LICENSE
 *
 * The MIT License
 *
 * @copyright Copyright (c) 2017-2018 TileDB, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * This file implements class TileIO.
 */

#include "tiledb/sm/tile/tile_io.h"
#include "tiledb/sm/filter/compression_filter.h"
#include "tiledb/sm/filter/encryption_aes256gcm_filter.h"
#include "tiledb/sm/misc/logger.h"
#include "tiledb/sm/misc/parallel_functions.h"
#include "tiledb/sm/misc/stats.h"

/* ****************************** */
/*             MACROS             */
/* ****************************** */

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

namespace tiledb {
namespace sm {

/* ****************************** */
/*   CONSTRUCTORS & DESTRUCTORS   */
/* ****************************** */

TileIO::TileIO(StorageManager* storage_manager, const URI& uri)
    : storage_manager_(storage_manager)
    , uri_(uri) {
  file_size_ = 0;
}

/* ****************************** */
/*               API              */
/* ****************************** */

uint64_t TileIO::file_size() const {
  return file_size_;
}

Status TileIO::is_generic_tile(
    const StorageManager* sm, const URI& uri, bool* is_generic_tile) {
  STATS_FUNC_IN(tileio_is_generic_tile);

  *is_generic_tile = false;

  bool is_file;
  RETURN_NOT_OK(sm->vfs()->is_file(uri, &is_file));
  if (!is_file)
    return Status::Ok();

  uint64_t file_size;
  RETURN_NOT_OK(sm->vfs()->file_size(uri, &file_size));
  if (file_size < GenericTileHeader::BASE_SIZE)
    return Status::Ok();

  GenericTileHeader header;
  RETURN_NOT_OK(read_generic_tile_header(sm, uri, 0, &header));

  auto expected_size = GenericTileHeader::BASE_SIZE +
                       header.filter_pipeline_size + header.persisted_size;
  if (file_size != expected_size)
    return Status::Ok();

  *is_generic_tile = true;
  return Status::Ok();

  STATS_FUNC_OUT(tileio_is_generic_tile);
}

Status TileIO::read_generic(
    Tile** tile, uint64_t file_offset, const EncryptionKey& encryption_key) {
  STATS_FUNC_IN(tileio_read_generic);

  GenericTileHeader header;
  RETURN_NOT_OK(
      read_generic_tile_header(storage_manager_, uri_, file_offset, &header));

  if (encryption_key.encryption_type() !=
      (EncryptionType)header.encryption_type)
    return LOG_STATUS(Status::Error(
        "Error reading generic tile; tile is encrypted with " +
        encryption_type_str((EncryptionType)header.encryption_type) +
        " but given key is for " +
        encryption_type_str(encryption_key.encryption_type())));

  RETURN_NOT_OK(configure_encryption_filter(&header, encryption_key));

  *tile = new Tile();
  RETURN_NOT_OK_ELSE(
      (*tile)->init(
          header.version_number,
          (Datatype)header.datatype,
          header.cell_size,
          0),
      delete *tile);

  auto tile_data_offset =
      GenericTileHeader::BASE_SIZE + header.filter_pipeline_size;

  // Read the tile.
  RETURN_NOT_OK_ELSE(
      storage_manager_->read(
          uri_,
          file_offset + tile_data_offset,
          (*tile)->buffer(),
          header.persisted_size),
      delete *tile);

  // Filter
  RETURN_NOT_OK_ELSE(header.filters.run_reverse(*tile), delete *tile);

  file_size_ = header.persisted_size;
  STATS_COUNTER_ADD(tileio_read_num_bytes_read, header.persisted_size);
  STATS_COUNTER_ADD(tileio_read_num_resulting_bytes, (*tile)->size());

  return Status::Ok();

  STATS_FUNC_OUT(tileio_read_generic);
}

Status TileIO::read_generic_tile_header(
    const StorageManager* sm,
    const URI& uri,
    uint64_t file_offset,
    GenericTileHeader* header) {
  // Read the fixed-sized part of the header from file
  std::unique_ptr<Buffer> header_buff(new Buffer());
  RETURN_NOT_OK(sm->read(
      uri, file_offset, header_buff.get(), GenericTileHeader::BASE_SIZE));

  // Read header individual values
  RETURN_NOT_OK(header_buff->read(&header->version_number, sizeof(uint32_t)));
  RETURN_NOT_OK(header_buff->read(&header->persisted_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->tile_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->datatype, sizeof(uint8_t)));
  RETURN_NOT_OK(header_buff->read(&header->cell_size, sizeof(uint64_t)));
  RETURN_NOT_OK(header_buff->read(&header->encryption_type, sizeof(uint8_t)));
  RETURN_NOT_OK(
      header_buff->read(&header->filter_pipeline_size, sizeof(uint32_t)));

  // Read header filter pipeline.
  header_buff->reset_size();
  header_buff->reset_offset();
  RETURN_NOT_OK(sm->read(
      uri,
      file_offset + GenericTileHeader::BASE_SIZE,
      header_buff.get(),
      header->filter_pipeline_size));
  ConstBuffer cbuf(header_buff->data(), header_buff->size());
  RETURN_NOT_OK(header->filters.deserialize(&cbuf));

  STATS_COUNTER_ADD(
      tileio_read_num_bytes_read,
      GenericTileHeader::BASE_SIZE + header->filter_pipeline_size);

  return Status::Ok();
}

Status TileIO::write_generic(Tile* tile, const EncryptionKey& encryption_key) {
  STATS_FUNC_IN(tileio_write_generic);

  // Reset the tile and buffer offset
  tile->reset_offset();

  STATS_COUNTER_ADD(tileio_write_num_input_bytes, tile->size());

  // Create a header
  GenericTileHeader header;
  RETURN_NOT_OK(init_generic_tile_header(tile, &header, encryption_key));

  // Filter tile
  RETURN_NOT_OK(header.filters.run_forward(tile));
  header.persisted_size = tile->buffer()->size();

  RETURN_NOT_OK(write_generic_tile_header(&header));
  RETURN_NOT_OK(storage_manager_->write(uri_, tile->buffer()));

  file_size_ = header.persisted_size;
  STATS_COUNTER_ADD(tileio_write_num_bytes_written, header.persisted_size);

  return Status::Ok();

  STATS_FUNC_OUT(tileio_write_generic);
}

Status TileIO::write_generic_tile_header(GenericTileHeader* header) {
  // Write to buffer
  auto buff = new Buffer();
  RETURN_NOT_OK_ELSE(
      buff->write(&header->version_number, sizeof(uint32_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->persisted_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->tile_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->datatype, sizeof(uint8_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->cell_size, sizeof(uint64_t)), delete buff);
  RETURN_NOT_OK_ELSE(
      buff->write(&header->encryption_type, sizeof(uint8_t)), delete buff);

  // Write placeholder value for pipeline size.
  uint64_t pipeline_size_offset = buff->offset();
  RETURN_NOT_OK_ELSE(
      buff->write(&header->filter_pipeline_size, sizeof(uint32_t)),
      delete buff);

  // Write pipeline to buffer
  auto orig_size = buff->size();
  RETURN_NOT_OK_ELSE(header->filters.serialize(buff), delete buff);

  // Write actual pipeline size over placeholder.
  header->filter_pipeline_size =
      static_cast<uint32_t>(buff->size() - orig_size);
  *(static_cast<uint32_t*>(buff->value_ptr(pipeline_size_offset))) =
      header->filter_pipeline_size;

  // Write buffer to file
  Status st = storage_manager_->write(uri_, buff);

  STATS_COUNTER_ADD(tileio_write_num_input_bytes, buff->size());
  STATS_COUNTER_ADD(tileio_write_num_bytes_written, buff->size());

  delete buff;

  return st;
}

Status TileIO::configure_encryption_filter(
    GenericTileHeader* header, const EncryptionKey& encryption_key) const {
  switch ((EncryptionType)header->encryption_type) {
    case EncryptionType::NO_ENCRYPTION:
      // Do nothing.
      break;
    case EncryptionType::AES_256_GCM: {
      auto* f = header->filters.get_filter<EncryptionAES256GCMFilter>();
      if (f == nullptr)
        return Status::Error(
            "Error getting generic tile; no encryption filter.");
      RETURN_NOT_OK(f->set_key(encryption_key));
      break;
    }
    default:
      return Status::Error(
          "Error getting generic tile; invalid encryption type.");
  }

  return Status::Ok();
}

Status TileIO::init_generic_tile_header(
    Tile* tile,
    GenericTileHeader* header,
    const EncryptionKey& encryption_key) const {
  header->tile_size = tile->size();
  header->datatype = (uint8_t)tile->type();
  header->cell_size = tile->cell_size();
  header->encryption_type = (uint8_t)encryption_key.encryption_type();

  RETURN_NOT_OK(header->filters.add_filter(CompressionFilter(
      constants::generic_tile_compressor,
      constants::generic_tile_compression_level)));

  RETURN_NOT_OK(FilterPipeline::append_encryption_filter(
      &header->filters, encryption_key));

  return Status::Ok();
}

}  // namespace sm
}  // namespace tiledb
<|endoftext|>


<commit_before>//===-- LiveVariables.cpp - Live Variable Analysis for Machine Code -------===//
//
// This file implements the LiveVariable analysis pass.  For each machine
// instruction in the function, this pass calculates the set of registers that
// are immediately dead after the instruction (i.e., the instruction calculates
// the value, but it is never used) and the set of registers that are used by
// the instruction, but are never used after the instruction (i.e., they are
// killed).
//
// This class computes live variables using are sparse implementation based on
// the machine code SSA form.  This class computes live variable information for
// each virtual and _register allocatable_ physical register in a function.  It
// uses the dominance properties of SSA form to efficiently compute live
// variables for virtual registers, and assumes that physical registers are only
// live within a single basic block (allowing it to do a single local analysis
// to resolve physical register lifetimes in each basic block).  If a physical
// register is not register allocatable, it is not tracked.  This is useful for
// things like the stack pointer and condition codes.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/CFG.h"
#include "Support/DepthFirstIterator.h"

static RegisterAnalysis<LiveVariables> X("livevars", "Live Variable Analysis");

void LiveVariables::MarkVirtRegAliveInBlock(VarInfo &VRInfo,
					    const BasicBlock *BB) {
  const std::pair<MachineBasicBlock*,unsigned> &Info = BBMap.find(BB)->second;
  MachineBasicBlock *MBB = Info.first;
  unsigned BBNum = Info.second;

  // Check to see if this basic block is one of the killing blocks.  If so,
  // remove it...
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    if (VRInfo.Kills[i].first == MBB) {
      VRInfo.Kills.erase(VRInfo.Kills.begin()+i);  // Erase entry
      break;
    }

  if (MBB == VRInfo.DefBlock) return;  // Terminate recursion

  if (VRInfo.AliveBlocks.size() <= BBNum)
    VRInfo.AliveBlocks.resize(BBNum+1);  // Make space...

  if (VRInfo.AliveBlocks[BBNum])
    return;  // We already know the block is live

  // Mark the variable known alive in this bb
  VRInfo.AliveBlocks[BBNum] = true;

  for (pred_const_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandleVirtRegUse(VarInfo &VRInfo, MachineBasicBlock *MBB,
				     MachineInstr *MI) {
  // Check to see if this basic block is already a kill block...
  if (!VRInfo.Kills.empty() && VRInfo.Kills.back().first == MBB) {
    // Yes, this register is killed in this basic block already.  Increase the
    // live range by updating the kill instruction.
    VRInfo.Kills.back().second = MI;
    return;
  }

#ifndef NDEBUG
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    assert(VRInfo.Kills[i].first != MBB && "entry should be at end!");
#endif

  assert(MBB != VRInfo.DefBlock && "Should have kill for defblock!");

  // Add a new kill entry for this basic block.
  VRInfo.Kills.push_back(std::make_pair(MBB, MI));

  // Update all dominating blocks to mark them known live.
  const BasicBlock *BB = MBB->getBasicBlock();
  for (pred_const_iterator PI = pred_begin(BB), E = pred_end(BB);
       PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandlePhysRegUse(unsigned Reg, MachineInstr *MI) {
  if (PhysRegInfo[Reg]) {
    PhysRegInfo[Reg] = MI;
    PhysRegUsed[Reg] = true;
  } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg)) {
    for (; unsigned NReg = AliasSet[0]; ++AliasSet)
      if (MachineInstr *LastUse = PhysRegInfo[NReg]) {
	PhysRegInfo[NReg] = MI;
	PhysRegUsed[NReg] = true;
      }
  }
}

void LiveVariables::HandlePhysRegDef(unsigned Reg, MachineInstr *MI) {
  // Does this kill a previous version of this register?
  if (MachineInstr *LastUse = PhysRegInfo[Reg]) {
    if (PhysRegUsed[Reg])
      RegistersKilled.insert(std::make_pair(LastUse, Reg));
    else
      RegistersDead.insert(std::make_pair(LastUse, Reg));
  } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg)) {
    for (; unsigned NReg = AliasSet[0]; ++AliasSet)
      if (MachineInstr *LastUse = PhysRegInfo[NReg]) {
	if (PhysRegUsed[NReg])
	  RegistersKilled.insert(std::make_pair(LastUse, NReg));
	else
	  RegistersDead.insert(std::make_pair(LastUse, NReg));
	PhysRegInfo[NReg] = 0;  // Kill the aliased register
      }
  }
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = false;
}

bool LiveVariables::runOnMachineFunction(MachineFunction &MF) {
  // First time though, initialize AllocatablePhysicalRegisters for the target
  if (AllocatablePhysicalRegisters.empty()) {
    const MRegisterInfo &MRI = *MF.getTarget().getRegisterInfo();
    assert(&MRI && "Target doesn't have register information?");

    // Make space, initializing to false...
    AllocatablePhysicalRegisters.resize(MRegisterInfo::FirstVirtualRegister);

    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator RCI = MRI.regclass_begin(),
           E = MRI.regclass_end(); RCI != E; ++RCI)
      // Loop over all of the allocatable registers in the function...
      for (TargetRegisterClass::iterator I = (*RCI)->allocation_order_begin(MF),
             E = (*RCI)->allocation_order_end(MF); I != E; ++I)
        AllocatablePhysicalRegisters[*I] = true;  // The reg is allocatable!
  }

  // Build BBMap...
  unsigned BBNum = 0;
  for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
    BBMap[I->getBasicBlock()] = std::make_pair(I, BBNum++);

  // PhysRegInfo - Keep track of which instruction was the last use of a
  // physical register.  This is a purely local property, because all physical
  // register references as presumed dead across basic blocks.
  //
  MachineInstr *PhysRegInfoA[MRegisterInfo::FirstVirtualRegister];
  bool          PhysRegUsedA[MRegisterInfo::FirstVirtualRegister];
  std::fill(PhysRegInfoA, PhysRegInfoA+MRegisterInfo::FirstVirtualRegister,
	    (MachineInstr*)0);
  PhysRegInfo = PhysRegInfoA;
  PhysRegUsed = PhysRegUsedA;

  const TargetInstrInfo &TII = MF.getTarget().getInstrInfo();
  RegInfo = MF.getTarget().getRegisterInfo();

  /// Get some space for a respectable number of registers...
  VirtRegInfo.resize(64);

  // Calculate live variable information in depth first order on the CFG of the
  // function.  This guarantees that we will see the definition of a virtual
  // register before its uses due to dominance properties of SSA (except for PHI
  // nodes, which are treated as a special case).
  //
  const BasicBlock *Entry = MF.getFunction()->begin();
  for (df_iterator<const BasicBlock*> DFI = df_begin(Entry), E = df_end(Entry);
       DFI != E; ++DFI) {
    const BasicBlock *BB = *DFI;
    std::pair<MachineBasicBlock*, unsigned> &BBRec = BBMap.find(BB)->second;
    MachineBasicBlock *MBB = BBRec.first;
    unsigned BBNum = BBRec.second;

    // Loop over all of the instructions, processing them.
    for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
	 I != E; ++I) {
      MachineInstr *MI = *I;
      const TargetInstrDescriptor &MID = TII.get(MI->getOpcode());

      // Process all of the operands of the instruction...
      unsigned NumOperandsToProcess = MI->getNumOperands();

      // Unless it is a PHI node.  In this case, ONLY process the DEF, not any
      // of the uses.  They will be handled in other basic blocks.
      if (MI->getOpcode() == TargetInstrInfo::PHI)
	NumOperandsToProcess = 1;

      // Loop over implicit uses, using them.
      if (const unsigned *ImplicitUses = MID.ImplicitUses)
	for (unsigned i = 0; ImplicitUses[i]; ++i)
	  HandlePhysRegUse(ImplicitUses[i], MI);

      // Process all explicit uses...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
	MachineOperand &MO = MI->getOperand(i);
	if (MO.opIsUse() || MO.opIsDefAndUse()) {
	  if (MO.isVirtualRegister() && !MO.getVRegValueOrNull()) {
	    unsigned RegIdx = MO.getReg()-MRegisterInfo::FirstVirtualRegister;
	    HandleVirtRegUse(getVarInfo(RegIdx), MBB, MI);
	  } else if (MO.isPhysicalRegister() &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
	    HandlePhysRegUse(MO.getReg(), MI);
	  }
	}
      }

      // Loop over implicit defs, defining them.
      if (const unsigned *ImplicitDefs = MID.ImplicitDefs)
	for (unsigned i = 0; ImplicitDefs[i]; ++i)
	  HandlePhysRegDef(ImplicitDefs[i], MI);

      // Process all explicit defs...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
	MachineOperand &MO = MI->getOperand(i);
	if (MO.opIsDef() || MO.opIsDefAndUse()) {
	  if (MO.isVirtualRegister()) {
	    unsigned RegIdx = MO.getReg()-MRegisterInfo::FirstVirtualRegister;
	    VarInfo &VRInfo = getVarInfo(RegIdx);

	    assert(VRInfo.DefBlock == 0 && "Variable multiply defined!");
	    VRInfo.DefBlock = MBB;                           // Created here...
	    VRInfo.DefInst = MI;
	    VRInfo.Kills.push_back(std::make_pair(MBB, MI)); // Defaults to dead
	  } else if (MO.isPhysicalRegister() &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
	    HandlePhysRegDef(MO.getReg(), MI);
	  }
	}
      }
    }

    // Handle any virtual assignments from PHI nodes which might be at the
    // bottom of this basic block.  We check all of our successor blocks to see
    // if they have PHI nodes, and if so, we simulate an assignment at the end
    // of the current block.
    for (succ_const_iterator SI = succ_begin(BB), E = succ_end(BB);
         SI != E; ++SI) {
      MachineBasicBlock *Succ = BBMap.find(*SI)->second.first;

      // PHI nodes are guaranteed to be at the top of the block...
      for (MachineBasicBlock::iterator I = Succ->begin(), E = Succ->end();
	   I != E && (*I)->getOpcode() == TargetInstrInfo::PHI; ++I) {
        MachineInstr *MI = *I;
	for (unsigned i = 1; ; i += 2)
	  if (MI->getOperand(i+1).getMachineBasicBlock() == MBB) {
	    MachineOperand &MO = MI->getOperand(i);
	    if (!MO.getVRegValueOrNull()) {
	      unsigned RegIdx = MO.getReg()-MRegisterInfo::FirstVirtualRegister;
	      VarInfo &VRInfo = getVarInfo(RegIdx);

	      // Only mark it alive only in the block we are representing...
	      MarkVirtRegAliveInBlock(VRInfo, BB);
	      break;   // Found the PHI entry for this block...
	    }
	  }
      }
    }

    // Loop over PhysRegInfo, killing any registers that are available at the
    // end of the basic block.  This also resets the PhysRegInfo map.
    for (unsigned i = 0, e = MRegisterInfo::FirstVirtualRegister; i != e; ++i)
      if (PhysRegInfo[i])
	HandlePhysRegDef(i, 0);
  }

  BBMap.clear();

  // Convert the information we have gathered into VirtRegInfo and transform it
  // into a form usable by RegistersKilled.
  //
  for (unsigned i = 0, e = VirtRegInfo.size(); i != e; ++i)
    for (unsigned j = 0, e = VirtRegInfo[i].Kills.size(); j != e; ++j) {
      if (VirtRegInfo[i].Kills[j].second == VirtRegInfo[i].DefInst)
	RegistersDead.insert(std::make_pair(VirtRegInfo[i].Kills[j].second,
		    i + MRegisterInfo::FirstVirtualRegister));

      else
	RegistersKilled.insert(std::make_pair(VirtRegInfo[i].Kills[j].second,
		    i + MRegisterInfo::FirstVirtualRegister));
    }

  return false;
}
<commit_msg>* Keep the BBMap around as long as the pass is live * Change getVarInfo to take real virtual register numbers and offset them   itself.  This has caused me so much grief, it's not even funny.<commit_after>//===-- LiveVariables.cpp - Live Variable Analysis for Machine Code -------===//
//
// This file implements the LiveVariable analysis pass.  For each machine
// instruction in the function, this pass calculates the set of registers that
// are immediately dead after the instruction (i.e., the instruction calculates
// the value, but it is never used) and the set of registers that are used by
// the instruction, but are never used after the instruction (i.e., they are
// killed).
//
// This class computes live variables using are sparse implementation based on
// the machine code SSA form.  This class computes live variable information for
// each virtual and _register allocatable_ physical register in a function.  It
// uses the dominance properties of SSA form to efficiently compute live
// variables for virtual registers, and assumes that physical registers are only
// live within a single basic block (allowing it to do a single local analysis
// to resolve physical register lifetimes in each basic block).  If a physical
// register is not register allocatable, it is not tracked.  This is useful for
// things like the stack pointer and condition codes.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/CFG.h"
#include "Support/DepthFirstIterator.h"

static RegisterAnalysis<LiveVariables> X("livevars", "Live Variable Analysis");

const std::pair<MachineBasicBlock*, unsigned> &
LiveVariables::getMachineBasicBlockInfo(MachineBasicBlock *MBB) const{
  return BBMap.find(MBB->getBasicBlock())->second;
}

LiveVariables::VarInfo &LiveVariables::getVarInfo(unsigned RegIdx) {
  assert(RegIdx >= MRegisterInfo::FirstVirtualRegister &&
         "getVarInfo: not a virtual register!");
  RegIdx -= MRegisterInfo::FirstVirtualRegister;
  if (RegIdx >= VirtRegInfo.size()) {
    if (RegIdx >= 2*VirtRegInfo.size())
      VirtRegInfo.resize(RegIdx*2);
    else
      VirtRegInfo.resize(2*VirtRegInfo.size());
  }
  return VirtRegInfo[RegIdx];
}

void LiveVariables::MarkVirtRegAliveInBlock(VarInfo &VRInfo,
					    const BasicBlock *BB) {
  const std::pair<MachineBasicBlock*,unsigned> &Info = BBMap.find(BB)->second;
  MachineBasicBlock *MBB = Info.first;
  unsigned BBNum = Info.second;

  // Check to see if this basic block is one of the killing blocks.  If so,
  // remove it...
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    if (VRInfo.Kills[i].first == MBB) {
      VRInfo.Kills.erase(VRInfo.Kills.begin()+i);  // Erase entry
      break;
    }

  if (MBB == VRInfo.DefBlock) return;  // Terminate recursion

  if (VRInfo.AliveBlocks.size() <= BBNum)
    VRInfo.AliveBlocks.resize(BBNum+1);  // Make space...

  if (VRInfo.AliveBlocks[BBNum])
    return;  // We already know the block is live

  // Mark the variable known alive in this bb
  VRInfo.AliveBlocks[BBNum] = true;

  for (pred_const_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandleVirtRegUse(VarInfo &VRInfo, MachineBasicBlock *MBB,
				     MachineInstr *MI) {
  // Check to see if this basic block is already a kill block...
  if (!VRInfo.Kills.empty() && VRInfo.Kills.back().first == MBB) {
    // Yes, this register is killed in this basic block already.  Increase the
    // live range by updating the kill instruction.
    VRInfo.Kills.back().second = MI;
    return;
  }

#ifndef NDEBUG
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    assert(VRInfo.Kills[i].first != MBB && "entry should be at end!");
#endif

  assert(MBB != VRInfo.DefBlock && "Should have kill for defblock!");

  // Add a new kill entry for this basic block.
  VRInfo.Kills.push_back(std::make_pair(MBB, MI));

  // Update all dominating blocks to mark them known live.
  const BasicBlock *BB = MBB->getBasicBlock();
  for (pred_const_iterator PI = pred_begin(BB), E = pred_end(BB);
       PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandlePhysRegUse(unsigned Reg, MachineInstr *MI) {
  if (PhysRegInfo[Reg]) {
    PhysRegInfo[Reg] = MI;
    PhysRegUsed[Reg] = true;
  } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg)) {
    for (; unsigned NReg = AliasSet[0]; ++AliasSet)
      if (MachineInstr *LastUse = PhysRegInfo[NReg]) {
	PhysRegInfo[NReg] = MI;
	PhysRegUsed[NReg] = true;
      }
  }
}

void LiveVariables::HandlePhysRegDef(unsigned Reg, MachineInstr *MI) {
  // Does this kill a previous version of this register?
  if (MachineInstr *LastUse = PhysRegInfo[Reg]) {
    if (PhysRegUsed[Reg])
      RegistersKilled.insert(std::make_pair(LastUse, Reg));
    else
      RegistersDead.insert(std::make_pair(LastUse, Reg));
  } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg)) {
    for (; unsigned NReg = AliasSet[0]; ++AliasSet)
      if (MachineInstr *LastUse = PhysRegInfo[NReg]) {
	if (PhysRegUsed[NReg])
	  RegistersKilled.insert(std::make_pair(LastUse, NReg));
	else
	  RegistersDead.insert(std::make_pair(LastUse, NReg));
	PhysRegInfo[NReg] = 0;  // Kill the aliased register
      }
  }
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = false;
}

bool LiveVariables::runOnMachineFunction(MachineFunction &MF) {
  // First time though, initialize AllocatablePhysicalRegisters for the target
  if (AllocatablePhysicalRegisters.empty()) {
    const MRegisterInfo &MRI = *MF.getTarget().getRegisterInfo();
    assert(&MRI && "Target doesn't have register information?");

    // Make space, initializing to false...
    AllocatablePhysicalRegisters.resize(MRegisterInfo::FirstVirtualRegister);

    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator RCI = MRI.regclass_begin(),
           E = MRI.regclass_end(); RCI != E; ++RCI)
      // Loop over all of the allocatable registers in the function...
      for (TargetRegisterClass::iterator I = (*RCI)->allocation_order_begin(MF),
             E = (*RCI)->allocation_order_end(MF); I != E; ++I)
        AllocatablePhysicalRegisters[*I] = true;  // The reg is allocatable!
  }

  // Build BBMap...
  unsigned BBNum = 0;
  for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
    BBMap[I->getBasicBlock()] = std::make_pair(I, BBNum++);

  // PhysRegInfo - Keep track of which instruction was the last use of a
  // physical register.  This is a purely local property, because all physical
  // register references as presumed dead across basic blocks.
  //
  MachineInstr *PhysRegInfoA[MRegisterInfo::FirstVirtualRegister];
  bool          PhysRegUsedA[MRegisterInfo::FirstVirtualRegister];
  std::fill(PhysRegInfoA, PhysRegInfoA+MRegisterInfo::FirstVirtualRegister,
	    (MachineInstr*)0);
  PhysRegInfo = PhysRegInfoA;
  PhysRegUsed = PhysRegUsedA;

  const TargetInstrInfo &TII = MF.getTarget().getInstrInfo();
  RegInfo = MF.getTarget().getRegisterInfo();

  /// Get some space for a respectable number of registers...
  VirtRegInfo.resize(64);

  // Calculate live variable information in depth first order on the CFG of the
  // function.  This guarantees that we will see the definition of a virtual
  // register before its uses due to dominance properties of SSA (except for PHI
  // nodes, which are treated as a special case).
  //
  const BasicBlock *Entry = MF.getFunction()->begin();
  for (df_iterator<const BasicBlock*> DFI = df_begin(Entry), E = df_end(Entry);
       DFI != E; ++DFI) {
    const BasicBlock *BB = *DFI;
    std::pair<MachineBasicBlock*, unsigned> &BBRec = BBMap.find(BB)->second;
    MachineBasicBlock *MBB = BBRec.first;
    unsigned BBNum = BBRec.second;

    // Loop over all of the instructions, processing them.
    for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
	 I != E; ++I) {
      MachineInstr *MI = *I;
      const TargetInstrDescriptor &MID = TII.get(MI->getOpcode());

      // Process all of the operands of the instruction...
      unsigned NumOperandsToProcess = MI->getNumOperands();

      // Unless it is a PHI node.  In this case, ONLY process the DEF, not any
      // of the uses.  They will be handled in other basic blocks.
      if (MI->getOpcode() == TargetInstrInfo::PHI)
	NumOperandsToProcess = 1;

      // Loop over implicit uses, using them.
      if (const unsigned *ImplicitUses = MID.ImplicitUses)
	for (unsigned i = 0; ImplicitUses[i]; ++i)
	  HandlePhysRegUse(ImplicitUses[i], MI);

      // Process all explicit uses...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
	MachineOperand &MO = MI->getOperand(i);
	if (MO.opIsUse() || MO.opIsDefAndUse()) {
	  if (MO.isVirtualRegister() && !MO.getVRegValueOrNull()) {
	    HandleVirtRegUse(getVarInfo(MO.getReg()), MBB, MI);
	  } else if (MO.isPhysicalRegister() &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
	    HandlePhysRegUse(MO.getReg(), MI);
	  }
	}
      }

      // Loop over implicit defs, defining them.
      if (const unsigned *ImplicitDefs = MID.ImplicitDefs)
	for (unsigned i = 0; ImplicitDefs[i]; ++i)
	  HandlePhysRegDef(ImplicitDefs[i], MI);

      // Process all explicit defs...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
	MachineOperand &MO = MI->getOperand(i);
	if (MO.opIsDef() || MO.opIsDefAndUse()) {
	  if (MO.isVirtualRegister()) {
	    VarInfo &VRInfo = getVarInfo(MO.getReg());

	    assert(VRInfo.DefBlock == 0 && "Variable multiply defined!");
	    VRInfo.DefBlock = MBB;                           // Created here...
	    VRInfo.DefInst = MI;
	    VRInfo.Kills.push_back(std::make_pair(MBB, MI)); // Defaults to dead
	  } else if (MO.isPhysicalRegister() &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
	    HandlePhysRegDef(MO.getReg(), MI);
	  }
	}
      }
    }

    // Handle any virtual assignments from PHI nodes which might be at the
    // bottom of this basic block.  We check all of our successor blocks to see
    // if they have PHI nodes, and if so, we simulate an assignment at the end
    // of the current block.
    for (succ_const_iterator SI = succ_begin(BB), E = succ_end(BB);
         SI != E; ++SI) {
      MachineBasicBlock *Succ = BBMap.find(*SI)->second.first;

      // PHI nodes are guaranteed to be at the top of the block...
      for (MachineBasicBlock::iterator I = Succ->begin(), E = Succ->end();
	   I != E && (*I)->getOpcode() == TargetInstrInfo::PHI; ++I) {
        MachineInstr *MI = *I;
	for (unsigned i = 1; ; i += 2)
	  if (MI->getOperand(i+1).getMachineBasicBlock() == MBB) {
	    MachineOperand &MO = MI->getOperand(i);
	    if (!MO.getVRegValueOrNull()) {
	      VarInfo &VRInfo = getVarInfo(MO.getReg());

	      // Only mark it alive only in the block we are representing...
	      MarkVirtRegAliveInBlock(VRInfo, BB);
	      break;   // Found the PHI entry for this block...
	    }
	  }
      }
    }

    // Loop over PhysRegInfo, killing any registers that are available at the
    // end of the basic block.  This also resets the PhysRegInfo map.
    for (unsigned i = 0, e = MRegisterInfo::FirstVirtualRegister; i != e; ++i)
      if (PhysRegInfo[i])
	HandlePhysRegDef(i, 0);
  }

  // Convert the information we have gathered into VirtRegInfo and transform it
  // into a form usable by RegistersKilled.
  //
  for (unsigned i = 0, e = VirtRegInfo.size(); i != e; ++i)
    for (unsigned j = 0, e = VirtRegInfo[i].Kills.size(); j != e; ++j) {
      if (VirtRegInfo[i].Kills[j].second == VirtRegInfo[i].DefInst)
	RegistersDead.insert(std::make_pair(VirtRegInfo[i].Kills[j].second,
		    i + MRegisterInfo::FirstVirtualRegister));

      else
	RegistersKilled.insert(std::make_pair(VirtRegInfo[i].Kills[j].second,
		    i + MRegisterInfo::FirstVirtualRegister));
    }

  return false;
}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/CIFactory.h"

#include "DeclCollector.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {
  //
  //  Dummy function so we can use dladdr to find the executable path.
  //
  void locate_cling_executable()
  {
  }

  /// \brief Retrieves the clang CC1 specific flags out of the compilation's
  /// jobs. Returns NULL on error.
  static const clang::driver::ArgStringList
  *GetCC1Arguments(clang::DiagnosticsEngine *Diagnostics,
                   clang::driver::Compilation *Compilation) {
    // We expect to get back exactly one Command job, if we didn't something
    // failed. Extract that job from the Compilation.
    const clang::driver::JobList &Jobs = Compilation->getJobs();
    if (!Jobs.size() || !isa<clang::driver::Command>(*Jobs.begin())) {
      // diagnose this...
      return NULL;
    }

    // The one job we find should be to invoke clang again.
    const clang::driver::Command *Cmd
      = cast<clang::driver::Command>(*Jobs.begin());
    if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
      // diagnose this...
      return NULL;
    }

    return &Cmd->getArguments();
  }

  CompilerInstance* CIFactory::createCI(llvm::StringRef code,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    return createCI(llvm::MemoryBuffer::getMemBuffer(code), argc, argv,
                    llvmdir);
  }

  CompilerInstance* CIFactory::createCI(llvm::MemoryBuffer* buffer,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    // Create an instance builder, passing the llvmdir and arguments.
    //
    //  Initialize the llvm library.
    llvm::InitializeNativeTarget();
    llvm::InitializeAllAsmPrinters();
    llvm::sys::Path resource_path;
    if (llvmdir) {
      resource_path = llvmdir;
      resource_path.appendComponent("lib");
      resource_path.appendComponent("clang");
      resource_path.appendComponent(CLANG_VERSION_STRING);
    } else {
      // FIXME: The first arg really does need to be argv[0] on FreeBSD.
      //
      // Note: The second arg is not used for Apple, FreeBSD, Linux,
      //       or cygwin, and can only be used on systems which support
      //       the use of dladdr().
      //
      // Note: On linux and cygwin this uses /proc/self/exe to find the path.
      //
      // Note: On Apple it uses _NSGetExecutablePath().
      //
      // Note: On FreeBSD it uses getprogpath().
      //
      // Note: Otherwise it uses dladdr().
      //
      resource_path
        = CompilerInvocation::GetResourcesPath("cling",
                                       (void*)(intptr_t) locate_cling_executable
                                               );
    }
    if (!resource_path.canRead()) {
      llvm::errs()
        << "ERROR in cling::CIFactory::createCI():\n  resource directory "
        << resource_path.str() << " not found!\n";
      resource_path = "";
    }

    //______________________________________
    DiagnosticOptions DefaultDiagnosticOptions;
    DefaultDiagnosticOptions.ShowColors = 1;
    TextDiagnosticPrinter* DiagnosticPrinter
      = new TextDiagnosticPrinter(llvm::errs(), DefaultDiagnosticOptions);
    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(new DiagnosticIDs());
    DiagnosticsEngine* Diagnostics
      = new DiagnosticsEngine(DiagIDs, DiagnosticPrinter,
                              /*Owns it*/ true); // LEAKS!

    std::vector<const char*> argvCompile(argv, argv + argc);
    // We do C++ by default; append right after argv[0] name
    // Only insert it if there is no other "-x":
    bool haveMinusX = false;
    for (const char* const* iarg = argv; !haveMinusX && iarg < argv + argc;
         ++iarg) {
      haveMinusX = !strcmp(*iarg, "-x");
    }
    if (!haveMinusX) {
      argvCompile.insert(argvCompile.begin() + 1,"-x");
      argvCompile.insert(argvCompile.begin() + 2, "c++");
    }
    argvCompile.push_back("-c");
    argvCompile.push_back("-");

    bool IsProduction = false;
    assert(IsProduction = true && "set IsProduction if asserts are on.");
    clang::driver::Driver Driver(argv[0], llvm::sys::getDefaultTargetTriple(),
                                 "cling.out",
                                 IsProduction,
                                 *Diagnostics);
    //Driver.setWarnMissingInput(false);
    Driver.setCheckInputsExist(false); // think foo.C(12)
    llvm::ArrayRef<const char*>RF(&(argvCompile[0]), argvCompile.size());
    llvm::OwningPtr<clang::driver::Compilation>
      Compilation(Driver.BuildCompilation(RF));
    const clang::driver::ArgStringList* CC1Args
      = GetCC1Arguments(Diagnostics, Compilation.get());
    if (CC1Args == NULL) {
      return 0;
    }
    clang::CompilerInvocation*
      Invocation = new clang::CompilerInvocation; // LEAKS!
    clang::CompilerInvocation::CreateFromArgs(*Invocation, CC1Args->data() + 1,
                                              CC1Args->data() + CC1Args->size(),
                                              *Diagnostics);
    Invocation->getFrontendOpts().DisableFree = true;

    if (Invocation->getHeaderSearchOpts().UseBuiltinIncludes &&
        !resource_path.empty()) {
      // Update ResourceDir
      // header search opts' entry for resource_path/include isn't
      // updated by providing a new resource path; update it manually.
      clang::HeaderSearchOptions& Opts = Invocation->getHeaderSearchOpts();
      llvm::sys::Path oldResInc(Opts.ResourceDir);
      oldResInc.appendComponent("include");
      llvm::sys::Path newResInc(resource_path);
      newResInc.appendComponent("include");
      bool foundOldResInc = false;
      for (unsigned i = 0, e = Opts.UserEntries.size();
           !foundOldResInc && i != e; ++i) {
        HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
        if (!E.IsUserSupplied && !E.IsFramework
            && E.Group == clang::frontend::System && E.IgnoreSysRoot
            && E.IsInternal && !E.ImplicitExternC
            && oldResInc.str() == E.Path) {
          E.Path = newResInc.str();
          foundOldResInc = true;
        }
      }

      Opts.ResourceDir = resource_path.str();
    }

    // Create and setup a compiler instance.
    CompilerInstance* CI = new CompilerInstance();
    CI->setInvocation(Invocation);

    CI->createDiagnostics(CC1Args->size(), CC1Args->data() + 1);
    {
      //
      //  Buffer the error messages while we process
      //  the compiler options.
      //

      // Set the language options, which cling needs
      SetClingCustomLangOpts(CI->getLangOpts());

      CI->getInvocation().getPreprocessorOpts().addMacroDef("__CLING__");
      if (CI->getDiagnostics().hasErrorOccurred()) {
        delete CI;
        CI = 0;
        return 0;
      }
    }
    CI->setTarget(TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
                                               Invocation->getTargetOpts()));
    if (!CI->hasTarget()) {
      delete CI;
      CI = 0;
      return 0;
    }
    CI->getTarget().setForcedLangOptions(CI->getLangOpts());
    SetClingTargetLangOpts(CI->getLangOpts(), CI->getTarget());

    // Set up source and file managers
    CI->createFileManager();
    CI->createSourceManager(CI->getFileManager());

    // Set up the memory buffer
    if (buffer)
      CI->getSourceManager().createMainFileIDForMemBuffer(buffer);

    // Set up the preprocessor
    CI->createPreprocessor();
    Preprocessor& PP = CI->getPreprocessor();
    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
                                           PP.getLangOpts());

    // Set up the ASTContext
    ASTContext *Ctx = new ASTContext(CI->getLangOpts(),
                                     PP.getSourceManager(), &CI->getTarget(),
                                     PP.getIdentifierTable(),
                                     PP.getSelectorTable(), PP.getBuiltinInfo(),
                                     /*size_reserve*/0, /*DelayInit*/false);
    CI->setASTContext(Ctx);

    // Set up the ASTConsumers
    CI->setASTConsumer(new DeclCollector());

    // Set up Sema
    CodeCompleteConsumer* CCC = 0;
    CI->createSema(TU_Prefix, CCC);

    // Set CodeGen options
    // CI->getCodeGenOpts().DebugInfo = 1; // want debug info
    // CI->getCodeGenOpts().EmitDeclMetadata = 1; // For unloading, for later
    CI->getCodeGenOpts().OptimizationLevel = 0; // see pure SSA, that comes out
    // When asserts are on, TURN ON not compare the VerifyModule
    assert(CI->getCodeGenOpts().VerifyModule = 1);
    return CI;
  }

  void CIFactory::SetClingCustomLangOpts(LangOptions& Opts) {
    Opts.EmitAllDecls = 1;
    Opts.Exceptions = 1;
    Opts.CXXExceptions = 1;
    Opts.Deprecated = 1;
    Opts.Modules = 1;
  }

  void CIFactory::SetClingTargetLangOpts(LangOptions& Opts,
                                         const TargetInfo& Target) {
    if (Target.getTriple().getOS() == llvm::Triple::Win32) {
      Opts.MicrosoftExt = 1;
      Opts.MSCVersion = 1300;
      // Should fix http://llvm.org/bugs/show_bug.cgi?id=10528
      Opts.DelayedTemplateParsing = 1;
    } else {
      Opts.MicrosoftExt = 0;
    }
  }
} // end namespace
<commit_msg>It doesn't leak, it is refcounted by the compiler instance.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/CIFactory.h"

#include "DeclCollector.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {
  //
  //  Dummy function so we can use dladdr to find the executable path.
  //
  void locate_cling_executable()
  {
  }

  /// \brief Retrieves the clang CC1 specific flags out of the compilation's
  /// jobs. Returns NULL on error.
  static const clang::driver::ArgStringList
  *GetCC1Arguments(clang::DiagnosticsEngine *Diagnostics,
                   clang::driver::Compilation *Compilation) {
    // We expect to get back exactly one Command job, if we didn't something
    // failed. Extract that job from the Compilation.
    const clang::driver::JobList &Jobs = Compilation->getJobs();
    if (!Jobs.size() || !isa<clang::driver::Command>(*Jobs.begin())) {
      // diagnose this...
      return NULL;
    }

    // The one job we find should be to invoke clang again.
    const clang::driver::Command *Cmd
      = cast<clang::driver::Command>(*Jobs.begin());
    if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
      // diagnose this...
      return NULL;
    }

    return &Cmd->getArguments();
  }

  CompilerInstance* CIFactory::createCI(llvm::StringRef code,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    return createCI(llvm::MemoryBuffer::getMemBuffer(code), argc, argv,
                    llvmdir);
  }

  CompilerInstance* CIFactory::createCI(llvm::MemoryBuffer* buffer,
                                        int argc,
                                        const char* const *argv,
                                        const char* llvmdir) {
    // Create an instance builder, passing the llvmdir and arguments.
    //
    //  Initialize the llvm library.
    llvm::InitializeNativeTarget();
    llvm::InitializeAllAsmPrinters();
    llvm::sys::Path resource_path;
    if (llvmdir) {
      resource_path = llvmdir;
      resource_path.appendComponent("lib");
      resource_path.appendComponent("clang");
      resource_path.appendComponent(CLANG_VERSION_STRING);
    } else {
      // FIXME: The first arg really does need to be argv[0] on FreeBSD.
      //
      // Note: The second arg is not used for Apple, FreeBSD, Linux,
      //       or cygwin, and can only be used on systems which support
      //       the use of dladdr().
      //
      // Note: On linux and cygwin this uses /proc/self/exe to find the path.
      //
      // Note: On Apple it uses _NSGetExecutablePath().
      //
      // Note: On FreeBSD it uses getprogpath().
      //
      // Note: Otherwise it uses dladdr().
      //
      resource_path
        = CompilerInvocation::GetResourcesPath("cling",
                                       (void*)(intptr_t) locate_cling_executable
                                               );
    }
    if (!resource_path.canRead()) {
      llvm::errs()
        << "ERROR in cling::CIFactory::createCI():\n  resource directory "
        << resource_path.str() << " not found!\n";
      resource_path = "";
    }

    //______________________________________
    DiagnosticOptions DefaultDiagnosticOptions;
    DefaultDiagnosticOptions.ShowColors = 1;
    TextDiagnosticPrinter* DiagnosticPrinter
      = new TextDiagnosticPrinter(llvm::errs(), DefaultDiagnosticOptions);
    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(new DiagnosticIDs());
    DiagnosticsEngine* Diagnostics
      = new DiagnosticsEngine(DiagIDs, DiagnosticPrinter,
                              /*Owns it*/ true); // LEAKS!

    std::vector<const char*> argvCompile(argv, argv + argc);
    // We do C++ by default; append right after argv[0] name
    // Only insert it if there is no other "-x":
    bool haveMinusX = false;
    for (const char* const* iarg = argv; !haveMinusX && iarg < argv + argc;
         ++iarg) {
      haveMinusX = !strcmp(*iarg, "-x");
    }
    if (!haveMinusX) {
      argvCompile.insert(argvCompile.begin() + 1,"-x");
      argvCompile.insert(argvCompile.begin() + 2, "c++");
    }
    argvCompile.push_back("-c");
    argvCompile.push_back("-");

    bool IsProduction = false;
    assert(IsProduction = true && "set IsProduction if asserts are on.");
    clang::driver::Driver Driver(argv[0], llvm::sys::getDefaultTargetTriple(),
                                 "cling.out",
                                 IsProduction,
                                 *Diagnostics);
    //Driver.setWarnMissingInput(false);
    Driver.setCheckInputsExist(false); // think foo.C(12)
    llvm::ArrayRef<const char*>RF(&(argvCompile[0]), argvCompile.size());
    llvm::OwningPtr<clang::driver::Compilation>
      Compilation(Driver.BuildCompilation(RF));
    const clang::driver::ArgStringList* CC1Args
      = GetCC1Arguments(Diagnostics, Compilation.get());
    if (CC1Args == NULL) {
      return 0;
    }
    clang::CompilerInvocation*
      Invocation = new clang::CompilerInvocation;
    clang::CompilerInvocation::CreateFromArgs(*Invocation, CC1Args->data() + 1,
                                              CC1Args->data() + CC1Args->size(),
                                              *Diagnostics);
    Invocation->getFrontendOpts().DisableFree = true;

    if (Invocation->getHeaderSearchOpts().UseBuiltinIncludes &&
        !resource_path.empty()) {
      // Update ResourceDir
      // header search opts' entry for resource_path/include isn't
      // updated by providing a new resource path; update it manually.
      clang::HeaderSearchOptions& Opts = Invocation->getHeaderSearchOpts();
      llvm::sys::Path oldResInc(Opts.ResourceDir);
      oldResInc.appendComponent("include");
      llvm::sys::Path newResInc(resource_path);
      newResInc.appendComponent("include");
      bool foundOldResInc = false;
      for (unsigned i = 0, e = Opts.UserEntries.size();
           !foundOldResInc && i != e; ++i) {
        HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
        if (!E.IsUserSupplied && !E.IsFramework
            && E.Group == clang::frontend::System && E.IgnoreSysRoot
            && E.IsInternal && !E.ImplicitExternC
            && oldResInc.str() == E.Path) {
          E.Path = newResInc.str();
          foundOldResInc = true;
        }
      }

      Opts.ResourceDir = resource_path.str();
    }

    // Create and setup a compiler instance.
    CompilerInstance* CI = new CompilerInstance();
    CI->setInvocation(Invocation);

    CI->createDiagnostics(CC1Args->size(), CC1Args->data() + 1);
    {
      //
      //  Buffer the error messages while we process
      //  the compiler options.
      //

      // Set the language options, which cling needs
      SetClingCustomLangOpts(CI->getLangOpts());

      CI->getInvocation().getPreprocessorOpts().addMacroDef("__CLING__");
      if (CI->getDiagnostics().hasErrorOccurred()) {
        delete CI;
        CI = 0;
        return 0;
      }
    }
    CI->setTarget(TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
                                               Invocation->getTargetOpts()));
    if (!CI->hasTarget()) {
      delete CI;
      CI = 0;
      return 0;
    }
    CI->getTarget().setForcedLangOptions(CI->getLangOpts());
    SetClingTargetLangOpts(CI->getLangOpts(), CI->getTarget());

    // Set up source and file managers
    CI->createFileManager();
    CI->createSourceManager(CI->getFileManager());

    // Set up the memory buffer
    if (buffer)
      CI->getSourceManager().createMainFileIDForMemBuffer(buffer);

    // Set up the preprocessor
    CI->createPreprocessor();
    Preprocessor& PP = CI->getPreprocessor();
    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
                                           PP.getLangOpts());

    // Set up the ASTContext
    ASTContext *Ctx = new ASTContext(CI->getLangOpts(),
                                     PP.getSourceManager(), &CI->getTarget(),
                                     PP.getIdentifierTable(),
                                     PP.getSelectorTable(), PP.getBuiltinInfo(),
                                     /*size_reserve*/0, /*DelayInit*/false);
    CI->setASTContext(Ctx);

    // Set up the ASTConsumers
    CI->setASTConsumer(new DeclCollector());

    // Set up Sema
    CodeCompleteConsumer* CCC = 0;
    CI->createSema(TU_Prefix, CCC);

    // Set CodeGen options
    // CI->getCodeGenOpts().DebugInfo = 1; // want debug info
    // CI->getCodeGenOpts().EmitDeclMetadata = 1; // For unloading, for later
    CI->getCodeGenOpts().OptimizationLevel = 0; // see pure SSA, that comes out
    // When asserts are on, TURN ON not compare the VerifyModule
    assert(CI->getCodeGenOpts().VerifyModule = 1);
    return CI;
  }

  void CIFactory::SetClingCustomLangOpts(LangOptions& Opts) {
    Opts.EmitAllDecls = 1;
    Opts.Exceptions = 1;
    Opts.CXXExceptions = 1;
    Opts.Deprecated = 1;
    Opts.Modules = 1;
  }

  void CIFactory::SetClingTargetLangOpts(LangOptions& Opts,
                                         const TargetInfo& Target) {
    if (Target.getTriple().getOS() == llvm::Triple::Win32) {
      Opts.MicrosoftExt = 1;
      Opts.MSCVersion = 1300;
      // Should fix http://llvm.org/bugs/show_bug.cgi?id=10528
      Opts.DelayedTemplateParsing = 1;
    } else {
      Opts.MicrosoftExt = 0;
    }
  }
} // end namespace
<|endoftext|>


<commit_before>#pragma once

#include <cassert>
#include <string>

#include "fixfmt/text.hh"

//------------------------------------------------------------------------------

namespace fixfmt {

using std::string;

class Bool
{
private:

  size_t const size_;
  bool const pad_left_;

  string const true_;
  string const false_;

public:

  Bool(
      string const& true_str,
      string const& false_str,
      size_t size,
      bool pad_left)
  : size_(size),
    pad_left_(pad_left),
    true_(palide(true_str, size, "", " ", 1.0, pad_left)),
    false_(palide(false_str, size, "", " ", 1.0, pad_left))
  {
    assert(true_.size() == size_);
    assert(false_.size() == size_);
  }

  Bool(
    string const& true_str="True",
    string const& false_str="False")
    : Bool(
        true_str, false_str,
        std::max(true_str.size(), false_str.size()),
        false)
  {
  }

  size_t        get_width()     const { return size_; }

  size_t        get_size()      const { return size_; }
  bool          get_pad_left()  const { return pad_left_; }

  string operator()(bool val) const
  {
    return val ? true_ : false_;
  }

};

}  // namespace fixfmt

<commit_msg>Correct bool string lengths.<commit_after>#pragma once

#include <cassert>
#include <string>

#include "fixfmt/text.hh"

//------------------------------------------------------------------------------

namespace fixfmt {

using std::string;

class Bool
{
private:

  size_t const size_;
  bool const pad_left_;

  string const true_;
  string const false_;

public:

  Bool(
      string const& true_str,
      string const& false_str,
      size_t size,
      bool pad_left)
  : size_(size),
    pad_left_(pad_left),
    true_(palide(true_str, size, "", " ", 1.0, pad_left)),
    false_(palide(false_str, size, "", " ", 1.0, pad_left))
  {
    assert(true_.size() == size_);
    assert(false_.size() == size_);
  }

  Bool(
    string const& true_str="True",
    string const& false_str="False")
    : Bool(
        true_str, false_str,
        std::max(string_length(true_str), string_length(false_str)),
        false)
  {
  }

  size_t        get_width()     const { return size_; }

  size_t        get_size()      const { return size_; }
  bool          get_pad_left()  const { return pad_left_; }

  string operator()(bool val) const
  {
    return val ? true_ : false_;
  }

};

}  // namespace fixfmt

<|endoftext|>


<commit_before>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "streams.h"
#include "support/allocators/zeroafterfree.h"
#include "test/test_bitcoin.h"

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>

using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
    std::vector<char> in;
    std::vector<char> expected_xor;
    std::vector<unsigned char> key;
    CDataStream ds(in, 0, 0);

    // Degenerate case

    key += '\x00','\x00';
    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));

    in += '\x0f','\xf0';
    expected_xor += '\xf0','\x0f';

    // Single character key

    ds.clear();
    ds.insert(ds.begin(), in.begin(), in.end());
    key.clear();

    key += '\xff';
    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));

    // Multi character key

    in.clear();
    expected_xor.clear();
    in += '\xf0','\x0f';
    expected_xor += '\x0f','\x00';

    ds.clear();
    ds.insert(ds.begin(), in.begin(), in.end());

    key.clear();
    key += '\xff','\x0f';

    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>[issue-210] removed 'using namespace std' from streams_tests.cpp<commit_after>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "streams.h"
#include "test/test_bitcoin.h"

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/test/unit_test.hpp>

using namespace boost::assign; // bring 'operator+=()' into scope

BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
    std::vector<char> in;
    std::vector<char> expected_xor;
    std::vector<unsigned char> key;
    CDataStream ds(in, 0, 0);

    // Degenerate case

    key += '\x00','\x00';
    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));

    in += '\x0f','\xf0';
    expected_xor += '\xf0','\x0f';

    // Single character key

    ds.clear();
    ds.insert(ds.begin(), in.begin(), in.end());
    key.clear();

    key += '\xff';
    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));

    // Multi character key

    in.clear();
    expected_xor.clear();
    in += '\xf0','\x0f';
    expected_xor += '\x0f','\x00';

    ds.clear();
    ds.insert(ds.begin(), in.begin(), in.end());

    key.clear();
    key += '\xff','\x0f';

    ds.Xor(key);
    BOOST_CHECK_EQUAL(
            std::string(expected_xor.begin(), expected_xor.end()),
            std::string(ds.begin(), ds.end()));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>