Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -147,7 +147,8 @@ // removing another test for this situation downstream in the // callchain. // - if (I->isPseudo() && !Subtarget->inMips16Mode()) + if (I->isPseudo() && !Subtarget->inMips16Mode() + && !Subtarget->isTargetNaCl()) llvm_unreachable("Pseudo opcode found in EmitInstruction()"); MCInst TmpInst0; Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -855,6 +855,13 @@ // Pseudo instructions //===----------------------------------------------------------------------===// +// See the comment in MipsLongBranch.cpp why we need these two instructions. +def NACL_LONG_BRANCH_LUi : PseudoSE<(outs GPR32Opnd:$dst), + (ins brtarget:$tgt, brtarget:$baltgt), []>; + +def NACL_LONG_BRANCH_ADDiu : PseudoSE<(outs GPR32Opnd:$dst), + (ins GPR32Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>; + // Return RA. let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>; Index: lib/Target/Mips/MipsLongBranch.cpp =================================================================== --- lib/Target/Mips/MipsLongBranch.cpp +++ lib/Target/Mips/MipsLongBranch.cpp @@ -67,7 +67,8 @@ : MachineFunctionPass(ID), TM(tm), IsPIC(TM.getRelocationModel() == Reloc::PIC_), ABI(TM.getSubtarget().getTargetABI()), - LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 13 : 9)) {} + LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 13 : + (!TM.getSubtarget().isTargetNaCl() ? 9 : 10))) {} virtual const char *getPassName() const { return "Mips Long Branch"; @@ -268,7 +269,8 @@ BalTgtMBB->addSuccessor(TgtMBB); int64_t TgtAddress = MBBInfos[TgtMBB->getNumber()].Address; - unsigned BalTgtMBBSize = 5; + unsigned BalTgtMBBSize = (!TM.getSubtarget().isTargetNaCl() + ? 5 : 6); int64_t Offset = TgtAddress - (I.Address + I.Size - BalTgtMBBSize * 4); int64_t Lo = SignExtend64<16>(Offset & 0xffff); int64_t Hi = SignExtend64<16>(((Offset + 0x8000) >> 16) & 0xffff); @@ -295,23 +297,67 @@ BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA) .addReg(Mips::SP).addImm(0); - MIBundleBuilder(*LongBrMBB, Pos) - .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) - .append(BuildMI(*MF, DL, TII->get(Mips::LUi), Mips::AT).addImm(Hi)); - - Pos = BalTgtMBB->begin(); - - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::AT) - .addReg(Mips::AT).addImm(Lo); - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT) - .addReg(Mips::RA).addReg(Mips::AT); - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) - .addReg(Mips::SP).addImm(0); - - MIBundleBuilder(*BalTgtMBB, Pos) - .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) - .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) - .addReg(Mips::SP).addImm(8)); + if (!TM.getSubtarget().isTargetNaCl()) { + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::LUi), Mips::AT).addImm(Hi)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::AT) + .addReg(Mips::AT).addImm(Lo); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT) + .addReg(Mips::RA).addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) + .addReg(Mips::SP).addImm(0); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8)); + } else { + // LUi and ADDiu instructions create 32-bit offset of the target basic + // block from the target of BAL instruction. We cannot use immediate + // value for this offset (as non-NaCl version does) because it does not + // include additional sandboxing instructions that will be added in + // the MC layer. We therefore replace the offset with relocation + // expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt). This + // expressions are resolved during the fixup after all sandboxing code + // is added, so the values will always be correct. + // + // Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt) + // expressions at this point (it is possible only at the MC layer), + // we replace LUi and ADDiu with pseudo instructions + // NACL_LONG_BRANCH_LUi and NACL_LONG_BRANCH_ADDiu, and add both basic + // blocks as operands to these instructions. When lowering these pseudo + // instructions to LUi and ADDiu in the MC layer, we will create + // %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as + // operands to lowered instructions. + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::NACL_LONG_BRANCH_LUi), + Mips::AT).addMBB(TgtMBB).addMBB(BalTgtMBB)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::NACL_LONG_BRANCH_ADDiu), + Mips::AT).addReg(Mips::AT).addMBB(TgtMBB).addMBB(BalTgtMBB); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT) + .addReg(Mips::RA).addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) + .addReg(Mips::SP).addImm(0); + + // In NaCl, modifying the sp is not allowed in branch delay slot. + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + // Align target of JR instruction. + TgtMBB->setAlignment(4); + } } else { // $longbr: // daddiu $sp, $sp, -16 @@ -440,8 +486,21 @@ int ShVal = TM.getSubtarget().inMicroMipsMode() ? 2 : 4; // Check if offset fits into 16-bit immediate field of branches. - if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) - continue; + if (!TM.getSubtarget().isTargetNaCl()) { + if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) + continue; + } else { + int64_t Offset = computeOffset(I->Br) / ShVal; + + // This offset calculation does not include sandboxing instructions + // that will be added later in the MC layer. Since at this point we + // don't know the exact amount of code that "sanboxing" will add, we + // conservatively estimate that code will not grow more than 100%. + Offset *= 2; + + if (!ForceLongBranch && isInt<16>(Offset)) + continue; + } I->HasLongBranch = true; I->Size += LongBranchSeqSize * 4; Index: lib/Target/Mips/MipsMCInstLower.h =================================================================== --- lib/Target/Mips/MipsMCInstLower.h +++ lib/Target/Mips/MipsMCInstLower.h @@ -31,6 +31,10 @@ MipsMCInstLower(MipsAsmPrinter &asmprinter); void Initialize(MCContext *C); void Lower(const MachineInstr *MI, MCInst &OutMI) const; + MCOperand createSub(MachineBasicBlock *BB1, MachineBasicBlock *BB2, + bool Hi) const; + void lowerNaClLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const; + void lowerNaClLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI) const; MCOperand LowerOperand(const MachineOperand& MO, unsigned offset = 0) const; private: Index: lib/Target/Mips/MipsMCInstLower.cpp =================================================================== --- lib/Target/Mips/MipsMCInstLower.cpp +++ lib/Target/Mips/MipsMCInstLower.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "MipsMCInstLower.h" #include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCExpr.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -151,7 +152,63 @@ return MCOperand(); } +MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1, + MachineBasicBlock *BB2, + bool Hi) const { + const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::Create(BB1->getSymbol(), *Ctx); + const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::Create(BB2->getSymbol(), *Ctx); + const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Sym1, Sym2, *Ctx); + + if (Hi) + return MCOperand::CreateExpr(MipsMCExpr::CreateHi(Sub, *Ctx)); + else + return MCOperand::CreateExpr(MipsMCExpr::CreateLo(Sub, *Ctx)); +} + +void MipsMCInstLower::lowerNaClLongBranchLUi(const MachineInstr *MI, + MCInst &OutMI) const { + OutMI.setOpcode(Mips::LUi); + + // Lower register operand. + MCOperand Reg = LowerOperand(MI->getOperand(0)); + if (Reg.isValid()) + OutMI.addOperand(Reg); + + // Create %hi($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(1).getMBB(), + MI->getOperand(2).getMBB(), true)); +} + +void MipsMCInstLower::lowerNaClLongBranchADDiu(const MachineInstr *MI, + MCInst &OutMI) const { + OutMI.setOpcode(Mips::ADDiu); + + // Lower two register operands. + for (unsigned i = 0, e = 2; i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + MCOperand Reg = LowerOperand(MO); + + if (Reg.isValid()) + OutMI.addOperand(Reg); + } + + // Create %lo($tgt-$baltgt). + OutMI.addOperand(createSub(MI->getOperand(2).getMBB(), + MI->getOperand(3).getMBB(), false)); +} + void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + // See the comment in file MipsLongBranch.cpp why we need this two + // instructions in NaCl. + if (MI->getOpcode() == Mips::NACL_LONG_BRANCH_LUi) { + lowerNaClLongBranchLUi(MI, OutMI); + return; + } + if (MI->getOpcode() == Mips::NACL_LONG_BRANCH_ADDiu) { + lowerNaClLongBranchADDiu(MI, OutMI); + return; + } + OutMI.setOpcode(MI->getOpcode()); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { Index: test/MC/Mips/nacl-long-branch.ll =================================================================== --- /dev/null +++ test/MC/Mips/nacl-long-branch.ll @@ -0,0 +1,88 @@ +; RUN: llc -filetype=obj -O3 -mtriple mipsel-none-linux < %s \ +; RUN: | llvm-objdump -triple mipsel -disassemble -no-show-raw-insn - \ +; RUN: | FileCheck %s + +; RUN: llc -filetype=obj -force-mips-long-branch -O3 -mtriple mipsel-none-nacl \ +; RUN: < %s | llvm-objdump -triple mipsel -disassemble -no-show-raw-insn - \ +; RUN: | FileCheck %s -check-prefix=CHECK-NACL + + +declare void @f() + +define void @test(i32 %arg) { +entry: + %cmp = icmp eq i32 %arg, 0 + br i1 %cmp, label %if.then, label %if.end +if.then: + tail call void @f() + br label %if.end +if.end: + ret void +} + +; This file tests that MipsLongBranchPass works with sandboxing. +; The nonsandboxed code of the previous function is: + +; CHECK-LABEL: test: + +; CHECK: 0: lui $2, 0 +; CHECK: 4: addiu $2, $2, 0 +; CHECK: 8: addiu $sp, $sp, -[[OFFSET1:[0-9]+]] +; CHECK: c: sw $ra, [[OFFSET2:[0-9]+]]($sp) +; CHECK: 10: bnez $4, 20 +; CHECK: 14: addu $gp, $2, $25 +; CHECK: 18: lw $25, 0($gp) +; CHECK: 1c: jalr $25 +; CHECK: 20: nop +; CHECK: 24: lw $ra, [[OFFSET2:[0-9]+]]($sp) +; CHECK: 28: jr $ra +; CHECK: 2c: addiu $sp, $sp, [[OFFSET1]] + +; We pass -force-mips-long-branch option to llc to make sure that bnez +; instruction is expanded into long branch. We specifically test that +; in the expanded sandboxed long branch sequence the offset that LUi/ADDiu +; instructions create is the correct offset from the ADDiu instruction to the +; branch target (which is lw $ra, 20($sp) in this case). More precisely: +; +; 0x80 - 0x40 = 64, +; where 0x40 and 0x80 are addresses and 64 is in the "addiu" at 0x40. + +; 0: lui $2, 0 +; 4: addiu $2, $2, 0 +; 8: addiu $sp, $sp, -24 +; c: and $sp, $sp, $15 +; 10: sw $ra, 20($sp) +; 14: beq $4, $zero, 80 +; 18: addu $gp, $2, $25 +; 1c: nop +; 20: addiu $sp, $sp, -8 +; 24: and $sp, $sp, $15 +; 28: sw $ra, 0($sp) +; 2c: nop +; 30: nop +; 34: nop +; CHECK-NACL: 38: bal 8 +; CHECK-NACL-NEXT: 3c: lui $1, 0 +; CHECK-NACL-NEXT: 40: addiu $1, $1, 64 +; CHECK-NACL: addu $1, $ra, $1 +; CHECK-NACL: lw $ra, 0($sp) +; CHECK-NACL: nop +; CHECK-NACL: addiu $sp, $sp, 8 +; CHECK-NACL: and $sp, $sp, $15 +; CHECK-NACL: and $1, $1, $14 +; CHECK-NACL: jr $1 +; CHECK-NACL: nop +; 64: and $gp, $gp, $15 +; 68: lw $25, 0($gp) +; 6c: nop +; 70: nop +; 74: and $25, $25, $14 +; 78: jalr $25 +; 7c: nop +; CHECK-NACL: 80: lw $ra, 20($sp) +; 84: addiu $sp, $sp, 24 +; 88: and $sp, $sp, $15 +; 8c: nop +; 90: and $ra, $ra, $14 +; 94: jr $ra +; 98: nop