llvm-alpha.cpp   [plain text]


/* LLVM LOCAL begin (ENTIRE FILE!)  */
/* High-level LLVM backend interface 
Copyright (C) 2005 Free Software Foundation, Inc.
Contributed by Evan Cheng (evan.cheng@apple.com)

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

//===----------------------------------------------------------------------===//
// This is a C++ source file that implements specific llvm alpha ABI.
//===----------------------------------------------------------------------===//

#include "llvm-abi.h"
#include "llvm-internal.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"

extern "C" {
#include "toplev.h"
}

static LLVMContext &Context = getGlobalContext();

enum alpha_builtin
{
  ALPHA_BUILTIN_CMPBGE,
  ALPHA_BUILTIN_EXTBL,
  ALPHA_BUILTIN_EXTWL,
  ALPHA_BUILTIN_EXTLL,
  ALPHA_BUILTIN_EXTQL,
  ALPHA_BUILTIN_EXTWH,
  ALPHA_BUILTIN_EXTLH,
  ALPHA_BUILTIN_EXTQH,
  ALPHA_BUILTIN_INSBL,
  ALPHA_BUILTIN_INSWL,
  ALPHA_BUILTIN_INSLL,
  ALPHA_BUILTIN_INSQL,
  ALPHA_BUILTIN_INSWH,
  ALPHA_BUILTIN_INSLH,
  ALPHA_BUILTIN_INSQH,
  ALPHA_BUILTIN_MSKBL,
  ALPHA_BUILTIN_MSKWL,
  ALPHA_BUILTIN_MSKLL,
  ALPHA_BUILTIN_MSKQL,
  ALPHA_BUILTIN_MSKWH,
  ALPHA_BUILTIN_MSKLH,
  ALPHA_BUILTIN_MSKQH,
  ALPHA_BUILTIN_UMULH,
  ALPHA_BUILTIN_ZAP,
  ALPHA_BUILTIN_ZAPNOT,
  ALPHA_BUILTIN_AMASK,
  ALPHA_BUILTIN_IMPLVER,
  ALPHA_BUILTIN_RPCC,
  ALPHA_BUILTIN_THREAD_POINTER,
  ALPHA_BUILTIN_SET_THREAD_POINTER,

  /* TARGET_MAX */
  ALPHA_BUILTIN_MINUB8,
  ALPHA_BUILTIN_MINSB8,
  ALPHA_BUILTIN_MINUW4,
  ALPHA_BUILTIN_MINSW4,
  ALPHA_BUILTIN_MAXUB8,
  ALPHA_BUILTIN_MAXSB8,
  ALPHA_BUILTIN_MAXUW4,
  ALPHA_BUILTIN_MAXSW4,
  ALPHA_BUILTIN_PERR,
  ALPHA_BUILTIN_PKLB,
  ALPHA_BUILTIN_PKWB,
  ALPHA_BUILTIN_UNPKBL,
  ALPHA_BUILTIN_UNPKBW,

  /* TARGET_CIX */
  ALPHA_BUILTIN_CTTZ,
  ALPHA_BUILTIN_CTLZ,
  ALPHA_BUILTIN_CTPOP,

  ALPHA_BUILTIN_max
};

/* TargetIntrinsicLower - For builtins that we want to expand to normal LLVM
 * code, emit the code now.  If we can handle the code, this macro should emit
 * the code, return true.
 */
bool TreeToLLVM::TargetIntrinsicLower(tree exp,
                                      unsigned FnCode,
                                      const MemRef *DestLoc,
                                      Value *&Result,
                                      const Type *ResultType,
                                      std::vector<Value*> &Ops) {
  switch (FnCode) {
  case ALPHA_BUILTIN_UMULH: {
    Value *Arg0 = Ops[0];
    Value *Arg1 = Ops[1];
    Arg0 = Builder.CreateZExt(Arg0, IntegerType::get(Context, 128));
    Arg1 = Builder.CreateZExt(Arg1, IntegerType::get(Context, 128));
    Result = Builder.CreateMul(Arg0, Arg1);
    Result = Builder.CreateLShr(Result, ConstantInt::get(
                                               Type::getInt64Ty(Context), 64));
    Result = Builder.CreateTrunc(Result, Type::getInt64Ty(Context));
    return true;
  }
  case ALPHA_BUILTIN_CMPBGE: {
    Value *Arg0 = Ops[0];
    Value *Arg1 = Ops[1];
    Value* cmps[8];
    for (unsigned x = 0; x < 8; ++x) {
      Value* LHS = Builder.CreateLShr(Arg0, ConstantInt::get(
                                              Type::getInt64Ty(Context), x*8));
      LHS = Builder.CreateTrunc(LHS, Type::getInt8Ty(Context));
      Value* RHS = Builder.CreateLShr(Arg1, ConstantInt::get(
                                              Type::getInt64Ty(Context), x*8));
      RHS = Builder.CreateTrunc(RHS, Type::getInt8Ty(Context));
      Value* cmps = Builder.CreateICmpUGE(LHS, RHS);
      cmps = Builder.CreateIsNotNull(cmps);
      cmps = Builder.CreateZExt(cmps, Type::getInt64Ty(Context));
      cmps = Builder.CreateShl(cmps, ConstantInt::get(
                                                Type::getInt64Ty(Context), x));
      if (x == 0)
	Result = cmps;
      else
	Result = Builder.CreateOr(Result,cmps);
    }
    return true;
  }
  case ALPHA_BUILTIN_EXTBL:
  case ALPHA_BUILTIN_EXTWL:
  case ALPHA_BUILTIN_EXTLL:
  case ALPHA_BUILTIN_EXTQL: {
    unsigned long long mask = 0;
    switch (FnCode) {
    case ALPHA_BUILTIN_EXTBL: mask = 0x00000000000000FFULL; break;
    case ALPHA_BUILTIN_EXTWL: mask = 0x000000000000FFFFULL; break;
    case ALPHA_BUILTIN_EXTLL: mask = 0x00000000FFFFFFFFULL; break;
    case ALPHA_BUILTIN_EXTQL: mask = 0xFFFFFFFFFFFFFFFFULL; break;
    };
    Value *Arg0 = Ops[0];
    Value *Arg1 = Builder.CreateAnd(Ops[1], ConstantInt::get(
                                                Type::getInt64Ty(Context), 7));
    Arg0 = Builder.CreateLShr(Arg0, Arg1);
    Result = Builder.CreateAnd(Arg0, ConstantInt::get(
                                             Type::getInt64Ty(Context), mask));
    return true;
  }
  case ALPHA_BUILTIN_EXTWH:
  case ALPHA_BUILTIN_EXTLH:
  case ALPHA_BUILTIN_EXTQH: {
    unsigned long long mask = 0;
    switch (FnCode) {
    case ALPHA_BUILTIN_EXTWH: mask = 0x000000000000FFFFULL; break;
    case ALPHA_BUILTIN_EXTLH: mask = 0x00000000FFFFFFFFULL; break;
    case ALPHA_BUILTIN_EXTQH: mask = 0xFFFFFFFFFFFFFFFFULL; break;
    };
    Value *Arg0 = Ops[0];
    Value *Arg1 = Builder.CreateAnd(Ops[1], ConstantInt::get(
                                                Type::getInt64Ty(Context), 7));
    Arg1 = Builder.CreateSub(ConstantInt::get(
                                         Type::getInt64Ty(Context), 64), Arg1);
    Arg0 = Builder.CreateShl(Arg0, Arg1);
    Result = Builder.CreateAnd(Arg0, ConstantInt::get(
                                             Type::getInt64Ty(Context), mask));
    return true;
  }

  default: break;
  }

  return false;
}

/* LLVM LOCAL end (ENTIRE FILE!)  */