/*******************************************************\
* Copyright (C) 2006, ApS s.r.o Brno, AllRightsReserved *
\*******************************************************/

#include "llvm/CallingConv.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/LLVMContext.h"

#include "CodasipGenISelLowering.h"
#include "CodasipMachineFunction.h"
#include "CodasipTargetMachine.h"
#include "CodasipTargetObjectFile.h"

#include <map>
#include <cstdlib>
#include <cstdio>
#include <iostream>

using namespace llvm;

#include "CodasipGenCallingConv.inc"

// init legalities
CodasipGenTargetLowering::CodasipGenTargetLowering(CodasipTargetMachine &TM): TargetLowering(TM, new CodasipTargetObjectFile())
{
  addRegisterClass(MVT::i32, Codasip::gpregsRegisterClass);
  addRegisterClass(MVT::f32, Codasip::fpregsRegisterClass);

  setOperationAction(ISD::ADD,MVT::i1,Expand);
  setOperationAction(ISD::ADD,MVT::i8,Expand);
  setOperationAction(ISD::ADD,MVT::i16,Expand);
  setOperationAction(ISD::ADD,MVT::i32,Legal);
  setOperationAction(ISD::ADD,MVT::i64,Expand);

//  setOperationAction(ISD::ADD,MVT::i32,Legal);

  setOperationAction(ISD::SUB,MVT::i1,Expand);
  setOperationAction(ISD::SUB,MVT::i8,Expand);
  setOperationAction(ISD::SUB,MVT::i16,Expand);
  setOperationAction(ISD::SUB,MVT::i32,Legal);
  setOperationAction(ISD::SUB,MVT::i64,Expand);

  setOperationAction(ISD::MUL,MVT::i1,Expand);
  setOperationAction(ISD::MUL,MVT::i8,Expand);
  setOperationAction(ISD::MUL,MVT::i16,Expand);
  setOperationAction(ISD::MUL,MVT::i32,Legal);
  setOperationAction(ISD::MUL,MVT::i64,Expand);

  setOperationAction(ISD::SDIV,MVT::i1,Expand);
  setOperationAction(ISD::SDIV,MVT::i8,Expand);
  setOperationAction(ISD::SDIV,MVT::i16,Expand);
  setOperationAction(ISD::SDIV,MVT::i32,Expand);
  setOperationAction(ISD::SDIV,MVT::i64,Expand);

  setOperationAction(ISD::UDIV,MVT::i1,Expand);
  setOperationAction(ISD::UDIV,MVT::i8,Expand);
  setOperationAction(ISD::UDIV,MVT::i16,Expand);
  setOperationAction(ISD::UDIV,MVT::i32,Expand);
  setOperationAction(ISD::UDIV,MVT::i64,Expand);

  setOperationAction(ISD::SREM,MVT::i1,Expand);
  setOperationAction(ISD::SREM,MVT::i8,Expand);
  setOperationAction(ISD::SREM,MVT::i16,Expand);
  setOperationAction(ISD::SREM,MVT::i32,Expand);
  setOperationAction(ISD::SREM,MVT::i64,Expand);

  setOperationAction(ISD::UREM,MVT::i1,Expand);
  setOperationAction(ISD::UREM,MVT::i8,Expand);
  setOperationAction(ISD::UREM,MVT::i16,Expand);
  setOperationAction(ISD::UREM,MVT::i32,Expand);
  setOperationAction(ISD::UREM,MVT::i64,Expand);

  setOperationAction(ISD::SDIVREM,MVT::i1,Expand);
  setOperationAction(ISD::SDIVREM,MVT::i8,Expand);
  setOperationAction(ISD::SDIVREM,MVT::i16,Expand);
  setOperationAction(ISD::SDIVREM,MVT::i32,Expand);
  setOperationAction(ISD::SDIVREM,MVT::i64,Expand);

  setOperationAction(ISD::UDIVREM,MVT::i1,Expand);
  setOperationAction(ISD::UDIVREM,MVT::i8,Expand);
  setOperationAction(ISD::UDIVREM,MVT::i16,Expand);
  setOperationAction(ISD::UDIVREM,MVT::i32,Expand);
  setOperationAction(ISD::UDIVREM,MVT::i64,Expand);

  setOperationAction(ISD::SMUL_LOHI,MVT::i1,Expand);
  setOperationAction(ISD::SMUL_LOHI,MVT::i8,Expand);
  setOperationAction(ISD::SMUL_LOHI,MVT::i16,Expand);
  setOperationAction(ISD::SMUL_LOHI,MVT::i32,Expand);
  setOperationAction(ISD::SMUL_LOHI,MVT::i64,Expand);

  setOperationAction(ISD::UMUL_LOHI,MVT::i1,Expand);
  setOperationAction(ISD::UMUL_LOHI,MVT::i8,Expand);
  setOperationAction(ISD::UMUL_LOHI,MVT::i16,Expand);
  setOperationAction(ISD::UMUL_LOHI,MVT::i32,Expand);
  setOperationAction(ISD::UMUL_LOHI,MVT::i64,Expand);

  setOperationAction(ISD::MULHS,MVT::i1,Expand);
  setOperationAction(ISD::MULHS,MVT::i8,Expand);
  setOperationAction(ISD::MULHS,MVT::i16,Expand);
  setOperationAction(ISD::MULHS,MVT::i32,Expand);
  setOperationAction(ISD::MULHS,MVT::i64,Expand);

  setOperationAction(ISD::MULHU,MVT::i1,Expand);
  setOperationAction(ISD::MULHU,MVT::i8,Expand);
  setOperationAction(ISD::MULHU,MVT::i16,Expand);
  setOperationAction(ISD::MULHU,MVT::i32,Expand);
  setOperationAction(ISD::MULHU,MVT::i64,Expand);

  setOperationAction(ISD::SHL,MVT::i1,Expand);
  setOperationAction(ISD::SHL,MVT::i8,Expand);
  setOperationAction(ISD::SHL,MVT::i16,Expand);
  setOperationAction(ISD::SHL,MVT::i32,Legal);
  setOperationAction(ISD::SHL,MVT::i64,Expand);

  setOperationAction(ISD::SRL,MVT::i1,Expand);
  setOperationAction(ISD::SRL,MVT::i8,Expand);
  setOperationAction(ISD::SRL,MVT::i16,Expand);
  setOperationAction(ISD::SRL,MVT::i32,Legal);
  setOperationAction(ISD::SRL,MVT::i64,Expand);

  setOperationAction(ISD::SRA,MVT::i1,Expand);
  setOperationAction(ISD::SRA,MVT::i8,Expand);
  setOperationAction(ISD::SRA,MVT::i16,Expand);
  setOperationAction(ISD::SRA,MVT::i32,Legal);
  setOperationAction(ISD::SRA,MVT::i64,Expand);

  setOperationAction(ISD::ROTL,MVT::i1,Expand);
  setOperationAction(ISD::ROTL,MVT::i8,Expand);
  setOperationAction(ISD::ROTL,MVT::i16,Expand);
  setOperationAction(ISD::ROTL,MVT::i32,Expand);
  setOperationAction(ISD::ROTL,MVT::i64,Expand);

  setOperationAction(ISD::ROTR,MVT::i1,Expand);
  setOperationAction(ISD::ROTR,MVT::i8,Expand);
  setOperationAction(ISD::ROTR,MVT::i16,Expand);
  setOperationAction(ISD::ROTR,MVT::i32,Expand);
  setOperationAction(ISD::ROTR,MVT::i64,Expand);

  setOperationAction(ISD::AND,MVT::i1,Expand);
  setOperationAction(ISD::AND,MVT::i8,Expand);
  setOperationAction(ISD::AND,MVT::i16,Expand);
  setOperationAction(ISD::AND,MVT::i32,Legal);
  setOperationAction(ISD::AND,MVT::i64,Expand);

  setOperationAction(ISD::OR,MVT::i1,Expand);
  setOperationAction(ISD::OR,MVT::i8,Expand);
  setOperationAction(ISD::OR,MVT::i16,Expand);
  setOperationAction(ISD::OR,MVT::i32,Legal);
  setOperationAction(ISD::OR,MVT::i64,Expand);

  setOperationAction(ISD::XOR,MVT::i1,Expand);
  setOperationAction(ISD::XOR,MVT::i8,Expand);
  setOperationAction(ISD::XOR,MVT::i16,Expand);
  setOperationAction(ISD::XOR,MVT::i32,Legal);
  setOperationAction(ISD::XOR,MVT::i64,Expand);

  setOperationAction(ISD::ADDC,MVT::i1,Expand);
  setOperationAction(ISD::ADDC,MVT::i8,Expand);
  setOperationAction(ISD::ADDC,MVT::i16,Expand);
  setOperationAction(ISD::ADDC,MVT::i32,Expand);
  setOperationAction(ISD::ADDC,MVT::i64,Expand);

  setOperationAction(ISD::SUBC,MVT::i1,Expand);
  setOperationAction(ISD::SUBC,MVT::i8,Expand);
  setOperationAction(ISD::SUBC,MVT::i16,Expand);
  setOperationAction(ISD::SUBC,MVT::i32,Expand);
  setOperationAction(ISD::SUBC,MVT::i64,Expand);

  setOperationAction(ISD::ADDE,MVT::i1,Expand);
  setOperationAction(ISD::ADDE,MVT::i8,Expand);
  setOperationAction(ISD::ADDE,MVT::i16,Expand);
  setOperationAction(ISD::ADDE,MVT::i32,Expand);
  setOperationAction(ISD::ADDE,MVT::i64,Expand);

  setOperationAction(ISD::SUBE,MVT::i1,Expand);
  setOperationAction(ISD::SUBE,MVT::i8,Expand);
  setOperationAction(ISD::SUBE,MVT::i16,Expand);
  setOperationAction(ISD::SUBE,MVT::i32,Expand);
  setOperationAction(ISD::SUBE,MVT::i64,Expand);

  setOperationAction(ISD::CTLZ,MVT::i1,Expand);
  setOperationAction(ISD::CTLZ,MVT::i8,Expand);
  setOperationAction(ISD::CTLZ,MVT::i16,Expand);
  setOperationAction(ISD::CTLZ,MVT::i32,Expand);
  setOperationAction(ISD::CTLZ,MVT::i64,Expand);

  setOperationAction(ISD::CTPOP,MVT::i1,Expand);
  setOperationAction(ISD::CTPOP,MVT::i8,Expand);
  setOperationAction(ISD::CTPOP,MVT::i16,Expand);
  setOperationAction(ISD::CTPOP,MVT::i32,Expand);
  setOperationAction(ISD::CTPOP,MVT::i64,Expand);

  setOperationAction(ISD::CTTZ,MVT::i1,Expand);
  setOperationAction(ISD::CTTZ,MVT::i8,Expand);
  setOperationAction(ISD::CTTZ,MVT::i16,Expand);
  setOperationAction(ISD::CTTZ,MVT::i32,Expand);
  setOperationAction(ISD::CTTZ,MVT::i64,Expand);

  setOperationAction(ISD::SIGN_EXTEND,MVT::i1,Expand);
  setOperationAction(ISD::SIGN_EXTEND,MVT::i8,Expand);
  setOperationAction(ISD::SIGN_EXTEND,MVT::i16,Expand);
  setOperationAction(ISD::SIGN_EXTEND,MVT::i32,Expand);
  setOperationAction(ISD::SIGN_EXTEND,MVT::i64,Expand);

  setOperationAction(ISD::ZERO_EXTEND,MVT::i1,Expand);
  setOperationAction(ISD::ZERO_EXTEND,MVT::i8,Expand);
  setOperationAction(ISD::ZERO_EXTEND,MVT::i16,Expand);
  setOperationAction(ISD::ZERO_EXTEND,MVT::i32,Expand);
  setOperationAction(ISD::ZERO_EXTEND,MVT::i64,Expand);

  setOperationAction(ISD::TRUNCATE,MVT::i1,Expand);
  setOperationAction(ISD::TRUNCATE,MVT::i8,Expand);
  setOperationAction(ISD::TRUNCATE,MVT::i16,Expand);
  setOperationAction(ISD::TRUNCATE,MVT::i32,Expand);
  setOperationAction(ISD::TRUNCATE,MVT::i64,Expand);

  setOperationAction(ISD::BITCAST,MVT::i1,Expand);
  setOperationAction(ISD::BITCAST,MVT::i8,Expand);
  setOperationAction(ISD::BITCAST,MVT::i16,Expand);
  setOperationAction(ISD::BITCAST,MVT::i32,Expand);
  setOperationAction(ISD::BITCAST,MVT::i64,Expand);
  setOperationAction(ISD::BITCAST,MVT::f32,Expand);
  setOperationAction(ISD::BITCAST,MVT::f64,Expand);

  setOperationAction(ISD::FADD,MVT::f32,Legal);
  setOperationAction(ISD::FADD,MVT::f64,Expand);

  setOperationAction(ISD::FSUB,MVT::f32,Legal);
  setOperationAction(ISD::FSUB,MVT::f64,Expand);

  setOperationAction(ISD::FMUL,MVT::f32,Legal);
  setOperationAction(ISD::FMUL,MVT::f64,Expand);

  setOperationAction(ISD::FDIV,MVT::f32,Legal);
  setOperationAction(ISD::FDIV,MVT::f64,Expand);

  setOperationAction(ISD::FNEG,MVT::f32,Legal);
  setOperationAction(ISD::FNEG,MVT::f64,Expand);

  setOperationAction(ISD::SINT_TO_FP,MVT::f32,Expand);
  setOperationAction(ISD::SINT_TO_FP,MVT::f64,Expand);

  setOperationAction(ISD::UINT_TO_FP,MVT::f32,Expand);
  setOperationAction(ISD::UINT_TO_FP,MVT::f64,Expand);

  setOperationAction(ISD::FP_TO_SINT,MVT::f32,Expand);
  setOperationAction(ISD::FP_TO_SINT,MVT::f64,Expand);

  setOperationAction(ISD::FP_TO_UINT,MVT::f32,Expand);
  setOperationAction(ISD::FP_TO_UINT,MVT::f64,Expand);

  setOperationAction(ISD::FTRUNC,MVT::f32,Legal);
  setOperationAction(ISD::FTRUNC,MVT::f64,Expand);

  setOperationAction(ISD::FP_EXTEND,MVT::f32,Expand);
  setOperationAction(ISD::FP_EXTEND,MVT::f64,Expand);

  setOperationAction(ISD::CopyToReg,MVT::i1,Expand);
  setOperationAction(ISD::CopyToReg,MVT::i8,Expand);
  setOperationAction(ISD::CopyToReg,MVT::i16,Expand);
  setOperationAction(ISD::CopyToReg,MVT::i32,Legal);
  setOperationAction(ISD::CopyToReg,MVT::i64,Expand);
  setOperationAction(ISD::CopyToReg,MVT::f32,Legal);
  setOperationAction(ISD::CopyToReg,MVT::f64,Expand);

  setOperationAction(ISD::CopyFromReg,MVT::i1,Expand);
  setOperationAction(ISD::CopyFromReg,MVT::i8,Expand);
  setOperationAction(ISD::CopyFromReg,MVT::i16,Expand);
  setOperationAction(ISD::CopyFromReg,MVT::i32,Legal);
  setOperationAction(ISD::CopyFromReg,MVT::i64,Expand);
  setOperationAction(ISD::CopyFromReg,MVT::f32,Legal);
  setOperationAction(ISD::CopyFromReg,MVT::f64,Expand);

  setOperationAction(ISD::LOAD,MVT::i1,Expand);
  setOperationAction(ISD::LOAD,MVT::i8,Expand);
  setOperationAction(ISD::LOAD,MVT::i16,Expand);
  setOperationAction(ISD::LOAD,MVT::i32,Legal);
  setOperationAction(ISD::LOAD,MVT::i64,Expand);
  setOperationAction(ISD::LOAD,MVT::f32,Legal);
  setOperationAction(ISD::LOAD,MVT::f64,Expand);

  setOperationAction(ISD::STORE,MVT::i1,Expand);
  setOperationAction(ISD::STORE,MVT::i8,Expand);
  setOperationAction(ISD::STORE,MVT::i16,Expand);
  setOperationAction(ISD::STORE,MVT::i32,Legal);
  setOperationAction(ISD::STORE,MVT::i64,Expand);
  setOperationAction(ISD::STORE,MVT::f32,Legal);
  setOperationAction(ISD::STORE,MVT::f64,Expand);

  setOperationAction(ISD::BR,MVT::Other,Legal);


  setOperationAction(ISD::BRIND,MVT::i1,Expand);
  setOperationAction(ISD::BRIND,MVT::i8,Expand);
  setOperationAction(ISD::BRIND,MVT::i16,Expand);
  setOperationAction(ISD::BRIND,MVT::i32,Legal);
  setOperationAction(ISD::BRIND,MVT::i64,Expand);
  setOperationAction(ISD::BRIND,MVT::f32,Legal);
  setOperationAction(ISD::BRIND,MVT::f64,Expand);



  setTruncStoreAction(MVT::i8,MVT::i1,Expand);
  setTruncStoreAction(MVT::i16,MVT::i1,Expand);
  setTruncStoreAction(MVT::i16,MVT::i8,Expand);
  setTruncStoreAction(MVT::i32,MVT::i1,Expand);
  setTruncStoreAction(MVT::i32,MVT::i8,Expand);
  setTruncStoreAction(MVT::i32,MVT::i16,Expand);
  setTruncStoreAction(MVT::i64,MVT::i1,Expand);
  setTruncStoreAction(MVT::i64,MVT::i8,Expand);
  setTruncStoreAction(MVT::i64,MVT::i16,Expand);
  setTruncStoreAction(MVT::i64,MVT::i32,Expand);

  setLoadExtAction(ISD::SEXTLOAD,MVT::i1,Expand);
  setLoadExtAction(ISD::SEXTLOAD,MVT::i8,Expand);
  setLoadExtAction(ISD::SEXTLOAD,MVT::i16,Expand);
  setLoadExtAction(ISD::SEXTLOAD,MVT::i32,Expand);
  setLoadExtAction(ISD::ZEXTLOAD,MVT::i1,Expand);
  setLoadExtAction(ISD::ZEXTLOAD,MVT::i8,Expand);
  setLoadExtAction(ISD::ZEXTLOAD,MVT::i16,Expand);
  setLoadExtAction(ISD::ZEXTLOAD,MVT::i32,Expand);



  setStackPointerRegisterToSaveRestore(Codasip::gpregs_0);

  for (int i=MVT::FIRST_INTEGER_VALUETYPE; i<MVT::LAST_INTEGER_VALUETYPE; ++i)
  {
    // all global symbols need to be wrapped
    setOperationAction(ISD::GlobalAddress, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::GlobalTLSAddress, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::ExternalSymbol, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::JumpTable, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::ConstantPool, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::BlockAddress, MVT::SimpleValueType(i), Custom);
    // br_jt always expand
    setOperationAction(ISD::BR_JT, MVT::SimpleValueType(i), Expand);
    // we don't use br_cc and sel_cc (expansion chain is: br_cc.other -> brcond -> br_cc.int)
    setOperationAction(ISD::BR_CC, MVT::SimpleValueType(i), Custom);
    setOperationAction(ISD::SELECT_CC, MVT::SimpleValueType(i), Custom);
    // "op_parts" operations are implicitly expanded
    setOperationAction(ISD::SHL_PARTS, MVT::SimpleValueType(i), Expand);
    setOperationAction(ISD::SRA_PARTS, MVT::SimpleValueType(i), Expand);
    setOperationAction(ISD::SRL_PARTS, MVT::SimpleValueType(i), Expand);
    // dynamic stack allocation (-> stacksave&stackrestore)
    setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::SimpleValueType(i), Expand);
    setOperationAction(ISD::STACKSAVE, MVT::SimpleValueType(i), Expand);
    setOperationAction(ISD::STACKRESTORE, MVT::SimpleValueType(i), Expand);
    // until the extractor recognises rotl, don't bother emulating it
    setOperationAction(ISD::ROTL, MVT::SimpleValueType(i), Expand);
    setOperationAction(ISD::ROTR, MVT::SimpleValueType(i), Expand);
  }

  setOperationAction(ISD::BR_JT,MVT::Other,Expand);
  setOperationAction(ISD::BR_CC,MVT::Other,Expand);
  setOperationAction(ISD::SELECT_CC,MVT::Other,Expand);
  
  setOperationAction(ISD::VASTART,MVT::Other,Custom);
  setOperationAction(ISD::VAEND,MVT::Other,Custom);
  setOperationAction(ISD::VAARG,MVT::Other,Custom);
  setOperationAction(ISD::VACOPY,MVT::Other,Custom);
  
  setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); //(required)
  setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);

  computeRegisterProperties();
}

unsigned CodasipGenTargetLowering::getFunctionAlignment(const Function *fc) const
{
  return 2;
}


SDValue CodasipGenTargetLowering::
LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, bool &isTailCall,
          const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals,
          const SmallVectorImpl<ISD::InputArg> &Ins, DebugLoc dl, SelectionDAG &DAG,
          SmallVectorImpl<SDValue> &InVals) const
{
  // note: try to implement this someday
  isTailCall = false;
  // get various metainfo
  LLVMContext &cont = *DAG.getContext();
  MachineFunction &MF = DAG.getMachineFunction();
  SmallVector<CCValAssign,16> ArgLocs;
  CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, cont);
  CCInfo.AnalyzeCallOperands(Outs, CC_Codasip);
  SDValue InFlag;
  MachineFrameInfo *MFI = MF.getFrameInfo();
  const TargetData *td = getTargetData();
  // how many bytes are to be pushed on the stack?
  unsigned NumBytes = CCInfo.getNextStackOffset();
  SDValue stackOff = DAG.getIntPtrConstant(NumBytes,true);
  Chain = DAG.getCALLSEQ_START(Chain,stackOff);
  // operands of the call (the first two slots empty for now)
  SmallVector<SDValue,8> Ops;
  Ops.push_back(SDValue()); Ops.push_back(SDValue());
  // note: it's expected that register passes go first, then stack passes
  // deal with stack passes first (they are at the back)
  for (int i=ArgLocs.size()-1; i>=0; --i)
  {
    SDValue Arg = OutVals[i];
    CCValAssign &VA = ArgLocs[i];
    // is it a stack pass?
    if (VA.isMemLoc()) {
      // memory requirements (alignment considered)
      EVT evt = Arg.getValueType();
      assert(evt.getSimpleVT()==VA.getValVT());
      Type *ty = evt.getTypeForEVT(cont);
      unsigned ArgSize = td->getTypeAllocSize(ty);
      // get index  -note: negative
      assert(evt.isByteSized() and "Yeah, obviously it isn't.");
      int FI = MFI->CreateFixedObject(ArgSize, -VA.getLocMemOffset(), true);
      SDValue PtrOff = DAG.getFrameIndex(FI,getPointerTy());
      // store
      Chain = DAG.getStore(Chain,dl,Arg,PtrOff,MachinePointerInfo(),false,false,0);
    }
    // reg pass otherwise
    else {
      assert(VA.isRegLoc());
      // stop this iteration
      break;
    }
  }
  // now deal with registers (in natural order)
  for (unsigned i=0; i<ArgLocs.size(); ++i)
  {
    SDValue Arg = OutVals[i];
    CCValAssign &VA = ArgLocs[i];
    // unprocessed yet?
    if (VA.isRegLoc()) {
      // from now on, everything has to flagged
      Chain = DAG.getCopyToReg(Chain,dl, VA.getLocReg(),Arg,InFlag);
      InFlag = Chain.getValue(1);
      // add to ops (to keep alive)
      Ops.push_back(DAG.getRegister(VA.getLocReg(),Arg.getValueType()));
    }
    else {
      assert(VA.isMemLoc());
      // already dealth with
      break;
    }
  }
  // insert the call itself
  SDVTList NodeTys = DAG.getVTList(MVT::Other,MVT::Glue);
  Ops[0] = Chain;
  Ops[1] = Callee;
  if (InFlag.getNode()) Ops.push_back(InFlag);
  Chain = DAG.getNode(CodasipISD::Call,dl,NodeTys, &Ops[0],Ops.size());
  InFlag = Chain.getValue(1); // (see definition of NodeTys)
  // Create the CALLSEQ_END node.                                         callee pushes nothing
  Chain = DAG.getCALLSEQ_END(Chain,stackOff, DAG.getIntPtrConstant(0,true), InFlag);
  InFlag = Chain.getValue(1);
  // ============= lower call result
  SmallVector<CCValAssign,16> RVLocs;
  CCState CCInfo2(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, cont);
  CCInfo2.AnalyzeCallResult(Ins,RetCC_Codasip);
  // If this is the first return lowered for this function,
  // add the regs to the livein set for the function.
  if (DAG.getMachineFunction().getRegInfo().livein_empty())
  {
    for (unsigned i=0; i<RVLocs.size(); ++i) {
      assert(RVLocs[i].isRegLoc());
      DAG.getMachineFunction().getRegInfo().addLiveIn(RVLocs[i].getLocReg());
    }
  }
  // copy the result value from register to the target
  for (unsigned i=0; i<RVLocs.size(); ++i)
  {
    assert(RVLocs[i].isRegLoc());
    Chain = DAG.getCopyFromReg(Chain,dl, RVLocs[i].getLocReg(), RVLocs[i].getValVT(), InFlag).getValue(1);
    InFlag = Chain.getValue(2);
    InVals.push_back(Chain.getValue(0));
  }
  return Chain;
}


SDValue CodasipGenTargetLowering::
LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins,
                     DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const
{
  MachineFunction &MF = DAG.getMachineFunction();
  const Function *func = MF.getFunction();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
  CodasipFunctionInfo *finfo = MF.getInfo<CodasipFunctionInfo>();
  const TargetData *td = getTargetData();
  LLVMContext &cont = *DAG.getContext();
  // Assign locations to all of the incoming arguments.
  SmallVector<CCValAssign,16> ArgLocs;
  CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, cont);
  CCInfo.AnalyzeFormalArguments(Ins, CC_Codasip);
  // last registers used for fixed regs
  std::map<unsigned,unsigned> lastRegs;
  lastRegs[Codasip::gpregsRegClassID] = 0;
  // take all params
  for (unsigned i=0, e=ArgLocs.size(); i!=e; ++i)
  {
    CCValAssign &VA = ArgLocs[i];
    EVT vt = VA.getValVT();
    // reg params
    if (VA.isRegLoc())
    {
      // should be always full
      assert(VA.getLocInfo()==CCValAssign::Full && "my assumption was faulty");
      // add the reg as a live in (direct use wouldn't always work)
      unsigned FReg = VA.getLocReg();
      const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(FReg,vt);
      unsigned VReg = MRI.createVirtualRegister(RC);
      MF.getRegInfo().addLiveIn(FReg,VReg);
      InVals.push_back(DAG.getCopyFromReg(Chain,dl,VReg,vt));
      // remember last (e.g. for vararg purposes)
      assert(lastRegs.count(RC->getID()));
      lastRegs[RC->getID()] = FReg;
    }
    // mem params
    else if (VA.isMemLoc())
    {
      // memory requirements (alignment considered)
      unsigned ArgSize = td->getTypeAllocSize(vt.getTypeForEVT(cont));
      // note1: (if the stack grows down,) the offset is positive and the argument alignment has to be added
      // note2: an offset is added depending on how many "our" save slots do we use (RA,BP)
      int FI = MFI->CreateFixedObject(ArgSize, VA.getLocMemOffset()+4+ArgSize, true);
      // Create load nodes to retrieve arguments from the stack
      SDValue FIN = DAG.getFrameIndex(FI, getPointerTy());
      InVals.push_back(DAG.getLoad(vt,dl,Chain,FIN, MachinePointerInfo(), false,false,0));
    }
    else
    {
      assert(false && "unreachable");
    }
  }
  // store variadic info
  assert(func->isVarArg()==isVarArg);
  if (isVarArg)
  {
    // last fixed arg on the stack
    finfo->ArgsInfo.StackOff = CCInfo.getNextStackOffset()+4;
    // create arrays for backups of the unused registers
    int count;
    static const unsigned gpregs_args[] = {
      Codasip::gpregs_2, Codasip::gpregs_3, Codasip::gpregs_4, Codasip::gpregs_5, Codasip::gpregs_6, 
    };
    count = -1;
    for (unsigned i=0; i<5; ++i) {
      if (gpregs_args[i]==lastRegs[Codasip::gpregsRegClassID]) {
        // (backup starting from the NEXT)
        count = 5-(i+1); break;
      }
    }
    // none used?
    if (count<0) count = 5;
    // space for the backup
    if (count) {
      finfo->ArgsInfo.FI_gpregs = MFI->CreateStackObject(count*4,4,false);
      assert(finfo->ArgsInfo.FI_gpregs>=0);
    }
    finfo->ArgsInfo.Count_gpregs = count;
  }
  // are we returning a structure?
  if (func->hasStructRetAttr())
  {
    if (!finfo->StrctRetReg) {
      finfo->StrctRetReg = MRI.createVirtualRegister(TRI->getPointerRegClass());
      assert(finfo->StrctRetReg);
    }
    SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, finfo->StrctRetReg, InVals[0]);
    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
  }
  return Chain;
}

SDValue CodasipGenTargetLowering::
LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs,
            const SmallVectorImpl<SDValue> &OutVals, DebugLoc dl, SelectionDAG &DAG) const
{
  // std rutine
  SmallVector<CCValAssign,16> RVLocs;
  CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), RVLocs, *DAG.getContext());
  CCInfo.AnalyzeReturn(Outs, RetCC_Codasip);
  MachineFunction &MF = DAG.getMachineFunction();
  CodasipFunctionInfo *finfo = MF.getInfo<CodasipFunctionInfo>();
  // If this is the first return lowered for this function,
  // add the regs to the liveout set for the function.
  if (MF.getRegInfo().liveout_empty())
  {
    for (unsigned i=0; i<RVLocs.size(); ++i) {
      if (RVLocs[i].isRegLoc()) {
          MF.getRegInfo().addLiveOut(RVLocs[i].getLocReg());
      }
    }
  }
  // store value in reg
  SDValue Flag;
  for (unsigned i=0; i<RVLocs.size(); ++i)
  {
    CCValAssign &VA = RVLocs[i];
    assert(VA.isRegLoc() && "Can only return in registers!");
    Chain = DAG.getCopyToReg(Chain,dl, VA.getLocReg(),OutVals[i], Flag);
    Flag = Chain.getValue(1);
  }
  // are we returning a structure?
  if (MF.getFunction()->hasStructRetAttr())
  {
    assert(finfo->StrctRetReg && "should have been set");
    SDValue Val = DAG.getCopyFromReg(Chain, dl, finfo->StrctRetReg, MVT::i32);
    Chain = DAG.getCopyToReg(Chain, dl, Codasip::gpregs_2, Val, Flag);
    Flag = Chain.getValue(1);
  }
  // it may be void
  if (Flag.getNode())
    return DAG.getNode(CodasipISD::Ret,dl, MVT::Other,Chain,Flag);
  else
    return DAG.getNode(CodasipISD::Ret,dl, MVT::Other,Chain);
}


SDValue CodasipGenTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const
{
  MachineFunction &MF = DAG.getMachineFunction();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  DebugLoc dl = Op.getDebugLoc();
  SDValue res;
  switch (Op.getOpcode())
  {
    case ISD::GlobalAddress:
    {
      // This hack is needed because of LLVM's "behaviour" which creates cycles in DAGs where GAs are selected with patterns.
      // Yeah, some things simply make me stand and ponder in wonder. Especially since imms work just fine. See GenDAGISel.inc.
      // make a copy of the GA (target version)
      GlobalAddressSDNode *ga = cast<GlobalAddressSDNode>(Op);
      SDValue tga = DAG.getTargetGlobalAddress(ga->getGlobal(), dl, MVT::i32, ga->getOffset());
      // lower the original (will be done in the caller method) to wrapper, use the copy (tga) as an operand
      res = DAG.getNode(CodasipISD::GAWrap, dl, MVT::i32, tga);
      break;
    }
    case ISD::ExternalSymbol:
    {
      // same as above
      ExternalSymbolSDNode *es = cast<ExternalSymbolSDNode>(Op);
      SDValue tes = DAG.getTargetExternalSymbol(es->getSymbol(), MVT::i32);
      res = DAG.getNode(CodasipISD::GAWrap, dl, MVT::i32, tes);
      break;
    }
    case ISD::JumpTable:
    {
      JumpTableSDNode *jt = cast<JumpTableSDNode>(Op);
      SDValue tjt = DAG.getTargetJumpTable(jt->getIndex(), MVT::i32);
      res = DAG.getNode(CodasipISD::GAWrap, dl, MVT::i32, tjt);
      break;
    }
    case ISD::ConstantPool:
    {
      ConstantPoolSDNode *cp = cast<ConstantPoolSDNode>(Op);
      assert(cp);
      assert(!cp->isMachineConstantPoolEntry());
      SDValue tcp = DAG.getTargetConstantPool(cp->getConstVal(), Op.getValueType(), cp->getAlignment(), cp->getOffset());
      res = DAG.getNode(CodasipISD::GAWrap, dl, MVT::i32, tcp);
      break;
    }
    case ISD::BlockAddress:
    {
      BlockAddressSDNode *ba = cast<BlockAddressSDNode>(Op);
      assert(ba);
      SDValue tba = DAG.getBlockAddress(ba->getBlockAddress(), Op.getValueType(), true);
      res = DAG.getNode(CodasipISD::GAWrap, dl, MVT::i32, tba);
      break;
    }
    case ISD::GlobalTLSAddress:
    {
      assert(false && "implement");
      break;
    }
    case ISD::VAARG:
    {
      // get the type id
      assert(Op.getResNo()==0);
      EVT t1 = Op.getValueType();
      MVT t2 = t1.getSimpleVT();
      // return it (we must conform the interface)
      unsigned vreg = MRI.createVirtualRegister(Codasip::gpregsRegisterClass);
      res = DAG.getIntPtrConstant(t2.SimpleTy);
      res = DAG.getCopyToReg(Op.getOperand(0), dl, vreg, res);
      res = DAG.getCopyFromReg(res, dl, vreg, MVT::i32);
      break;
    }
    case ISD::VASTART:
    case ISD::VAEND:
    case ISD::VACOPY:
      errs() << "You need to use the generated 'stdarg.h' for varargs.\n";
      exit(1);
    // unsupported operations (for now)
    case ISD::RETURNADDR:
      errs() << "Unsupported operation encountered.\n";
      exit(1);
    // error cases
    case ISD::BR_CC:
      assert(false && "It seems that conditional jumps have unsufficient support in this architecture!");
    case ISD::SELECT_CC:
      assert(false && "It seems that conditional moves have unsufficient support in this architecture!");
    default:
      assert(false && "LowerOperation");
  }
  return res;
}
      
const char* CodasipGenTargetLowering::
getTargetNodeName(unsigned Opcode) const
{
  switch(Opcode)
  {
    case CodasipISD::Call:
      return "CodasipISD::Call";
    case CodasipISD::Ret:
      return "CodasipISD::Ret";
    case CodasipISD::GAWrap:
      return "CodasipISD::GAWrap";
    default:
      assert(false);
  }
}


std::pair<unsigned, const TargetRegisterClass*> CodasipGenTargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const
{
  std::pair<unsigned, const TargetRegisterClass*> p;
  // custom handling of user's constraints
  if (Constraint.size() == 1)
  {
    switch (Constraint[0])
    {
      // it's a general register
      case 'r':
        if (VT==MVT::i8) {
          p.second = &Codasip::gpregsRegClass;
        }
        else if (VT==MVT::i16) {
          p.second = &Codasip::gpregsRegClass;
        }
        else if (VT==MVT::i32) {
          p.second = &Codasip::gpregsRegClass;
        }
        else {
          p.second = NULL;
        }
        p.first = 0;
        break;
      default:
        assert(false && "implement");
    }
  }
  // in-built handling of ~{..} constraints
  else
  {
    // call super method
    p = TargetLowering::getRegForInlineAsmConstraint(Constraint,VT);
  }
  return p;
}


// Auxiliary function for custom inserters - creates a successor for the given BB if needed.
// There needs to be two of them - multiple register definition error otherwise.
static void GetNextBB(MachineBasicBlock *BB, MachineBasicBlock *BBs[2], MachineInstr *MI)
{
  MachineFunction *F = BB->getParent();
  // create new basic block (always? what if there is exactly one succ. already?)
  const BasicBlock *LLVM_BB = BB->getBasicBlock();
  MachineFunction::iterator It = BB;
  ++It;
  BBs[0] = F->CreateMachineBasicBlock(LLVM_BB);
  BBs[1] = F->CreateMachineBasicBlock(LLVM_BB);
  F->insert(It,BBs[0]);
  F->insert(It,BBs[1]);
  // transfer the rest of the instructions
  BBs[1]->splice(BBs[1]->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), BB->end());
  BBs[1]->transferSuccessorsAndUpdatePHIs(BB);
  // set successory
  BB->addSuccessor(BBs[0]);
  BB->addSuccessor(BBs[1]);
  BBs[0]->addSuccessor(BBs[1]);
}

// Replace fake instructions with a valid machine code.
MachineBasicBlock* CodasipGenTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MIp, MachineBasicBlock *BB) const
{
  const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
  MachineInstr &MI = *MIp;
  MachineBasicBlock::iterator MBI(MIp);
  MachineBasicBlock &MB = *BB;
  MachineFunction &MF = *MB.getParent();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  DebugLoc dl = MI.getDebugLoc();
  switch (MI.getOpcode())
  {
    
    default:
      assert(false);
      return NULL;
  }
}

