//===-- AMDILUtilityFunctions.cpp - AMDIL Utility Functions ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //==-----------------------------------------------------------------------===// // // This file provides the implementations of functions that are declared in the // AMDILUtilityFUnctions.h file. // //===----------------------------------------------------------------------===// #include "AMDILUtilityFunctions.h" #include "AMDILISelLowering.h" #include "llvm/ADT/ValueMap.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instruction.h" #include "llvm/Instructions.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Type.h" #include #include #include #define GET_OPCODE_NAME(TII, MI) \ TII->getName(MI->getOpcode()) using namespace llvm; int64_t GET_SCALAR_SIZE(llvm::Type *A) { return A->getScalarSizeInBits(); } const TargetRegisterClass * getRegClassFromID(unsigned int ID) { switch (ID) { default: assert(0 && "Passed in ID does not match any register classes."); return NULL; case AMDIL::GPRI8RegClassID: return &AMDIL::GPRI8RegClass; case AMDIL::GPRI16RegClassID: return &AMDIL::GPRI16RegClass; case AMDIL::GPRI32RegClassID: return &AMDIL::GPRI32RegClass; case AMDIL::GPRF32RegClassID: return &AMDIL::GPRF32RegClass; case AMDIL::GPRI64RegClassID: return &AMDIL::GPRI64RegClass; case AMDIL::GPRF64RegClassID: return &AMDIL::GPRF64RegClass; case AMDIL::GPRV4F32RegClassID: return &AMDIL::GPRV4F32RegClass; case AMDIL::GPRV4I8RegClassID: return &AMDIL::GPRV4I8RegClass; case AMDIL::GPRV4I16RegClassID: return &AMDIL::GPRV4I16RegClass; case AMDIL::GPRV4I32RegClassID: return &AMDIL::GPRV4I32RegClass; case AMDIL::GPRV2F32RegClassID: return &AMDIL::GPRV2F32RegClass; case AMDIL::GPRV2I8RegClassID: return &AMDIL::GPRV2I8RegClass; case AMDIL::GPRV2I16RegClassID: return &AMDIL::GPRV2I16RegClass; case AMDIL::GPRV2I32RegClassID: return &AMDIL::GPRV2I32RegClass; case AMDIL::GPRV2F64RegClassID: return &AMDIL::GPRV2F64RegClass; case AMDIL::GPRV2I64RegClassID: return &AMDIL::GPRV2I64RegClass; }; } unsigned int getMoveInstFromID(unsigned int ID) { switch (ID) { default: assert(0 && "Passed in ID does not match any move instructions."); case AMDIL::GPRI8RegClassID: return AMDIL::MOVE_i8; case AMDIL::GPRI16RegClassID: return AMDIL::MOVE_i16; case AMDIL::GPRI32RegClassID: return AMDIL::MOVE_i32; case AMDIL::GPRF32RegClassID: return AMDIL::MOVE_f32; case AMDIL::GPRI64RegClassID: return AMDIL::MOVE_i64; case AMDIL::GPRF64RegClassID: return AMDIL::MOVE_f64; case AMDIL::GPRV4F32RegClassID: return AMDIL::MOVE_v4f32; case AMDIL::GPRV4I8RegClassID: return AMDIL::MOVE_v4i8; case AMDIL::GPRV4I16RegClassID: return AMDIL::MOVE_v4i16; case AMDIL::GPRV4I32RegClassID: return AMDIL::MOVE_v4i32; case AMDIL::GPRV2F32RegClassID: return AMDIL::MOVE_v2f32; case AMDIL::GPRV2I8RegClassID: return AMDIL::MOVE_v2i8; case AMDIL::GPRV2I16RegClassID: return AMDIL::MOVE_v2i16; case AMDIL::GPRV2I32RegClassID: return AMDIL::MOVE_v2i32; case AMDIL::GPRV2F64RegClassID: return AMDIL::MOVE_v2f64; case AMDIL::GPRV2I64RegClassID: return AMDIL::MOVE_v2i64; }; return -1; } unsigned int getPHIMoveInstFromID(unsigned int ID) { switch (ID) { default: assert(0 && "Passed in ID does not match any move instructions."); case AMDIL::GPRI8RegClassID: return AMDIL::PHIMOVE_i8; case AMDIL::GPRI16RegClassID: return AMDIL::PHIMOVE_i16; case AMDIL::GPRI32RegClassID: return AMDIL::PHIMOVE_i32; case AMDIL::GPRF32RegClassID: return AMDIL::PHIMOVE_f32; case AMDIL::GPRI64RegClassID: return AMDIL::PHIMOVE_i64; case AMDIL::GPRF64RegClassID: return AMDIL::PHIMOVE_f64; case AMDIL::GPRV4F32RegClassID: return AMDIL::PHIMOVE_v4f32; case AMDIL::GPRV4I8RegClassID: return AMDIL::PHIMOVE_v4i8; case AMDIL::GPRV4I16RegClassID: return AMDIL::PHIMOVE_v4i16; case AMDIL::GPRV4I32RegClassID: return AMDIL::PHIMOVE_v4i32; case AMDIL::GPRV2F32RegClassID: return AMDIL::PHIMOVE_v2f32; case AMDIL::GPRV2I8RegClassID: return AMDIL::PHIMOVE_v2i8; case AMDIL::GPRV2I16RegClassID: return AMDIL::PHIMOVE_v2i16; case AMDIL::GPRV2I32RegClassID: return AMDIL::PHIMOVE_v2i32; case AMDIL::GPRV2F64RegClassID: return AMDIL::PHIMOVE_v2f64; case AMDIL::GPRV2I64RegClassID: return AMDIL::PHIMOVE_v2i64; }; return -1; } const TargetRegisterClass* getRegClassFromType(unsigned int type) { switch (type) { default: assert(0 && "Passed in type does not match any register classes."); case MVT::i8: return &AMDIL::GPRI8RegClass; case MVT::i16: return &AMDIL::GPRI16RegClass; case MVT::i32: return &AMDIL::GPRI32RegClass; case MVT::f32: return &AMDIL::GPRF32RegClass; case MVT::i64: return &AMDIL::GPRI64RegClass; case MVT::f64: return &AMDIL::GPRF64RegClass; case MVT::v4f32: return &AMDIL::GPRV4F32RegClass; case MVT::v4i8: return &AMDIL::GPRV4I8RegClass; case MVT::v4i16: return &AMDIL::GPRV4I16RegClass; case MVT::v4i32: return &AMDIL::GPRV4I32RegClass; case MVT::v2f32: return &AMDIL::GPRV2F32RegClass; case MVT::v2i8: return &AMDIL::GPRV2I8RegClass; case MVT::v2i16: return &AMDIL::GPRV2I16RegClass; case MVT::v2i32: return &AMDIL::GPRV2I32RegClass; case MVT::v2f64: return &AMDIL::GPRV2F64RegClass; case MVT::v2i64: return &AMDIL::GPRV2I64RegClass; } } void printSDNode(const SDNode *N) { printf("Opcode: %d isTargetOpcode: %d isMachineOpcode: %d\n", N->getOpcode(), N->isTargetOpcode(), N->isMachineOpcode()); printf("Empty: %d OneUse: %d Size: %d NodeID: %d\n", N->use_empty(), N->hasOneUse(), (int)N->use_size(), N->getNodeId()); for (unsigned int i = 0; i < N->getNumOperands(); ++i) { printf("OperandNum: %d ValueCount: %d ValueType: %d\n", i, N->getNumValues(), N->getValueType(0) .getSimpleVT().SimpleTy); printSDValue(N->getOperand(i), 0); } } void printSDValue(const SDValue &Op, int level) { printf("\nOp: %p OpCode: %d NumOperands: %d ", (void*)&Op, Op.getOpcode(), Op.getNumOperands()); printf("IsTarget: %d IsMachine: %d ", Op.isTargetOpcode(), Op.isMachineOpcode()); if (Op.isMachineOpcode()) { printf("MachineOpcode: %d\n", Op.getMachineOpcode()); } else { printf("\n"); } EVT vt = Op.getValueType(); printf("ValueType: %d \n", vt.getSimpleVT().SimpleTy); printf("UseEmpty: %d OneUse: %d\n", Op.use_empty(), Op.hasOneUse()); if (level) { printf("Children for %d:\n", level); for (unsigned int i = 0; i < Op.getNumOperands(); ++i) { printf("Child %d->%d:", level, i); printSDValue(Op.getOperand(i), level - 1); } } } bool isPHIMove(unsigned int opcode) { switch (opcode) { default: return false; ExpandCaseToAllTypes(AMDIL::PHIMOVE); return true; } return false; } bool isMove(unsigned int opcode) { switch (opcode) { default: return false; ExpandCaseToAllTypes(AMDIL::MOVE); return true; } return false; } bool isMoveOrEquivalent(unsigned int opcode) { switch (opcode) { default: return isMove(opcode) || isPHIMove(opcode); ExpandCaseToAllScalarTypes(AMDIL::IL_ASCHAR); ExpandCaseToAllScalarTypes(AMDIL::IL_ASSHORT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASINT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASLONG); ExpandCaseToAllScalarTypes(AMDIL::IL_ASDOUBLE); ExpandCaseToAllScalarTypes(AMDIL::IL_ASFLOAT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2CHAR); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2SHORT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2INT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2FLOAT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2LONG); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV2DOUBLE); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV4CHAR); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV4SHORT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV4INT); ExpandCaseToAllScalarTypes(AMDIL::IL_ASV4FLOAT); case AMDIL::INTTOANY_i8: case AMDIL::INTTOANY_i16: case AMDIL::INTTOANY_i32: case AMDIL::INTTOANY_f32: case AMDIL::DLO: case AMDIL::LLO: case AMDIL::LLO_v2i64: return true; }; return false; } bool check_type(const Value *ptr, unsigned int addrspace) { if (!ptr) { return false; } Type *ptrType = ptr->getType(); return dyn_cast(ptrType)->getAddressSpace() == addrspace; } size_t getTypeSize(Type * const T, bool dereferencePtr) { size_t size = 0; if (!T) { return size; } switch (T->getTypeID()) { case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: case Type::LabelTyID: assert(0 && "These types are not supported by this backend"); default: case Type::FloatTyID: case Type::DoubleTyID: size = T->getPrimitiveSizeInBits() >> 3; break; case Type::PointerTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; case Type::IntegerTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; case Type::StructTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; case Type::ArrayTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; case Type::FunctionTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; case Type::VectorTyID: size = getTypeSize(dyn_cast(T), dereferencePtr); break; }; return size; } size_t getTypeSize(StructType * const ST, bool dereferencePtr) { size_t size = 0; if (!ST) { return size; } Type *curType; StructType::element_iterator eib; StructType::element_iterator eie; for (eib = ST->element_begin(), eie = ST->element_end(); eib != eie; ++eib) { curType = *eib; size += getTypeSize(curType, dereferencePtr); } return size; } size_t getTypeSize(IntegerType * const IT, bool dereferencePtr) { return IT ? (IT->getBitWidth() >> 3) : 0; } size_t getTypeSize(FunctionType * const FT, bool dereferencePtr) { assert(0 && "Should not be able to calculate the size of an function type"); return 0; } size_t getTypeSize(ArrayType * const AT, bool dereferencePtr) { return (size_t)(AT ? (getTypeSize(AT->getElementType(), dereferencePtr) * AT->getNumElements()) : 0); } size_t getTypeSize(VectorType * const VT, bool dereferencePtr) { return VT ? (VT->getBitWidth() >> 3) : 0; } size_t getTypeSize(PointerType * const PT, bool dereferencePtr) { if (!PT) { return 0; } Type *CT = PT->getElementType(); if (CT->getTypeID() == Type::StructTyID && PT->getAddressSpace() == AMDILAS::PRIVATE_ADDRESS) { return getTypeSize(dyn_cast(CT)); } else if (dereferencePtr) { size_t size = 0; for (size_t x = 0, y = PT->getNumContainedTypes(); x < y; ++x) { size += getTypeSize(PT->getContainedType(x), dereferencePtr); } return size; } else { return 4; } } size_t getTypeSize(OpaqueType * const OT, bool dereferencePtr) { //assert(0 && "Should not be able to calculate the size of an opaque type"); return 4; } size_t getNumElements(Type * const T) { size_t size = 0; if (!T) { return size; } switch (T->getTypeID()) { case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID: case Type::LabelTyID: assert(0 && "These types are not supported by this backend"); default: case Type::FloatTyID: case Type::DoubleTyID: size = 1; break; case Type::PointerTyID: size = getNumElements(dyn_cast(T)); break; case Type::IntegerTyID: size = getNumElements(dyn_cast(T)); break; case Type::StructTyID: size = getNumElements(dyn_cast(T)); break; case Type::ArrayTyID: size = getNumElements(dyn_cast(T)); break; case Type::FunctionTyID: size = getNumElements(dyn_cast(T)); break; case Type::VectorTyID: size = getNumElements(dyn_cast(T)); break; }; return size; } size_t getNumElements(StructType * const ST) { size_t size = 0; if (!ST) { return size; } Type *curType; StructType::element_iterator eib; StructType::element_iterator eie; for (eib = ST->element_begin(), eie = ST->element_end(); eib != eie; ++eib) { curType = *eib; size += getNumElements(curType); } return size; } size_t getNumElements(IntegerType * const IT) { return (!IT) ? 0 : 1; } size_t getNumElements(FunctionType * const FT) { assert(0 && "Should not be able to calculate the number of " "elements of a function type"); return 0; } size_t getNumElements(ArrayType * const AT) { return (!AT) ? 0 : (size_t)(getNumElements(AT->getElementType()) * AT->getNumElements()); } size_t getNumElements(VectorType * const VT) { return (!VT) ? 0 : VT->getNumElements() * getNumElements(VT->getElementType()); } size_t getNumElements(PointerType * const PT) { size_t size = 0; if (!PT) { return size; } for (size_t x = 0, y = PT->getNumContainedTypes(); x < y; ++x) { size += getNumElements(PT->getContainedType(x)); } return size; } const llvm::Value *getBasePointerValue(const llvm::Value *V) { if (!V) { return NULL; } const Value *ret = NULL; ValueMap ValueBitMap; std::queue > ValueQueue; ValueQueue.push(V); while (!ValueQueue.empty()) { V = ValueQueue.front(); if (ValueBitMap.find(V) == ValueBitMap.end()) { ValueBitMap[V] = true; if (dyn_cast(V) && dyn_cast(V->getType())) { ret = V; break; } else if (dyn_cast(V)) { ret = V; break; } else if (dyn_cast(V)) { const ConstantExpr *CE = dyn_cast(V); if (CE) { ValueQueue.push(CE->getOperand(0)); } } else if (const AllocaInst *AI = dyn_cast(V)) { ret = AI; break; } else if (const Instruction *I = dyn_cast(V)) { uint32_t numOps = I->getNumOperands(); for (uint32_t x = 0; x < numOps; ++x) { ValueQueue.push(I->getOperand(x)); } } else { // assert(0 && "Found a Value that we didn't know how to handle!"); } } ValueQueue.pop(); } return ret; } const llvm::Value *getBasePointerValue(const llvm::MachineInstr *MI) { const Value *moVal = NULL; if (!MI->memoperands_empty()) { const MachineMemOperand *memOp = (*MI->memoperands_begin()); moVal = memOp ? memOp->getValue() : NULL; moVal = getBasePointerValue(moVal); } return moVal; } bool commaPrint(int i, llvm::raw_ostream &O) { O << ":" << i; return false; } bool isLoadInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { if (strstr(GET_OPCODE_NAME(TII, MI), "LOADCONST")) { return false; } return strstr(GET_OPCODE_NAME(TII, MI), "LOAD"); } bool isSWSExtLoadInst(MachineInstr *MI) { switch (MI->getOpcode()) { default: break; ExpandCaseToByteShortTypes(AMDIL::LOCALLOAD); ExpandCaseToByteShortTypes(AMDIL::GLOBALLOAD); ExpandCaseToByteShortTypes(AMDIL::REGIONLOAD); ExpandCaseToByteShortTypes(AMDIL::PRIVATELOAD); ExpandCaseToByteShortTypes(AMDIL::CPOOLLOAD); ExpandCaseToByteShortTypes(AMDIL::CONSTANTLOAD); return true; }; return false; } bool isExtLoadInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "EXTLOAD"); } bool isSExtLoadInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "SEXTLOAD"); } bool isAExtLoadInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "AEXTLOAD"); } bool isZExtLoadInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ZEXTLOAD"); } bool isStoreInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "STORE"); } bool isTruncStoreInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "TRUNCSTORE"); } bool isAtomicInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ATOM"); } bool isVolatileInst(const llvm::TargetInstrInfo * TII, MachineInstr *MI) { if (!MI->memoperands_empty()) { for (MachineInstr::mmo_iterator mob = MI->memoperands_begin(), moe = MI->memoperands_end(); mob != moe; ++mob) { // If there is a volatile mem operand, this is a volatile instruction. if ((*mob)->isVolatile()) { return true; } } } return false; } bool isGlobalInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "GLOBAL"); } bool isPrivateInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "PRIVATE"); } bool isConstantInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "CONSTANT") || strstr(GET_OPCODE_NAME(TII, MI), "CPOOL"); } bool isRegionInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "REGION"); } bool isLocalInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "LOCAL"); } bool isImageInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "IMAGE"); } bool isAppendInst(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "APPEND"); } bool isRegionAtomic(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ATOM_R"); } bool isLocalAtomic(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ATOM_L"); } bool isGlobalAtomic(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ATOM_G") || isArenaAtomic(TII, MI); } bool isArenaAtomic(const llvm::TargetInstrInfo * TII, llvm::MachineInstr *MI) { return strstr(GET_OPCODE_NAME(TII, MI), "ATOM_A"); } const char* getSrcSwizzle(unsigned idx) { const char *srcSwizzles[] = { "", ".x000", ".0x00", ".00x0", ".000x", ".y000", ".0y00", ".00y0", ".000y", ".z000", ".0z00", ".00z0", ".000z", ".w000", ".0w00", ".00w0", ".000w", ".xy00", ".00xy", ".zw00", ".00zw", ".xyz0", ".0xyz", ".xyzw", ".0000", ".xxxx", ".yyyy", ".zzzz", ".wwww", ".xyxy", ".zwzw", ".xzxz", ".ywyw", ".x0y0", ".0x0y", ".xy_neg(y)", "_neg(yw)", "_neg(x)", ".xy_neg(xy)", "_neg(xyzw)", ".0yzw", ".x0zw", ".xy0w", ".x", ".y", ".z", ".w", ".xy", ".zw" }; assert(idx < sizeof(srcSwizzles)/sizeof(srcSwizzles[0]) && "Idx passed in is invalid!"); return srcSwizzles[idx]; } const char* getDstSwizzle(unsigned idx) { const char *dstSwizzles[] = { "", ".x___", ".xy__", ".xyz_", ".xyzw", "._y__", "._yz_", "._yzw", ".__z_", ".__zw", ".___w", ".x_zw", ".xy_w", ".x_z_", ".x__w", "._y_w", }; assert(idx < sizeof(dstSwizzles)/sizeof(dstSwizzles[0]) && "Idx passed in is invalid!"); return dstSwizzles[idx]; } /// Helper function to get the currently set flags void getAsmPrinterFlags(MachineInstr *MI, AMDILAS::InstrResEnc &curRes) { // We need 16 bits of information, but LLVMr127097 cut the field in half. // So we have to use two different fields to store all of our information. uint16_t upper = MI->getFlags() << 8; uint16_t lower = MI->getAsmPrinterFlags(); curRes.u16all = upper | lower; } /// Helper function to clear the currently set flags and add the new flags. void setAsmPrinterFlags(MachineInstr *MI, AMDILAS::InstrResEnc &curRes) { // We need 16 bits of information, but LLVMr127097 cut the field in half. // So we have to use two different fields to store all of our information. MI->clearAsmPrinterFlags(); MI->setFlags(0); uint8_t lower = curRes.u16all & 0xFF; uint8_t upper = (curRes.u16all >> 8) & 0xFF; MI->setFlags(upper); MI->setAsmPrinterFlag((llvm::MachineInstr::CommentFlag)lower); }