summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJF Bastien <jfb@google.com>2015-08-19 16:17:08 +0000
committerJF Bastien <jfb@google.com>2015-08-19 16:17:08 +0000
commit5ab87edbb42bd3d8c0c38056db11d700b0188f31 (patch)
tree25367e51ae2ae67cb23ad2d6e504ad456a810d92
parentb0da42fb55ed574c5e3ca8351a3b5b48e088ccba (diff)
downloadbcm5719-llvm-5ab87edbb42bd3d8c0c38056db11d700b0188f31.tar.gz
bcm5719-llvm-5ab87edbb42bd3d8c0c38056db11d700b0188f31.zip
x32. Fixes jmp %reg in x32
x32 has 32-bit pointers; x86-64 can't jmp %r32. This patch addresses this issue by explicitly zero-extending brind's target to 64-bits. Author: jpp Reviewers: jfb, dschuff, pavel.v.chupin Subscribers: llvm-commits Differential revision: http://reviews.llvm.org/D12112 llvm-svn: 245452
-rw-r--r--llvm/lib/Target/X86/X86ISelDAGToDAG.cpp21
-rw-r--r--llvm/test/CodeGen/X86/x32-indirectbr.ll26
2 files changed, 47 insertions, 0 deletions
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index d37db7f788b..df8de82c14b 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -2224,6 +2224,27 @@ SDNode *X86DAGToDAGISel::Select(SDNode *Node) {
switch (Opcode) {
default: break;
+ case ISD::BRIND: {
+ if (Subtarget->isTargetNaCl())
+ // NaCl has its own pass where jmp %r32 are converted to jmp %r64. We
+ // leave the instruction alone.
+ break;
+ if (Subtarget->isTarget64BitILP32()) {
+ // Converts a 32-bit register to a 64-bit, zero-extended version of
+ // it. This is needed because x86-64 can do many things, but jmp %r32
+ // ain't one of them.
+ const SDValue &Target = Node->getOperand(1);
+ assert(Target.getSimpleValueType() == llvm::MVT::i32);
+ SDValue ZextTarget = CurDAG->getZExtOrTrunc(Target, dl, EVT(MVT::i64));
+ SDValue Brind = CurDAG->getNode(ISD::BRIND, dl, MVT::Other,
+ Node->getOperand(0), ZextTarget);
+ ReplaceUses(SDValue(Node, 0), Brind);
+ SelectCode(ZextTarget.getNode());
+ SelectCode(Brind.getNode());
+ return nullptr;
+ }
+ break;
+ }
case ISD::INTRINSIC_W_CHAIN: {
unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
switch (IntNo) {
diff --git a/llvm/test/CodeGen/X86/x32-indirectbr.ll b/llvm/test/CodeGen/X86/x32-indirectbr.ll
new file mode 100644
index 00000000000..7c83827990c
--- /dev/null
+++ b/llvm/test/CodeGen/X86/x32-indirectbr.ll
@@ -0,0 +1,26 @@
+; RUN: llc < %s -mtriple=x86_64-none-none-gnux32 -mcpu=generic | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-none-none-gnux32 -mcpu=generic -fast-isel | FileCheck %s
+; Bug 22859
+;
+; x32 pointers are 32-bits wide. x86-64 indirect branches use the full 64-bit
+; registers. Therefore, x32 CodeGen needs to zero extend indirectbr's target to
+; 64-bit.
+
+define i8 @test1() nounwind ssp {
+entry:
+ %0 = select i1 undef, ; <i8*> [#uses=1]
+ i8* blockaddress(@test1, %bb),
+ i8* blockaddress(@test1, %bb6)
+ indirectbr i8* %0, [label %bb, label %bb6]
+bb: ; preds = %entry
+ ret i8 1
+
+bb6: ; preds = %entry
+ ret i8 2
+}
+; CHECK-LABEL: @test1
+; We are looking for a movl ???, %r32 followed by a 64-bit jmp through the
+; same register.
+; CHECK: movl {{.*}}, %{{e|r}}[[REG:.[^d]*]]{{d?}}
+; CHECK-NEXT: jmpq *%r[[REG]]
+
OpenPOWER on IntegriCloud