blob: facf55b640cc1afe1ca9a9b88ab859b056606966 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Vyacheslav P. Shakin
*/
#include "Ia32CallingConvention.h"
#include "Ia32IRManager.h"
namespace Jitrino {
namespace Ia32 {
const CallingConvention * CallingConvention::str2cc(const char * cc_name) {
if( NULL == cc_name ) { // default
return &CallingConvention_STDCALL;
}
if( !strcmpi(cc_name, "stdcall") ) {
return &CallingConvention_STDCALL;
}
if( !strcmpi(cc_name, "drl") ) {
return &CallingConvention_Managed;
}
if( !strcmpi(cc_name, "cdecl") ) {
return &CallingConvention_CDECL;
}
assert( false );
return NULL;
}
//========================================================================================
STDCALLCallingConvention CallingConvention_STDCALL;
CDECLCallingConvention CallingConvention_CDECL;
ManagedCallingConvention CallingConvention_Managed;
MultiArrayCallingConvention CallingConvention_MultiArray;
//========================================================================================
// STDCALLCallingConvention
//========================================================================================
#ifdef _EM64T_
#ifdef _WIN64
const RegName fastCallGPRegs[4] = {RegName_RCX, RegName_RDX, RegName_R8, RegName_R9} ;
const RegName fastCallFPRegs[4] = {RegName_XMM0,RegName_XMM1,RegName_XMM2,RegName_XMM3};
#else
const RegName fastCallGPRegs[6] = {RegName_RDI, RegName_RSI, RegName_RDX, RegName_RCX, RegName_R8, RegName_R9} ;
const RegName fastCallFPRegs[8] = {RegName_XMM0,RegName_XMM1,RegName_XMM2,RegName_XMM3,RegName_XMM4,RegName_XMM5,RegName_XMM6,RegName_XMM7};
#endif
#endif
#ifdef _IA32_
//______________________________________________________________________________________
void STDCALLCallingConventionIA32::getOpndInfo(ArgKind kind, U_32 count, OpndInfo * infos) const
{
if (kind == ArgKind_InArg) {
for (U_32 i=0; i<count; i++){
Type::Tag typeTag=(Type::Tag)infos[i].typeTag;
OpndSize size=IRManager::getTypeSize(typeTag);
assert(size!=OpndSize_Null && size<=OpndSize_64);
infos[i].slotCount=1;
infos[i].slots[0]=RegName_Null;
infos[i].isReg=false;
if (size==OpndSize_64){
infos[i].slotCount=2;
infos[i].slots[1]=RegName_Null;
}
}
} else {
assert(kind == ArgKind_RetArg);
assert(count <= 1);
if (count == 1) {
Type::Tag typeTag=(Type::Tag)infos[0].typeTag;
infos[0].isReg=true;
switch (typeTag) {
case Type::Void:
infos[0].slotCount=0;
break;
case Type::Float:
case Type::Double:
case Type::Single:
infos[0].slotCount=1;
infos[0].slots[0]=RegName_FP0;
break;
default: {
OpndSize size=IRManager::getTypeSize(typeTag);
assert(size!=OpndSize_Null && size<=OpndSize_64);
infos[0].slotCount=1;
infos[0].slots[0]=RegName_EAX;
if (size == OpndSize_64) {
infos[0].slotCount=2;
infos[0].slots[1]=RegName_EDX;
}
}
};
}
}
}
#else
void STDCALLCallingConventionEM64T::getOpndInfo(ArgKind kind, U_32 count, OpndInfo * infos) const
{
if (kind == ArgKind_InArg) {
U_32 gpreg = 0;
#ifdef _WIN64
#define fpreg gpreg
#else
U_32 fpreg = 0;
#endif
for (U_32 i=0; i<count; i++){
Type::Tag typeTag=(Type::Tag)infos[i].typeTag;
if(((typeTag>Type::Float ||typeTag<Type::Single) && gpreg < lengthof(fastCallGPRegs))) {
infos[i].slotCount=1;
infos[i].slots[0]=fastCallGPRegs[gpreg];
infos[i].isReg=true;
gpreg++;
} else if(((typeTag<=Type::Float && typeTag>=Type::Single) && fpreg < lengthof(fastCallFPRegs))) {
infos[i].slotCount=1;
infos[i].slots[0]=fastCallFPRegs[fpreg];
infos[i].isReg=true;
fpreg++;
} else {
infos[i].slotCount=1;
infos[i].slots[0]=RegName_Null;
infos[i].isReg=false;
}
}
} else {
assert(kind == ArgKind_RetArg);
assert(count <= 1);
if (count == 1) {
Type::Tag typeTag=(Type::Tag)infos[0].typeTag;
infos[0].isReg=true;
switch (typeTag) {
case Type::Void:
infos[0].slotCount=0;
break;
case Type::Float:
case Type::Double:
case Type::Single:
infos[0].slotCount=1;
infos[0].slots[0]=RegName_XMM0;
break;
default: {
OpndSize size=IRManager::getTypeSize(typeTag);
infos[0].slotCount=1;
infos[0].slots[0]=RegName_RAX;
if (size == OpndSize_128) {
infos[0].slotCount=2;
infos[0].slots[1]=RegName_RDX;
}
}
};
}
}
}
#endif
#ifdef _IA32_
//______________________________________________________________________________________
Constraint STDCALLCallingConventionIA32::getCalleeSavedRegs(OpndKind regKind) const
{
switch (regKind){
case OpndKind_GPReg:
return (Constraint(RegName_EBX)|RegName_EBP|RegName_ESI|RegName_EDI);
default:
return Constraint();
}
}
#else
Constraint STDCALLCallingConventionEM64T::getCalleeSavedRegs(OpndKind regKind) const
{
switch (regKind){
case OpndKind_GPReg:
#ifdef _WIN64
return (Constraint(RegName_RBX)|RegName_RBP|RegName_R12|RegName_R13|RegName_R14|RegName_R15|RegName_RSI|RegName_RDI);
#else
return (Constraint(RegName_RBX)|RegName_RBP|RegName_R12|RegName_R13|RegName_R14|RegName_R15);
#endif
default:
return Constraint();
}
}
#endif
//______________________________________________________________________________________
#ifdef _IA32_
void ManagedCallingConventionIA32::getOpndInfo(ArgKind kind, U_32 count, OpndInfo * infos) const
{
if (kind == ArgKind_RetArg) {
assert(count <= 1);
if (count == 1) {
Type::Tag typeTag = (Type::Tag)infos[0].typeTag;
switch (typeTag) {
case Type::Float:
case Type::Double:
case Type::Single:
infos[0].isReg = true;
infos[0].slotCount = 1;
infos[0].slots[0] = RegName_XMM0;
return;
default:;
};
}
}
return STDCALLCallingConventionIA32::getOpndInfo(kind, count, infos);
}
#else
#endif
#ifdef _IA32_
#else
void MultiArrayCallingConventionEM64T::getOpndInfo(ArgKind kind, U_32 count, OpndInfo * infos) const
{
if (kind == ArgKind_InArg){
for (U_32 i = 0; i < count; i++) {
infos[i].slotCount = 1;
infos[i].slots[0] = RegName_Null;
infos[i].isReg = false;
}
} else {
CDECLCallingConventionEM64T::getOpndInfo(kind, count, infos);
}
}
#endif
}; // namespace Ia32
}