Index: lib/Target/ARM/ARMISelLowering.cpp |
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp |
index fe84f0d4f94212ff9118736b63d9282a9b9c379e..337a4ad62429470e0d27e9ea1f7d357fcfa358d4 100644 |
--- a/lib/Target/ARM/ARMISelLowering.cpp |
+++ b/lib/Target/ARM/ARMISelLowering.cpp |
@@ -49,6 +49,7 @@ |
#include "llvm/Support/MathExtras.h" |
#include "llvm/Target/TargetOptions.h" |
#include <utility> |
+ |
using namespace llvm; |
#define DEBUG_TYPE "arm-isel" |
@@ -67,6 +68,18 @@ ARMInterworking("arm-interworking", cl::Hidden, |
cl::desc("Enable / disable ARM interworking (for debugging only)"), |
cl::init(true)); |
+// @LOCALMOD-START |
+// PNaCl's build of compiler-rt does not define __aeabi_* functions for ARM |
+// yet. For Non-SFI NaCl, where we don't use "nacl" in the target triple, |
+// we use the following option to turn off use of the __aeabi_* functions. |
+// TODO(mseaborn): In the longer term, it would be cleaner to change the |
+// compiler-rt build to define __aeabi_* functions. |
+cl::opt<bool> |
+llvm::EnableARMAEABIFunctions("arm-enable-aeabi-functions", |
+ cl::desc("Allow using ARM __aeabi_* functions in generated code"), |
+ cl::init(true)); |
+// @LOCALMOD-END |
+ |
namespace { |
class ARMCCState : public CCState { |
public: |
@@ -247,8 +260,10 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM) |
setLibcallName(RTLIB::SRL_I128, nullptr); |
setLibcallName(RTLIB::SRA_I128, nullptr); |
+ // @LOCALMOD: use standard names and calling conventions for pnacl |
if (Subtarget->isAAPCS_ABI() && !Subtarget->isTargetMachO() && |
- !Subtarget->isTargetWindows()) { |
+ !Subtarget->isTargetWindows() && !Subtarget->isTargetNaCl() && |
+ EnableARMAEABIFunctions) { |
static const struct { |
const RTLIB::Libcall Op; |
const char * const Name; |
@@ -735,7 +750,11 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM) |
setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom); |
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); |
setOperationAction(ISD::BlockAddress, MVT::i32, Custom); |
- |
+ // @LOCALMOD-START |
+ if (!Subtarget->useInlineJumpTables()) |
+ setOperationAction(ISD::JumpTable, MVT::i32, Custom); |
+ // @LOCALMOD-END |
+ |
setOperationAction(ISD::TRAP, MVT::Other, Legal); |
// Use the default implementation. |
@@ -749,8 +768,22 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM) |
if (!Subtarget->isTargetMachO()) { |
// Non-MachO platforms may return values in these registers via the |
// personality function. |
- setExceptionPointerRegister(ARM::R0); |
- setExceptionSelectorRegister(ARM::R1); |
+ // @LOCALMOD-START |
+ if (Subtarget->isTargetNaCl()) { |
+ // we use the first caller saved regs here |
+ // c.f.: llvm-gcc/llvm-gcc-4.2/gcc/unwind-dw2.c::uw_install_context |
+ // NOTE: these are related to the _Unwind_PNaClSetResult{0,1} functions |
+ setExceptionPointerRegister(ARM::R4); |
+ setExceptionSelectorRegister(ARM::R5); |
+ |
+ setOperationAction(ISD::FRAME_TO_ARGS_OFFSET, MVT::i32, Custom); |
+ |
+ setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); |
+ } else { |
+ setExceptionPointerRegister(ARM::R0); |
+ setExceptionSelectorRegister(ARM::R1); |
+ } |
+ // @LOCALMOD-END |
} |
if (Subtarget->getTargetTriple().isWindowsItaniumEnvironment()) |
@@ -839,8 +872,12 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM) |
setOperationAction(ISD::BR_CC, MVT::i32, Custom); |
setOperationAction(ISD::BR_CC, MVT::f32, Custom); |
setOperationAction(ISD::BR_CC, MVT::f64, Custom); |
- setOperationAction(ISD::BR_JT, MVT::Other, Custom); |
- |
+ // @LOCALMOD-START |
+ //setOperationAction(ISD::BR_JT, MVT::Other, Custom); |
+ setOperationAction(ISD::BR_JT, MVT::Other, |
+ Subtarget->useInlineJumpTables() ? Custom : Expand); |
+ // @LOCALMOD-END |
+ |
// We don't support sin/cos/fmod/copysign/pow |
setOperationAction(ISD::FSIN, MVT::f64, Expand); |
setOperationAction(ISD::FSIN, MVT::f32, Expand); |
@@ -1006,6 +1043,10 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { |
case ARMISD::Wrapper: return "ARMISD::Wrapper"; |
case ARMISD::WrapperPIC: return "ARMISD::WrapperPIC"; |
case ARMISD::WrapperJT: return "ARMISD::WrapperJT"; |
+ // @LOCALMOD-START |
+ case ARMISD::WrapperJT2: return "ARMISD::WrapperJT2"; |
+ case ARMISD::EH_RETURN: return "ARMISD::EH_RETURN"; |
+ // @LOCALMOD-END |
case ARMISD::CALL: return "ARMISD::CALL"; |
case ARMISD::CALL_PRED: return "ARMISD::CALL_PRED"; |
case ARMISD::CALL_NOLINK: return "ARMISD::CALL_NOLINK"; |
@@ -2384,7 +2425,14 @@ static SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) { |
} |
unsigned ARMTargetLowering::getJumpTableEncoding() const { |
- return MachineJumpTableInfo::EK_Inline; |
+ // @LOCALMOD-BEGIN |
+ if (Subtarget->useInlineJumpTables()) { |
+ return MachineJumpTableInfo::EK_Inline; |
+ } else { |
+ // TODO: Find a better way to call the super-class. |
+ return TargetLowering::getJumpTableEncoding(); |
+ } |
+ // @LOCALMOD-END |
} |
SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, |
@@ -2417,12 +2465,69 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, |
return DAG.getNode(ARMISD::PIC_ADD, DL, PtrVT, Result, PICLabel); |
} |
+// @LOCALMOD-START |
+// more conventional jumptable implementation |
+SDValue ARMTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { |
+ assert(!Subtarget->useInlineJumpTables() && |
+ "inline jump tables not custom lowered"); |
+ const SDLoc dl(Op); |
+ EVT PTy = getPointerTy(); |
+ JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); |
+ SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); |
+ return DAG.getNode(ARMISD::WrapperJT2, dl, MVT::i32, JTI); |
+} |
+// @LOCALMOD-END |
+ |
// Lower ISD::GlobalTLSAddress using the "general dynamic" model |
SDValue |
ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, |
SelectionDAG &DAG) const { |
SDLoc dl(GA); |
EVT PtrVT = getPointerTy(); |
+ // @LOCALMOD-BEGIN |
+ SDValue Chain; |
+ SDValue Argument; |
+ |
+ if (!Subtarget->useConstIslands()) { |
+ // With constant islands "disabled" (moved to rodata), this constant pool |
+ // entry is no longer in text, and simultaneous PC relativeness |
+ // and CP Addr relativeness is no longer expressible. |
+ // So, instead of having: |
+ // |
+ // .LCPI12_0: |
+ // .long var(tlsgd)-((.LPC12_0+8) - .) |
+ // ... |
+ // ldr r2, .LCPI12_0 |
+ // .LPC12_0: |
+ // add r0, pc, r2 |
+ // |
+ // we have: |
+ // |
+ // .LCPI12_0: |
+ // .long var(tlsgd) |
+ // ... |
+ // // get addr of .LCPI12_0 into r2 |
+ // ldr r0, [r2] |
+ // add r0, r2, r0 |
+ // (1) No longer subtracting pc, so no longer adding that back |
+ // (2) Not adding "." in the CP entry, so adding it via instructions. |
+ // |
+ unsigned char PCAdj = 0; |
+ MachineFunction &MF = DAG.getMachineFunction(); |
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); |
+ unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); |
+ ARMConstantPoolValue *CPV = |
+ ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, |
+ ARMCP::CPValue, PCAdj, ARMCP::TLSGD, |
+ false); |
+ SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); |
+ CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); |
+ Argument = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, |
+ MachinePointerInfo::getConstantPool(), |
+ false, false, false, 0); |
+ Chain = Argument.getValue(1); |
+ Argument = DAG.getNode(ISD::ADD, dl, PtrVT, Argument, CPAddr); |
+ } else { // sort of @LOCALMOD-END |
unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; |
MachineFunction &MF = DAG.getMachineFunction(); |
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); |
@@ -2430,15 +2535,16 @@ ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, |
ARMConstantPoolValue *CPV = |
ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, |
ARMCP::CPValue, PCAdj, ARMCP::TLSGD, true); |
- SDValue Argument = DAG.getTargetConstantPool(CPV, PtrVT, 4); |
+ /*SDValue*/ Argument = DAG.getTargetConstantPool(CPV, PtrVT, 4); // @LOCALMOD |
Argument = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Argument); |
Argument = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Argument, |
MachinePointerInfo::getConstantPool(), |
false, false, false, 0); |
- SDValue Chain = Argument.getValue(1); |
+ /*SDValue*/ Chain = Argument.getValue(1); // @LOCALMOD |
SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); |
Argument = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Argument, PICLabel); |
+ } // @LOCALMOD-END |
// call __tls_get_addr. |
ArgListTy Args; |
@@ -2476,25 +2582,49 @@ ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, |
MachineFunction &MF = DAG.getMachineFunction(); |
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); |
unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); |
- // Initial exec model. |
- unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; |
- ARMConstantPoolValue *CPV = |
+ |
+ // @LOCALMOD-BEGIN |
+ if (!Subtarget->useConstIslands()) { |
+ // Similar to change to LowerToTLSGeneralDynamicModel, and |
+ // for the same reason. |
+ unsigned char PCAdj = 0; |
+ ARMConstantPoolValue *CPV = |
+ ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, |
+ ARMCP::CPValue, PCAdj, ARMCP::GOTTPOFF, |
+ false); |
+ SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); |
+ CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); |
+ Offset = DAG.getLoad(PtrVT, dl, Chain, CPAddr, |
+ MachinePointerInfo::getConstantPool(), |
+ false, false, false, 0); |
+ Chain = Offset.getValue(1); |
+ |
+ Offset = DAG.getNode(ISD::ADD, dl, PtrVT, Offset, CPAddr); |
+ |
+ Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, |
+ MachinePointerInfo::getConstantPool(), |
+ false, false, false, 0); |
+ } else { // sort of @LOCALMOD-END (indentation) |
+ // Initial exec model. |
+ unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; |
+ ARMConstantPoolValue *CPV = |
ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, |
ARMCP::CPValue, PCAdj, ARMCP::GOTTPOFF, |
true); |
- Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); |
- Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); |
- Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, |
- MachinePointerInfo::getConstantPool(), |
- false, false, false, 0); |
- Chain = Offset.getValue(1); |
+ Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); |
+ Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); |
+ Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, |
+ MachinePointerInfo::getConstantPool(), |
+ false, false, false, 0); |
+ Chain = Offset.getValue(1); |
- SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); |
- Offset = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Offset, PICLabel); |
+ SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); |
+ Offset = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Offset, PICLabel); |
- Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, |
- MachinePointerInfo::getConstantPool(), |
- false, false, false, 0); |
+ Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, |
+ MachinePointerInfo::getConstantPool(), |
+ false, false, false, 0); |
+ } // @LOCALMOD-END |
} else { |
// local exec model |
assert(model == TLSModel::LocalExec); |
@@ -2634,6 +2764,44 @@ SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, |
unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); |
EVT PtrVT = getPointerTy(); |
SDLoc dl(Op); |
+ |
+ // @LOCALMOD-BEGIN |
+ if (!Subtarget->useConstIslands()) { |
+ // With constant islands "disabled" (moved to rodata), the constant pool |
+ // entry is no longer in text, and the PC relativeness is |
+ // no longer expressible. |
+ // |
+ // Instead of having: |
+ // |
+ // .LCPI12_0: |
+ // .long _GLOBAL_OFFSET_TABLE_-(.LPC12_0+8) |
+ // ... |
+ // ldr r2, .LCPI12_0 |
+ // .LPC12_0: |
+ // add r0, pc, r2 |
+ // |
+ // Things to try: |
+ // (1) get the address of the GOT through a pc-relative MOVW / MOVT. |
+ // |
+ // movw r0, :lower16:_GLOBAL_OFFSET_TABLE_ - (.LPC12_0 + 8) |
+ // movt r0, :upper16:_GLOBAL_OFFSET_TABLE_ - (.LPC12_0 + 8) |
+ // .LPC12_0: |
+ // add r0, pc, r0 |
+ // |
+ // (2) Make the constant pool entry relative to its own location |
+ // |
+ // .LCPI12_0: |
+ // .long _GLOBAL_OFFSET_TABLE_-. |
+ // ... |
+ // // get address of LCPI12_0 into r0 (possibly 3 instructions for PIC) |
+ // ldr r1, [r0] |
+ // add r1, r0, r1 |
+ // |
+ // We will try (1) for now, since (2) takes about 3 more instructions |
+ // (and one of them is a load). |
+ return DAG.getNode(ARMISD::WrapperGOT, dl, MVT::i32); |
+ } |
+ // @LOCALMOD-END |
unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; |
ARMConstantPoolValue *CPV = |
ARMConstantPoolSymbol::Create(*DAG.getContext(), "_GLOBAL_OFFSET_TABLE_", |
@@ -2675,6 +2843,7 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, |
"RBIT intrinsic must have i32 type!"); |
return DAG.getNode(ARMISD::RBIT, dl, MVT::i32, Op.getOperand(1)); |
} |
+ case Intrinsic::nacl_read_tp: // @LOCALMOD |
case Intrinsic::arm_thread_pointer: { |
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); |
return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT); |
@@ -6078,6 +6247,38 @@ static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { |
DAG.getNode(ISD::BITCAST, DL, Op1VT, N01), Op1)); |
} |
+// @LOCALMOD-START |
+// An EH_RETURN is the result of lowering llvm.eh.return.i32 which in turn is |
+// generated from __builtin_eh_return (offset, handler) |
+// The effect of this is to adjust the stack pointer by "offset" |
+// and then branch to "handler". |
+SDValue ARMTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) |
+ const { |
+ SDValue Chain = Op.getOperand(0); |
+ SDValue Offset = Op.getOperand(1); |
+ SDValue Handler = Op.getOperand(2); |
+ SDLoc dl(Op); |
+ |
+ // Store stack offset in R2, jump target in R3, dummy return value in R0 |
+ // The dummy return value is needed to make the use-def chains happy, |
+ // because the EH_RETURN instruction uses the isReturn attribute, which |
+ // means preceding code needs to define the return register (R0 on ARM). |
+ // http://code.google.com/p/nativeclient/issues/detail?id=2643 |
+ unsigned OffsetReg = ARM::R2; |
+ unsigned AddrReg = ARM::R3; |
+ unsigned ReturnReg = ARM::R0; |
+ Chain = DAG.getCopyToReg(Chain, dl, OffsetReg, Offset); |
+ Chain = DAG.getCopyToReg(Chain, dl, AddrReg, Handler); |
+ Chain = DAG.getCopyToReg(Chain, dl, ReturnReg, DAG.getIntPtrConstant(0)); |
+ return DAG.getNode(ARMISD::EH_RETURN, dl, |
+ MVT::Other, |
+ Chain, |
+ DAG.getRegister(OffsetReg, MVT::i32), |
+ DAG.getRegister(AddrReg, getPointerTy())); |
+} |
+// @LOCALMOD-END |
+ |
+ |
static SDValue |
LowerSDIV_v4i8(SDValue X, SDValue Y, SDLoc dl, SelectionDAG &DAG) { |
// Convert to float |
@@ -6390,6 +6591,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { |
default: llvm_unreachable("Don't know how to custom lower this!"); |
case ISD::ConstantPool: return LowerConstantPool(Op, DAG); |
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); |
+ case ISD::JumpTable: return LowerJumpTable(Op, DAG); // @LOCALMOD |
case ISD::GlobalAddress: |
switch (Subtarget->getTargetTriple().getObjectFormat()) { |
default: llvm_unreachable("unknown object format"); |
@@ -6415,6 +6617,17 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { |
case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); |
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); |
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); |
+ // @LOCALMOD-START |
+ // The exact semantics of this ISD are not completely clear. |
+ // LLVM seems to always point the fp after the push ra and the old fp, i.e. |
+ // two register slots after the beginning of the stack frame. |
+ // It is not clear what happens when there is no frame pointer but |
+ // but llvm unlike gcc seems to always force one when this node is |
+ // encountered. |
+ case ISD::FRAME_TO_ARGS_OFFSET: return DAG.getIntPtrConstant(2*4); |
+ case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG); |
+ // @LOCALMOD-END |
+ |
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG); |
case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG); |
case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG); |
@@ -10305,6 +10518,15 @@ ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base, |
if (Subtarget->isThumb1Only()) |
return false; |
+ // @LOCALMOD-START |
+ // Avoid two reg addressing mode for loads and stores |
+ const bool restrict_addressing_modes_for_nacl = Subtarget->isTargetNaCl() && |
+ (N->getOpcode() == ISD::LOAD || N->getOpcode() == ISD::STORE); |
+ if (restrict_addressing_modes_for_nacl) { |
+ return false; |
+ } |
+ // @LOCALMOD-END |
+ |
EVT VT; |
SDValue Ptr; |
bool isSEXTLoad = false; |
@@ -10343,7 +10565,14 @@ bool ARMTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op, |
SelectionDAG &DAG) const { |
if (Subtarget->isThumb1Only()) |
return false; |
- |
+ // @LOCALMOD-START |
+ // Avoid two reg addressing mode for loads and stores |
+ const bool restrict_addressing_modes_for_nacl = Subtarget->isTargetNaCl() && |
+ (N->getOpcode() == ISD::LOAD || N->getOpcode() == ISD::STORE); |
+ if (restrict_addressing_modes_for_nacl) { |
+ return false; |
+ } |
+ // @LOCALMOD-END |
EVT VT; |
SDValue Ptr; |
bool isSEXTLoad = false; |