aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Sands <baldrick@free.fr>2007-07-27 20:02:49 +0000
committerDuncan Sands <baldrick@free.fr>2007-07-27 20:02:49 +0000
commitb116fac90f9b54142ac511a30b4d45b54d3508ba (patch)
tree6b21b6fc1649448004743c4bbab63c7360ce61ee
parent50f19f5860b4019f261963064df22679476e4d9b (diff)
Trampoline codegen support for X86-32.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40566 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/X86/X86CallingConv.td17
-rw-r--r--lib/Target/X86/X86CodeEmitter.cpp9
-rw-r--r--lib/Target/X86/X86CodeEmitter.h25
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp90
-rw-r--r--lib/Target/X86/X86ISelLowering.h1
5 files changed, 130 insertions, 12 deletions
diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td
index 39811bd740..b188050130 100644
--- a/lib/Target/X86/X86CallingConv.td
+++ b/lib/Target/X86/X86CallingConv.td
@@ -108,6 +108,9 @@ def CC_X86_64_C : CallingConv<[
CCIfType<[v8i8, v4i16, v2i32, v1i64],
CCAssignToReg<[RDI, RSI, RDX, RCX, R8 , R9 ]>>,
+ // The 'nest' parameter, if any, is passed in R10.
+ CCIfNest<CCAssignToReg<[R10]>>,
+
// Integer/FP values get stored in stack slots that are 8 bytes in size and
// 8-byte aligned if there are no more registers to hold them.
CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>,
@@ -150,11 +153,14 @@ def CC_X86_32_Common : CallingConv<[
def CC_X86_32_C : CallingConv<[
// Promote i8/i16 arguments to i32.
CCIfType<[i8, i16], CCPromoteToType<i32>>,
-
+
+ // The 'nest' parameter, if any, is passed in ECX.
+ CCIfNest<CCAssignToReg<[ECX]>>,
+
// The first 3 integer arguments, if marked 'inreg' and if the call is not
// a vararg call, are passed in integer registers.
CCIfNotVarArg<CCIfInReg<CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX]>>>>,
-
+
// Otherwise, same as everything else.
CCDelegateTo<CC_X86_32_Common>
]>;
@@ -163,10 +169,13 @@ def CC_X86_32_C : CallingConv<[
def CC_X86_32_FastCall : CallingConv<[
// Promote i8/i16 arguments to i32.
CCIfType<[i8, i16], CCPromoteToType<i32>>,
-
+
+ // The 'nest' parameter, if any, is passed in EAX.
+ CCIfNest<CCAssignToReg<[EAX]>>,
+
// The first 2 integer arguments are passed in ECX/EDX
CCIfType<[i32], CCAssignToReg<[ECX, EDX]>>,
-
+
// Otherwise, same as everything else.
CCDelegateTo<CC_X86_32_Common>
]>;
diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp
index 8b22634bd4..9d5180452b 100644
--- a/lib/Target/X86/X86CodeEmitter.cpp
+++ b/lib/Target/X86/X86CodeEmitter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "x86-emitter"
+#include "X86CodeEmitter.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
@@ -192,14 +193,6 @@ void Emitter::emitJumpTableAddress(unsigned JTI, unsigned Reloc,
MCE.emitWordLE(0); // The relocated value will be added to the displacement
}
-/// N86 namespace - Native X86 Register numbers... used by X86 backend.
-///
-namespace N86 {
- enum {
- EAX = 0, ECX = 1, EDX = 2, EBX = 3, ESP = 4, EBP = 5, ESI = 6, EDI = 7
- };
-}
-
// getX86RegNum - This function maps LLVM register identifiers to their X86
// specific numbering, which is used in various places encoding instructions.
//
diff --git a/lib/Target/X86/X86CodeEmitter.h b/lib/Target/X86/X86CodeEmitter.h
new file mode 100644
index 0000000000..f3e9dc0b47
--- /dev/null
+++ b/lib/Target/X86/X86CodeEmitter.h
@@ -0,0 +1,25 @@
+//===-- X86CodeEmitter.h - X86 DAG Lowering Interface -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Duncan Sands and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utilities for X86 code emission.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86CODEEMITTER_H
+#define X86CODEEMITTER_H
+
+/// N86 namespace - Native X86 Register numbers... used by X86 backend.
+///
+namespace N86 {
+ enum {
+ EAX = 0, ECX = 1, EDX = 2, EBX = 3, ESP = 4, EBP = 5, ESI = 6, EDI = 7
+ };
+}
+
+#endif // X86CODEEMITTER_H
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 94505c45c0..9ce1fa993d 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "X86.h"
+#include "X86CodeEmitter.h"
#include "X86InstrBuilder.h"
#include "X86ISelLowering.h"
#include "X86MachineFunctionInfo.h"
@@ -34,6 +35,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ParameterAttributes.h"
using namespace llvm;
X86TargetLowering::X86TargetLowering(TargetMachine &TM)
@@ -244,6 +246,10 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
setExceptionSelectorRegister(X86::EDX);
}
+ setOperationAction(ISD::ADJUST_TRAMP, MVT::i32, Expand);
+ setOperationAction(ISD::ADJUST_TRAMP, MVT::i64, Expand);
+ setOperationAction(ISD::TRAMPOLINE, MVT::Other, Custom);
+
// VASTART needs to be custom lowered to use the VarArgsFrameIndex
setOperationAction(ISD::VASTART , MVT::Other, Custom);
setOperationAction(ISD::VAARG , MVT::Other, Expand);
@@ -4265,6 +4271,89 @@ SDOperand X86TargetLowering::LowerEH_RETURN(SDOperand Op, SelectionDAG &DAG)
Chain, DAG.getRegister(X86::ECX, getPointerTy()));
}
+SDOperand X86TargetLowering::LowerTRAMPOLINE(SDOperand Op,
+ SelectionDAG &DAG) {
+ SDOperand Root = Op.getOperand(0);
+ SDOperand Trmp = Op.getOperand(1); // trampoline
+ SDOperand FPtr = Op.getOperand(2); // nested function
+ SDOperand Nest = Op.getOperand(3); // 'nest' parameter value
+
+ SrcValueSDNode *TrmpSV = cast<SrcValueSDNode>(Op.getOperand(4));
+
+ if (Subtarget->is64Bit()) {
+ return SDOperand(); // not yet supported
+ } else {
+ Function *Func = (Function *)
+ cast<Function>(cast<SrcValueSDNode>(Op.getOperand(5))->getValue());
+ unsigned CC = Func->getCallingConv();
+ unsigned char NestReg;
+
+ switch (CC) {
+ default:
+ assert(0 && "Unsupported calling convention");
+ case CallingConv::C:
+ case CallingConv::Fast:
+ case CallingConv::X86_StdCall: {
+ // Pass 'nest' parameter in ECX.
+ // Must be kept in sync with X86CallingConv.td
+ NestReg = N86::ECX;
+
+ // Check that ECX wasn't needed by an 'inreg' parameter.
+ const FunctionType *FTy = Func->getFunctionType();
+ const ParamAttrsList *Attrs = FTy->getParamAttrs();
+
+ if (Attrs && !Func->isVarArg()) {
+ unsigned InRegCount = 0;
+ unsigned Idx = 1;
+
+ for (FunctionType::param_iterator I = FTy->param_begin(),
+ E = FTy->param_end(); I != E; ++I, ++Idx)
+ if (Attrs->paramHasAttr(Idx, ParamAttr::InReg))
+ // FIXME: should only count parameters that are lowered to integers.
+ InRegCount += (getTargetData()->getTypeSizeInBits(*I) + 31) / 32;
+
+ if (InRegCount > 2) {
+ cerr << "Nest register in use - reduce number of inreg parameters!\n";
+ abort();
+ }
+ }
+ break;
+ }
+ case CallingConv::X86_FastCall:
+ // Pass 'nest' parameter in EAX.
+ // Must be kept in sync with X86CallingConv.td
+ NestReg = N86::EAX;
+ break;
+ }
+
+ SDOperand OutChains[4];
+ SDOperand Addr, Disp;
+
+ Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(10, MVT::i32));
+ Disp = DAG.getNode(ISD::SUB, MVT::i32, FPtr, Addr);
+
+ const unsigned char MOV32ri = 0xB8;
+ const unsigned char JMP = 0xE9;
+
+ OutChains[0] = DAG.getStore(Root, DAG.getConstant(MOV32ri|NestReg, MVT::i8),
+ Trmp, TrmpSV->getValue(), TrmpSV->getOffset());
+
+ Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(1, MVT::i32));
+ OutChains[1] = DAG.getStore(Root, Nest, Addr, TrmpSV->getValue(),
+ TrmpSV->getOffset() + 1, false, 1);
+
+ Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(5, MVT::i32));
+ OutChains[2] = DAG.getStore(Root, DAG.getConstant(JMP, MVT::i8), Addr,
+ TrmpSV->getValue() + 5, TrmpSV->getOffset());
+
+ Addr = DAG.getNode(ISD::ADD, MVT::i32, Trmp, DAG.getConstant(6, MVT::i32));
+ OutChains[3] = DAG.getStore(Root, Disp, Addr, TrmpSV->getValue(),
+ TrmpSV->getOffset() + 6, false, 1);
+
+ return DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains, 4);
+ }
+}
+
/// LowerOperation - Provide custom lowering hooks for some operations.
///
SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
@@ -4306,6 +4395,7 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
+ case ISD::TRAMPOLINE: return LowerTRAMPOLINE(Op, DAG);
}
return SDOperand();
}
diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h
index 521916e035..ef48095547 100644
--- a/lib/Target/X86/X86ISelLowering.h
+++ b/lib/Target/X86/X86ISelLowering.h
@@ -423,6 +423,7 @@ namespace llvm {
SDOperand LowerFRAMEADDR(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFRAME_TO_ARGS_OFFSET(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerEH_RETURN(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerTRAMPOLINE(SDOperand Op, SelectionDAG &DAG);
};
}