diff --git a/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/lib/Target/XCore/XCoreISelDAGToDAG.cpp index 4dac1cee982..8d746ae6c37 100644 --- a/lib/Target/XCore/XCoreISelDAGToDAG.cpp +++ b/lib/Target/XCore/XCoreISelDAGToDAG.cpp @@ -120,7 +120,7 @@ bool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Addr, SDValue &Base, ConstantSDNode *CN = 0; if ((Addr.getOperand(0).getOpcode() == XCoreISD::DPRelativeWrapper) && (CN = dyn_cast(Addr.getOperand(1))) - && (CN->getSExtValue() % 4 == 0)) { + && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { // Constant word offset from a object in the data region Base = Addr.getOperand(0).getOperand(0); Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32); @@ -141,7 +141,7 @@ bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base, ConstantSDNode *CN = 0; if ((Addr.getOperand(0).getOpcode() == XCoreISD::CPRelativeWrapper) && (CN = dyn_cast(Addr.getOperand(1))) - && (CN->getSExtValue() % 4 == 0)) { + && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { // Constant word offset from a object in the data region Base = Addr.getOperand(0).getOperand(0); Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32); diff --git a/test/CodeGen/XCore/global_negative_offset.ll b/test/CodeGen/XCore/global_negative_offset.ll new file mode 100644 index 00000000000..0328fb0460f --- /dev/null +++ b/test/CodeGen/XCore/global_negative_offset.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -march=xcore | FileCheck %s + +; Don't fold negative offsets into cp / dp accesses to avoid a relocation +; error if the address + addend is less than the start of the cp / dp. + +@a = external constant [0 x i32], section ".cp.rodata" +@b = external global [0 x i32] + +define i32 *@f() nounwind { +entry: +; CHECK: f: +; CHECK: ldaw r11, cp[a] +; CHECK: sub r0, r11, 4 + %0 = getelementptr [0 x i32]* @a, i32 0, i32 -1 + ret i32* %0 +} + +define i32 *@g() nounwind { +entry: +; CHECK: g: +; CHECK: ldaw [[REG:r[0-9]+]], dp[b] +; CHECK: sub r0, [[REG]], 4 + %0 = getelementptr [0 x i32]* @b, i32 0, i32 -1 + ret i32* %0 +}