diff options
| author | JF Bastien <jfb@google.com> | 2015-08-19 16:17:08 +0000 |
|---|---|---|
| committer | JF Bastien <jfb@google.com> | 2015-08-19 16:17:08 +0000 |
| commit | 5ab87edbb42bd3d8c0c38056db11d700b0188f31 (patch) | |
| tree | 25367e51ae2ae67cb23ad2d6e504ad456a810d92 | |
| parent | b0da42fb55ed574c5e3ca8351a3b5b48e088ccba (diff) | |
| download | bcm5719-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.cpp | 21 | ||||
| -rw-r--r-- | llvm/test/CodeGen/X86/x32-indirectbr.ll | 26 |
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]] + |

