aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Mips
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Mips')
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp15
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsMCNaCl.cpp261
-rw-r--r--lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h19
-rw-r--r--lib/Target/Mips/Mips.h14
-rw-r--r--lib/Target/Mips/MipsAsmPrinter.cpp45
-rw-r--r--lib/Target/Mips/MipsAsmPrinter.h4
-rw-r--r--lib/Target/Mips/MipsISelDAGToDAG.cpp2
-rw-r--r--lib/Target/Mips/MipsISelLowering.cpp58
-rw-r--r--lib/Target/Mips/MipsISelLowering.h5
-rw-r--r--lib/Target/Mips/MipsInstrFPU.td9
-rw-r--r--lib/Target/Mips/MipsInstrInfo.td33
-rw-r--r--lib/Target/Mips/MipsMCInstLower.cpp45
-rw-r--r--lib/Target/Mips/MipsNaClHeaders.cpp128
-rw-r--r--lib/Target/Mips/MipsNaClRewritePass.cpp333
-rw-r--r--lib/Target/Mips/MipsNaClRewritePass.h21
-rw-r--r--lib/Target/Mips/MipsRegisterInfo.cpp1
-rw-r--r--lib/Target/Mips/MipsSubtarget.cpp3
-rw-r--r--lib/Target/Mips/MipsSubtarget.h9
-rw-r--r--lib/Target/Mips/MipsTargetMachine.cpp8
-rw-r--r--lib/Target/Mips/MipsTargetObjectFile.cpp23
20 files changed, 1030 insertions, 6 deletions
diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 9a35bb6bd7..9a94c75e2f 100644
--- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -14,6 +14,7 @@
#include "MipsFixupKinds.h"
#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "MCTargetDesc/MipsMCNaCl.h" // @LOCALMOD
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCDirectives.h"
@@ -239,6 +240,20 @@ public:
OW->Write32(0);
return true;
}
+
+ // @LOCALMOD-BEGIN
+ // FIXME! NaCl should INHERIT from MipsAsmBackend, not add to it.
+ unsigned getBundleSize() const {
+ return (OSType == Triple::NativeClient) ? 16 : 0;
+ }
+
+ bool CustomExpandInst(const MCInst &Inst, MCStreamer &Out) const {
+ if (OSType == Triple::NativeClient) {
+ return CustomExpandInstNaClMips(Inst, Out);
+ }
+ return false;
+ }
+ // @LOCALMOD-END
}; // class MipsAsmBackend
} // namespace
diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.cpp
new file mode 100644
index 0000000000..d39a60d41c
--- /dev/null
+++ b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.cpp
@@ -0,0 +1,261 @@
+//=== MipsMCNaCl.cpp - Expansion of NaCl pseudo-instructions --*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "mips-mc-nacl"
+
+#include "MCTargetDesc/MipsBaseInfo.h"
+#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+/// Two helper functions for emitting the actual guard instructions
+
+static void EmitMask(MCStreamer &Out,
+ unsigned Addr, unsigned Mask) {
+ // and \Addr, \Addr, \Mask
+ MCInst MaskInst;
+ MaskInst.setOpcode(Mips::AND);
+ MaskInst.addOperand(MCOperand::CreateReg(Addr));
+ MaskInst.addOperand(MCOperand::CreateReg(Addr));
+ MaskInst.addOperand(MCOperand::CreateReg(Mask));
+ Out.EmitInstruction(MaskInst);
+}
+
+// This is ONLY used for sandboxing stack changes.
+// The reason why SFI_NOP_IF_AT_BUNDLE_END gets handled here is that
+// it must ensure that the two instructions are in the same bundle.
+// It just so happens that the SFI_NOP_IF_AT_BUNDLE_END is always
+// emitted in conjunction with a SFI_DATA_MASK
+//
+static void EmitDataMask(int I, MCInst Saved[], MCStreamer &Out) {
+ assert(I == 3 &&
+ (Mips::SFI_NOP_IF_AT_BUNDLE_END == Saved[0].getOpcode()) &&
+ (Mips::SFI_DATA_MASK == Saved[2].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering");
+
+ unsigned Addr = Saved[2].getOperand(0).getReg();
+ unsigned Mask = Saved[2].getOperand(2).getReg();
+ assert((Mips::SP == Addr) && "Unexpected register at stack guard");
+
+ Out.EmitBundleLock();
+ Out.EmitInstruction(Saved[1]);
+ EmitMask(Out, Addr, Mask);
+ Out.EmitBundleUnlock();
+}
+
+static void EmitDirectGuardCall(int I, MCInst Saved[],
+ MCStreamer &Out) {
+ // sfi_call_preamble --->
+ // sfi_nops_to_force_slot2
+ assert(I == 3 && (Mips::SFI_GUARD_CALL == Saved[0].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL");
+ Out.EmitBundleAlignEnd();
+ Out.EmitBundleLock();
+ Out.EmitInstruction(Saved[1]);
+ Out.EmitInstruction(Saved[2]);
+ Out.EmitBundleUnlock();
+}
+
+static void EmitIndirectGuardCall(int I, MCInst Saved[],
+ MCStreamer &Out) {
+ // sfi_indirect_call_preamble link --->
+ // sfi_nops_to_force_slot1
+ // sfi_code_mask \link \link \maskreg
+ assert(I == 3 && (Mips::SFI_GUARD_INDIRECT_CALL == Saved[0].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering SFI_GUARD_INDIRECT_CALL");
+
+ unsigned Addr = Saved[0].getOperand(0).getReg();
+ unsigned Mask = Saved[0].getOperand(2).getReg();
+
+ Out.EmitBundleAlignEnd();
+ Out.EmitBundleLock();
+ EmitMask(Out, Addr, Mask);
+ Out.EmitInstruction(Saved[1]);
+ Out.EmitInstruction(Saved[2]);
+ Out.EmitBundleUnlock();
+}
+
+static void EmitIndirectGuardJmp(int I, MCInst Saved[], MCStreamer &Out) {
+ // sfi_indirect_jump_preamble link --->
+ // sfi_nop_if_at_bundle_end
+ // sfi_code_mask \link \link \maskreg
+ assert(I == 2 && (Mips::SFI_GUARD_INDIRECT_JMP == Saved[0].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering SFI_GUARD_INDIRECT_JMP");
+ unsigned Addr = Saved[0].getOperand(0).getReg();
+ unsigned Mask = Saved[0].getOperand(2).getReg();
+
+ Out.EmitBundleLock();
+ EmitMask(Out, Addr, Mask);
+ Out.EmitInstruction(Saved[1]);
+ Out.EmitBundleUnlock();
+}
+
+static void EmitGuardReturn(int I, MCInst Saved[], MCStreamer &Out) {
+ // sfi_return_preamble reg --->
+ // sfi_nop_if_at_bundle_end
+ // sfi_code_mask \reg \reg \maskreg
+ assert(I == 2 && (Mips::SFI_GUARD_RETURN == Saved[0].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering SFI_GUARD_RETURN");
+ unsigned Reg = Saved[0].getOperand(0).getReg();
+ unsigned Mask = Saved[0].getOperand(2).getReg();
+
+ Out.EmitBundleLock();
+ EmitMask(Out, Reg, Mask);
+ Out.EmitInstruction(Saved[1]);
+ Out.EmitBundleUnlock();
+}
+
+static void EmitGuardLoadOrStore(int I, MCInst Saved[], MCStreamer &Out) {
+ // sfi_load_store_preamble reg --->
+ // sfi_nop_if_at_bundle_end
+ // sfi_data_mask \reg \reg \maskreg
+ assert(I == 2 && (Mips::SFI_GUARD_LOADSTORE == Saved[0].getOpcode()) &&
+ "Unexpected SFI Pseudo while lowering SFI_GUARD_LOADSTORE");
+ unsigned Reg = Saved[0].getOperand(0).getReg();
+ unsigned Mask = Saved[0].getOperand(2).getReg();
+
+ Out.EmitBundleLock();
+ EmitMask(Out, Reg, Mask);
+ Out.EmitInstruction(Saved[1]);
+ Out.EmitBundleUnlock();
+}
+
+namespace llvm {
+// CustomExpandInstNaClMips -
+// If Inst is a NaCl pseudo instruction, emits the substitute
+// expansion to the MCStreamer and returns true.
+// Otherwise, returns false.
+//
+// NOTE: Each time this function calls Out.EmitInstruction(), it will be
+// called again recursively to rewrite the new instruction being emitted.
+// Care must be taken to ensure that this does not result in an infinite
+// loop. Also, global state must be managed carefully so that it is
+// consistent during recursive calls.
+//
+// We need global state to keep track of the explicit prefix (PREFIX_*)
+// instructions. Unfortunately, the assembly parser prefers to generate
+// these instead of combined instructions. At this time, having only
+// one explicit prefix is supported.
+
+
+bool CustomExpandInstNaClMips(const MCInst &Inst, MCStreamer &Out) {
+ const int MaxSaved = 4;
+ static MCInst Saved[MaxSaved];
+ static int SaveCount = 0;
+ static int I = 0;
+ // This routine only executes if RecurseGuard == 0
+ static bool RecurseGuard = false;
+
+ // If we are emitting to .s, just emit all pseudo-instructions directly.
+ if (Out.hasRawTextSupport()) {
+ return false;
+ }
+
+ //No recursive calls allowed;
+ if (RecurseGuard) return false;
+
+ unsigned Opc = Inst.getOpcode();
+
+ DEBUG(dbgs() << "CustomExpandInstNaClMips("; Inst.dump(); dbgs() << ")\n");
+
+ // Note: SFI_NOP_IF_AT_BUNDLE_END is only emitted directly as part of
+ // a stack guard in conjunction with a SFI_DATA_MASK
+
+ // Logic:
+ // This is somewhat convoluted, but in the current model, the SFI
+ // guard pseudo instructions occur PRIOR to the actual instruction.
+ // So, the bundling/alignment operation has to refer to the FOLLOWING
+ // one or two instructions.
+ //
+ // When a SFI_* pseudo is detected, it is saved. Then, the saved SFI_*
+ // pseudo and the very next one or two instructions are used as arguments to
+ // the Emit*() functions in this file. This is the reason why we have a
+ // doublely nested switch here. First, to save the SFI_* pseudo, then to
+ // emit it and the next instruction
+
+ // By default, we only need to save two or three instructions
+
+ if ((I == 0) && (SaveCount == 0)) {
+ // Base State, no saved instructions.
+ // If the current instruction is a SFI instruction, set the SaveCount
+ // and fall through.
+ switch (Opc) {
+ default:
+ SaveCount = 0; // Nothing to do.
+ return false; // Handle this Inst elsewhere.
+ case Mips::SFI_NOP_IF_AT_BUNDLE_END:
+ case Mips::SFI_GUARD_CALL:
+ case Mips::SFI_GUARD_INDIRECT_CALL:
+ SaveCount = 3;
+ break;
+ case Mips::SFI_DATA_MASK:
+ SaveCount = 0; // Do nothing.
+ break;
+ case Mips::SFI_GUARD_INDIRECT_JMP:
+ case Mips::SFI_GUARD_RETURN:
+ case Mips::SFI_GUARD_LOADSTORE:
+ SaveCount = 2;
+ break;
+ }
+ }
+
+ if (I < SaveCount) {
+ // Othewise, save the current Inst and return
+ Saved[I++] = Inst;
+ if (I < SaveCount)
+ return true;
+ // Else fall through to next stat
+ }
+
+ if (SaveCount > 0) {
+ assert(I == SaveCount && "Bookeeping Error");
+ SaveCount = 0; // Reset for next iteration
+ // The following calls may call Out.EmitInstruction()
+ // which must not again call CustomExpandInst ...
+ // So set RecurseGuard = 1;
+ RecurseGuard = true;
+
+ switch (Saved[0].getOpcode()) {
+ default: /* No action required */ break;
+ case Mips::SFI_NOP_IF_AT_BUNDLE_END:
+ EmitDataMask(I, Saved, Out);
+ break;
+ case Mips::SFI_DATA_MASK:
+ assert(0 && "Unexpected NOP_IF_AT_BUNDLE_END as a Saved Inst");
+ break;
+ case Mips::SFI_GUARD_CALL:
+ EmitDirectGuardCall(I, Saved, Out);
+ break;
+ case Mips::SFI_GUARD_INDIRECT_CALL:
+ EmitIndirectGuardCall(I, Saved, Out);
+ break;
+ case Mips::SFI_GUARD_INDIRECT_JMP:
+ EmitIndirectGuardJmp(I, Saved, Out);
+ break;
+ case Mips::SFI_GUARD_RETURN:
+ EmitGuardReturn(I, Saved, Out);
+ break;
+ case Mips::SFI_GUARD_LOADSTORE:
+ EmitGuardLoadOrStore(I, Saved, Out);
+ break;
+ }
+ I = 0; // Reset I for next.
+ assert(RecurseGuard && "Illegal Depth");
+ RecurseGuard = false;
+ return true;
+ }
+ return false;
+}
+
+} // namespace llvm
diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h
new file mode 100644
index 0000000000..c90502ec33
--- /dev/null
+++ b/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h
@@ -0,0 +1,19 @@
+//===-- MipsMCNaCl.h - Prototype for CustomExpandInstNaClMips ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MIPSMCNACL_H
+#define MIPSMCNACL_H
+
+namespace llvm {
+ class MCInst;
+ class MCStreamer;
+ bool CustomExpandInstNaClMips(const MCInst &Inst, MCStreamer &Out);
+}
+
+#endif
diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h
index 2963f7e7fa..411030aaa1 100644
--- a/lib/Target/Mips/Mips.h
+++ b/lib/Target/Mips/Mips.h
@@ -18,6 +18,16 @@
#include "MCTargetDesc/MipsMCTargetDesc.h"
#include "llvm/Target/TargetMachine.h"
+/* @LOCALMOD-START */
+namespace llvm {
+
+namespace Mips {
+ extern unsigned LoadStoreStackMaskReg;
+ extern unsigned IndirectBranchMaskReg;
+}
+} // End llvm namespace
+/* @LOCALMOD-END */
+
namespace llvm {
class MipsTargetMachine;
class FunctionPass;
@@ -28,6 +38,10 @@ namespace llvm {
FunctionPass *createMipsJITCodeEmitterPass(MipsTargetMachine &TM,
JITCodeEmitter &JCE);
+ // @LOCALMOD-START
+ FunctionPass *createMipsNaClRewritePass();
+ // @LOCALMOD-END
+
} // end namespace llvm;
#endif
diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp
index 6ca41624d3..1bf4a542d8 100644
--- a/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -229,13 +229,24 @@ const char *MipsAsmPrinter::getCurrentABIString() const {
}
void MipsAsmPrinter::EmitFunctionEntryLabel() {
- if (OutStreamer.hasRawTextSupport()) {
+ // @LOCALMOD-START
+ // make sure function entry is aligned. We use XmagicX as our basis
+ // for alignment decisions (c.f. assembler sfi macros).
+ int alignment = MF->getAlignment();
+ if (alignment < 4) alignment = 4;
+ EmitAlignment(alignment);
+ if (Subtarget->isTargetNaCl() && OutStreamer.hasRawTextSupport()) {
if (Subtarget->inMips16Mode())
OutStreamer.EmitRawText(StringRef("\t.set\tmips16"));
else
OutStreamer.EmitRawText(StringRef("\t.set\tnomips16"));
// leave out until FSF available gas has micromips changes
// OutStreamer.EmitRawText(StringRef("\t.set\tnomicromips"));
+ OutStreamer.EmitRawText(StringRef("\t.set XmagicX, .\n"));
+ }
+ // @LOCALMOD-END
+
+ if (OutStreamer.hasRawTextSupport()) {
OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName()));
}
OutStreamer.EmitLabel(CurrentFnSym);
@@ -539,6 +550,10 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
}
+// @LOCALMOD-START
+extern void EmitMipsSFIHeaders(raw_ostream &O);
+// @LOCALMOD-END
+
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
// FIXME: Use SwitchSection.
@@ -560,7 +575,35 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
// return to previous section
if (OutStreamer.hasRawTextSupport())
OutStreamer.EmitRawText(StringRef("\t.previous"));
+
+ // @LOCALMOD-START
+ if (Subtarget->isTargetNaCl() && OutStreamer.hasRawTextSupport()) {
+ std::string str;
+ raw_string_ostream OS(str);
+ EmitMipsSFIHeaders(OS);
+ OutStreamer.EmitRawText(StringRef(OS.str()));
+ }
+ // @LOCALMOD-END
+}
+
+// @LOCALMOD-START
+unsigned MipsAsmPrinter::GetTargetLabelAlign(const MachineInstr *MI) const {
+ if (Subtarget->isTargetNaCl()) {
+ switch (MI->getOpcode()) {
+ default: return 0;
+ // These labels may indicate an indirect entry point that is
+ // externally reachable and hence must be bundle aligned.
+ // Note: these labels appear to be always at basic block beginnings
+ // so it may be possible to simply set the MBB alignment.
+ // However, it is unclear whether this always holds.
+ case TargetOpcode::EH_LABEL:
+ case TargetOpcode::GC_LABEL:
+ return 4;
+ }
+ }
+ return 0;
}
+// @LOCALMOD-END
MachineLocation
MipsAsmPrinter::getDebugValueLocation(const MachineInstr *MI) const {
diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h
index 94d8bfa105..efed6357a4 100644
--- a/lib/Target/Mips/MipsAsmPrinter.h
+++ b/lib/Target/Mips/MipsAsmPrinter.h
@@ -82,6 +82,10 @@ public:
void EmitStartOfAsmFile(Module &M);
virtual MachineLocation getDebugValueLocation(const MachineInstr *MI) const;
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
+
+ // @LOCALMOD-START
+ virtual unsigned GetTargetLabelAlign(const MachineInstr *MI) const;
+ // @LOCALMOD-END
};
}
diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp
index ceff6dd9b9..0d47303e92 100644
--- a/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -353,7 +353,7 @@ SelectAddr(SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset) {
if (LS &&
(LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) &&
- Subtarget.hasMips32r2Or64())
+ Subtarget.hasMips32r2Or64() && !Subtarget.isTargetNaCl()/*@LOCALMOD*/)
return false;
}
diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp
index d8097032ca..e9f330ffc1 100644
--- a/lib/Target/Mips/MipsISelLowering.cpp
+++ b/lib/Target/Mips/MipsISelLowering.cpp
@@ -321,6 +321,13 @@ MipsTargetLowering(MipsTargetMachine &TM)
setTruncStoreAction(MVT::i64, MVT::i32, Custom);
}
+ // @LOCALMOD-BEGIN
+ if (Subtarget->isTargetNaCl()) {
+ setOperationAction(ISD::NACL_TP_TLS_OFFSET, MVT::i32, Custom);
+ setOperationAction(ISD::NACL_TP_TDB_OFFSET, MVT::i32, Custom);
+ }
+ // @LOCALMOD-END
+
setTargetDAGCombine(ISD::ADDE);
setTargetDAGCombine(ISD::SUBE);
setTargetDAGCombine(ISD::SDIVREM);
@@ -870,6 +877,11 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
case ISD::STORE: return LowerSTORE(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, DAG);
+
+ // @LOCALMOD-BEGIN
+ case ISD::NACL_TP_TLS_OFFSET: return LowerNaClTpTlsOffset(Op, DAG);
+ case ISD::NACL_TP_TDB_OFFSET: return LowerNaClTpTdbOffset(Op, DAG);
+ // @LOCALMOD-END
}
return SDValue();
}
@@ -1766,6 +1778,24 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op,
return DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo);
}
+// @LOCALMOD-BEGIN
+
+// NaCl TLS setup / layout intrinsics.
+// See: native_client/src/untrusted/nacl/tls_params.h
+SDValue MipsTargetLowering::LowerNaClTpTlsOffset(SDValue Op,
+ SelectionDAG &DAG) const {
+ return DAG.getConstant(0, Op.getValueType().getSimpleVT());
+}
+
+SDValue MipsTargetLowering::LowerNaClTpTdbOffset(SDValue Op,
+ SelectionDAG &DAG) const {
+ DebugLoc dl = Op.getDebugLoc();
+ return DAG.getNode(ISD::SUB, dl, Op.getValueType().getSimpleVT(),
+ DAG.getConstant(0, Op.getValueType().getSimpleVT()),
+ Op.getOperand(0));
+}
+// @LOCALMOD-END
+
SDValue MipsTargetLowering::
LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
{
@@ -1780,6 +1810,34 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
TLSModel::Model model = getTargetMachine().getTLSModel(GV);
+ // @LOCALMOD-BEGIN
+ if (getTargetMachine().getSubtarget<MipsSubtarget>().isTargetNaCl()) {
+ SDVTList VTs = DAG.getVTList(MVT::i32);
+ SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
+ MipsII::MO_TPREL_HI);
+ SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
+ MipsII::MO_TPREL_LO);
+ SDValue Hi = DAG.getNode(MipsISD::Hi, dl, VTs, &TGAHi, 1);
+ SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, TGALo);
+ SDValue Offset = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo);
+
+ unsigned PtrSize = PtrVT.getSizeInBits();
+ IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize);
+
+ SDValue TlsGetAddr = DAG.getExternalSymbol("__tls_get_addr", PtrVT);
+
+ ArgListTy Args;
+ std::pair<SDValue, SDValue> CallResult =
+ LowerCallTo(DAG.getEntryNode(),
+ (Type *) Type::getInt32Ty(*DAG.getContext()),
+ false, false, false, false, 0, CallingConv::C, false,
+ false, true, TlsGetAddr, Args, DAG, dl);
+
+ SDValue ThreadPointer = CallResult.first;
+ return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset);
+ }
+ // @LOCALMOD-END
+
if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) {
// General Dynamic and Local Dynamic TLS Model.
unsigned Flag = (model == TLSModel::LocalDynamic) ? MipsII::MO_TLSLDM
diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h
index b4cc16c1ca..2dce449765 100644
--- a/lib/Target/Mips/MipsISelLowering.h
+++ b/lib/Target/Mips/MipsISelLowering.h
@@ -205,6 +205,11 @@ namespace llvm {
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
+ // @LOCALMOD-BEGIN
+ SDValue LowerNaClTpTlsOffset(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerNaClTpTdbOffset(SDValue Op, SelectionDAG &DAG) const;
+ // @LOCALMOD-END
+
virtual SDValue
LowerFormalArguments(SDValue Chain,
CallingConv::ID CallConv, bool isVarArg,
diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td
index 441d2e8702..fa6faf242d 100644
--- a/lib/Target/Mips/MipsInstrFPU.td
+++ b/lib/Target/Mips/MipsInstrFPU.td
@@ -281,23 +281,24 @@ let Predicates = [NotN64, NotMips64, HasStandardEncoding] in {
}
// Indexed loads and stores.
-let Predicates = [HasMips32r2Or64, HasStandardEncoding] in {
+let Predicates = [HasMips32r2Or64, NotNaCl/*@LOCALMOD*/] in {
def LWXC1 : FPIdxLoad<0x0, "lwxc1", FGR32, CPURegs, load>;
def SWXC1 : FPIdxStore<0x8, "swxc1", FGR32, CPURegs, store>;
}
-let Predicates = [HasMips32r2, NotMips64, HasStandardEncoding] in {
+let Predicates = [HasMips32r2, NotMips64, NotNaCl/*@LOCALMOD*/] in {
def LDXC1 : FPIdxLoad<0x1, "ldxc1", AFGR64, CPURegs, load>;
def SDXC1 : FPIdxStore<0x9, "sdxc1", AFGR64, CPURegs, store>;
}
-let Predicates = [HasMips64, NotN64, HasStandardEncoding], DecoderNamespace="Mips64" in {
+let Predicates = [HasMips64, NotN64, NotNaCl/*@LOCALMOD*/],
+ DecoderNamespace="Mips64" in {
def LDXC164 : FPIdxLoad<0x1, "ldxc1", FGR64, CPURegs, load>;
def SDXC164 : FPIdxStore<0x9, "sdxc1", FGR64, CPURegs, store>;
}
// n64
-let Predicates = [IsN64, HasStandardEncoding], isCodeGenOnly=1 in {
+let Predicates = [IsN64, NotNaCl/*@LOCALMOD*/], isCodeGenOnly=1 in {
def LWXC1_P8 : FPIdxLoad<0x0, "lwxc1", FGR32, CPU64Regs, load>;
def LDXC164_P8 : FPIdxLoad<0x1, "ldxc1", FGR64, CPU64Regs, load>;
def SWXC1_P8 : FPIdxStore<0x8, "swxc1", FGR32, CPU64Regs, store>;
diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td
index 685b785bd2..6fa94a96e5 100644
--- a/lib/Target/Mips/MipsInstrInfo.td
+++ b/lib/Target/Mips/MipsInstrInfo.td
@@ -170,6 +170,8 @@ def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">,
AssemblerPredicate<"FeatureMips32">;
def HasStandardEncoding : Predicate<"Subtarget.hasStandardEncoding()">,
AssemblerPredicate<"!FeatureMips16">;
+def IsNaCl : Predicate<"Subtarget.isTargetNaCl()">;
+def NotNaCl : Predicate<"!Subtarget.isTargetNaCl()">;
class MipsPat<dag pattern, dag result> : Pat<pattern, result> {
let Predicates = [HasStandardEncoding];
@@ -810,6 +812,37 @@ class SCBase<bits<6> Opc, string opstring, RegisterClass RC, Operand Mem> :
// Pseudo instructions
//===----------------------------------------------------------------------===//
+// @LOCALMOD-START
+
+// Older Macro based SFI Model
+def SFI_GUARD_LOADSTORE :
+MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$src1, CPURegs:$src2),
+ "sfi_load_store_preamble\t$dst, $src1, $src2", []>;
+
+def SFI_GUARD_INDIRECT_CALL :
+MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$src1, CPURegs:$src2),
+ "sfi_indirect_call_preamble\t$dst, $src1, $src2", []>;
+
+def SFI_GUARD_INDIRECT_JMP :
+MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$src1, CPURegs:$src2),
+ "sfi_indirect_jump_preamble\t$dst, $src1, $src2", []>;
+
+def SFI_GUARD_CALL :
+MipsPseudo<(outs), (ins), "sfi_call_preamble", []>;
+
+def SFI_GUARD_RETURN :
+MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$src1, CPURegs:$src2),
+ "sfi_return_preamble\t$dst, $src1, $src2", []>;
+
+def SFI_NOP_IF_AT_BUNDLE_END :
+MipsPseudo<(outs), (ins), "sfi_nop_if_at_bundle_end", []>;
+
+def SFI_DATA_MASK :
+MipsPseudo<(outs CPURegs:$dst), (ins CPURegs:$src1, CPURegs:$src2),
+ "sfi_data_mask\t$dst, $src1, $src2", []>;
+
+// @LOCALMOD-END
+
// Return RA.
let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in
def RetRA : PseudoSE<(outs), (ins), "", [(MipsRet)]>;
diff --git a/lib/Target/Mips/MipsMCInstLower.cpp b/lib/Target/Mips/MipsMCInstLower.cpp
index 5fa6339338..1d108ab192 100644
--- a/lib/Target/Mips/MipsMCInstLower.cpp
+++ b/lib/Target/Mips/MipsMCInstLower.cpp
@@ -160,3 +160,48 @@ void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
}
}
+
+ MCInst Instr4, Mask1, Mask2; // @LOCALMOD
+ // @LOCALMOD-START
+ MCOperand MaskReg = MCOperand::CreateReg(Mips::LoadStoreStackMaskReg);
+ // @LOCALMOD-END
+
+ // @LOCALMOD-START
+ if (AsmPrinter.TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) {
+ Mask1.setOpcode(Mips::SFI_GUARD_LOADSTORE);
+ Mask1.addOperand(Base);
+ Mask1.addOperand(Base);
+ Mask1.addOperand(MaskReg);
+
+ Mask2.setOpcode(Mips::SFI_GUARD_LOADSTORE);
+ Mask2.addOperand(Base);
+ Mask2.addOperand(Base);
+ Mask2.addOperand(MaskReg);
+ if (Opc == Mips::ULW || Opc == Mips::USW || Opc == Mips::ULHu) {
+ // FIXME: ULHu should be rewritten because it uses mips32r2 instr. INS
+ MCInsts.push_back(Mask1);
+ MCInsts.push_back(Instr1);
+ MCInsts.push_back(Mask2);
+ MCInsts.push_back(Instr2);
+ if (!TwoInstructions) MCInsts.push_back(Instr3);
+ return;
+ } else if (Opc == Mips::ULH) {
+ MCInsts.push_back(Mask1);
+ MCInsts.push_back(Instr1);
+ MCInsts.push_back(Mask2);
+ MCInsts.push_back(Instr2);
+ MCInsts.push_back(Instr3);
+ MCInsts.push_back(Instr4);
+ return;
+ } else if (Opc == Mips::USH) {
+ MCInsts.push_back(Mask1);
+ MCInsts.push_back(Instr1);
+ MCInsts.push_back(Instr2);
+ MCInsts.push_back(Mask2);
+ MCInsts.push_back(Instr3);
+ return;
+ } else {
+ llvm_unreachable("unaligned instruction not sandboxed");
+ }
+ }
+ // @LOCALMOD-END \ No newline at end of file
diff --git a/lib/Target/Mips/MipsNaClHeaders.cpp b/lib/Target/Mips/MipsNaClHeaders.cpp
new file mode 100644
index 0000000000..375c287d67
--- /dev/null
+++ b/lib/Target/Mips/MipsNaClHeaders.cpp
@@ -0,0 +1,128 @@
+//===-- MipsNaClHeaders.cpp - Print SFI headers to an Mips .s file --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the initial header string needed
+// for the Native Client target in Mips assembly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/raw_ostream.h"
+#include "MipsNaClRewritePass.h"
+#include <string>
+
+using namespace llvm;
+
+void EmitMipsSFIHeaders(raw_ostream &O) {
+ O << " # ========================================\n";
+ O << "# Branch: " << FlagSfiBranch << "\n";
+ O << "# Stack: " << FlagSfiStack << "\n";
+ O << "# Store: " << FlagSfiStore << "\n";
+ O << "# Load: " << FlagSfiLoad << "\n";
+
+ O << " # ========================================\n";
+ // NOTE: this macro does bundle alignment as follows
+ // if current bundle pos is X emit pX data items of value "val"
+ // NOTE: that pos will be one of: 0,4,8,12
+ //
+ O <<
+ "\t.macro sfi_long_based_on_pos p0 p1 p2 p3 val\n"
+ "\t.set pos, (. - XmagicX) % 16\n"
+ "\t.fill (((\\p3<<12)|(\\p2<<8)|(\\p1<<4)|\\p0)>>pos) & 15, 4, \\val\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_nop_if_at_bundle_end\n"
+ "\tsfi_long_based_on_pos 0 0 0 1 0x00000000\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_nops_to_force_slot3\n"
+ "\tsfi_long_based_on_pos 3 2 1 0 0x00000000\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_nops_to_force_slot2\n"
+ "\tsfi_long_based_on_pos 2 1 0 3 0x00000000\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_nops_to_force_slot1\n"
+ "\tsfi_long_based_on_pos 1 0 3 2 0x00000000\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O << " # ========================================\n";
+ O <<
+ "\t.macro sfi_data_mask reg1 reg2 maskreg\n"
+ "\tand \\reg1, \\reg2, \\maskreg\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_code_mask reg1 reg2 maskreg\n"
+ "\tand \\reg1, \\reg2, \\maskreg\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O << " # ========================================\n";
+ if (FlagSfiBranch) {
+ O <<
+ "\t.macro sfi_call_preamble\n"
+ "\tsfi_nops_to_force_slot2\n"
+ "\t.endm\n"
+ "\n\n";
+
+ O <<
+ "\t.macro sfi_return_preamble reg1 reg2 maskreg\n"
+ "\tsfi_nop_if_at_bundle_end\n"
+ "\tsfi_code_mask \\reg1, \\reg2, \\maskreg\n"
+ "\t.endm\n"
+ "\n\n";
+
+ // This is used just before "jr"
+ O <<
+ "\t.macro sfi_indirect_jump_preamble reg1 reg2 maskreg\n"
+ "\tsfi_nop_if_at_bundle_end\n"
+ "\tsfi_code_mask \\reg1, \\reg2, \\maskreg\n"
+ "\t.endm\n"
+ "\n\n";
+
+ // This is used just before "jalr"
+ O <<
+