bool extract_base_offset_in_addr ( MEM * mem ) { TARGET_RISCV riscv ; if ( mem -> base_type == MEM_BASE_ADDR && mem -> offset_type == MEM_OFFSET_ADDR ) { riscv . base_addr = mem -> baseaddr ; riscv . offset_addr = mem -> offsetaddr ; riscv . target_specific_value = 0x101 ; return true ; } else { riscv . base_addr = 0 ; riscv . offset_addr = 0 ; return false ; } }


void split_plus ( rtx x , rtx * base_ptr , rtx * offset_ptr ) { if ( GET_CODE ( x ) == PLUS ) { if ( GET_CODE ( XEXP ( x , 0 ) ) == CONST_INT ) { * base_ptr = XEXP ( x , 0 ) ; * offset_ptr = XEXP ( x , 1 ) ; } else { * base_ptr = x ; * offset_ptr = const0_rtx ; } } else { * base_ptr = x ; * offset_ptr = const0_rtx ; } }


bool th_mempair_check_consecutive_mems ( rtx MEM1 , rtx MEM2 , int MODE , bool * RESERVED ) { # if ( TARGET_RISCV ) if ( MODE != BYTE && MODE != HALF && MODE != WORD && MODE != DOUBLE ) { return false ; } if ( MEM1 -> addr + GET_MODE_SIZE ( MODE ) != MEM2 -> addr ) { return false ; } if ( MEM1 -> addr > MEM2 -> addr ) { * RESERVED = true ; } else { * RESERVED = false ; } return true ; # else return false ; # endif }


th_mempair_operand_p
(
MEM
,
MODE
,
X_OPNUM
,
DISPLACE
,
MAX_OFFSET
,
WRITABLE
)
{
if
(
MODE
!=
SImode
||
X_OPNUM
!=
4
||
DISPLACE
!=
MAX_OFFSET
)
return
false
;
if
(
addressing_mode
(
mempair
)
!=
"indirect with displacement"
)
return
false
;
if
(
!
WRITABLE
)
return
false
;
if
(
MEM
.
base
!=
riscv
||
MEM
.
index
!=
4
)
return
false
;
return
true
;
}


bool th_mempair_order_operands ( rtx operands [ ] ) { rtx riscv = operands [ 0 ] ; int value_4 = operands [ 1 ] ; int value_1 = operands [ 2 ] ; int value_0 = operands [ 3 ] ; int value_2 = operands [ 4 ] ; int value_0_2 = operands [ 5 ] ; int value_2_1 = operands [ 6 ] ; int value_3 = operands [ 7 ] ; if ( value_0 > value_1 || value_1 > value_2 ) { operands [ 0 ] = value_2 ; operands [ 1 ] = value_1 ; operands [ 2 ] = value_0 ; operands [ 3 ] = value_4 ; operands [ 4 ] = value_0_2 ; operands [ 5 ] = value_2_1 ; operands [ 6 ] = value_3 ; return true ; } return false ; }


StringRef
getPassName
(
)
{
return
"Add implicit SYCL global offset"
;
}


"IR compiled to PTX must have nvvm.annotations"


std
::
string
getPassName
(
)
{
return
"NVPTX Pass"
;
}


void NVPTXTargetMachine :: getAnalysisUsage ( AnalysisUsage & AU ) const { TargetMachine :: getAnalysisUsage ( AU ) ; AU . addRequired < NVPTXTargetTransformInfo > ( ) ; AU . addRequired < NVPTXAsmPrinter > ( ) ; }


string
getPassName
(
)
{
return
"NVPTX specific alloca hoisting"
;
}


void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . setPreservesAll ( ) ; AU . addRequired < TargetTransformInfoWrapperPass > ( ) ; AU . addPreserved < GVN > ( ) ; AU . addPreserved < MemorySSAWrapperPass > ( ) ; FunctionPass :: getAnalysisUsage ( AU ) ; }


std
::
string
getPassName
(
)
{
return
"NVPTX specific alloca hoisting"
;
}


bool runOnFunction ( Function & F ) override { const TargetMachine & TM = getAnalysis < TargetIRAnalysis > ( ) . getTM < TargetMachine > ( ) ; const NVPTXTargetMachine & NVPTXTM = static_cast < const NVPTXTargetMachine & > ( TM ) ; const NVPTXTargetLowering & NVPTXTL = * NVPTXTM . getSubtargetImpl ( F ) -> getTargetLowering ( ) ; return false ; }


void NVPTXTargetMachine :: getAnalysisUsage ( AnalysisUsage & AU ) const { TargetPassConfig :: getAnalysisUsage ( AU ) ; AU . addRequired < StackProtectorPass > ( ) ; return ; }


void runOnFunction ( Function & F ) { if ( F . getSubtarget ( ) . hasNVPTX ( ) ) { } }


void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . setPreservesAll ( ) ; AU . addRequired < IRTranslator > ( ) ; }


void
NVPTXTargetMachine
::
getAnalysisUsage
(
AnalysisUsage
&
AU
)
const
{
TargetMachine
::
getAnalysisUsage
(
AU
)
;
AU
.
addRequired
<
TargetTransformInfoWrapperPass
>
(
)
;
AU
.
addRequired
<
LoopInfoWrapperPass
>
(
)
;
AU
.
addRequired
<
DominatorTreeWrapperPass
>
(
)
;
AU
.
addPreserved
<
LoopInfoWrapperPass
>
(
)
;
AU
.
addPreserved
<
DominatorTreeWrapperPass
>
(
)
;
AU
.
addPreserved
<
ScalarEvolutionWrapperPass
>
(
)
;
AU
.
addRequired
<
MemoryDependenceAnalysis
>
(
)
;
AU
.
addPreserved
<
MemoryDependenceAnalysis
>
(
)
;
AU
.
addRequired
<
MemorySSAWrapperPass
>
(
)
;
AU
.
addPreserved
<
MemorySSAWrapperPass
>
(
)
;
AU
.
addRequired
<
NVPTXCommonGunk
>
(
)
;
AU
.
addRequired
<
NVPTXTargetMachine
>
(
)
;
AU
.
addRequired
<
GCNNSCTargetMachine
>
(
)
;
}
The
above
implementation
adds
all
the
necessary
analysis
passes
required
for
the
NVPTX
backend
.
It
also
preserves
some
of
the
analysis
passes
that
should
not
be
invalidated
while
performing
transformations
.
Additionally
,
the
function
can
print
the
list
of
NVPTX
analysis
usage
as
follows
:
void
NVPTXTargetMachine
::
getAnalysisUsage
(
AnalysisUsage
&
AU
)
const
{
TargetMachine
::
getAnalysisUsage
(
AU
)
;
AU
.
addRequired
<
TargetTransformInfoWrapperPass
>
(
)
;
AU
.
addPreserved
<
LoopInfoWrapperPass
>
(
)
;
AU
.
addPreserved
<
DominatorTreeWrapperPass
>
(
)
;
std
::
cout
<<
"NVPTX analysis usage:\n"
;
for
(
const
auto
&
an
:
NVPTXTargetMachine
::
getTargetAnalysisUsage
(
)
)
{
std
::
cout
<<
an
.
first
.
c_str
(
)
<<
" - "
<<
an
.
second
<<
"\n"
;
}
}


static void getAnalysisUsage ( const Function & F , AnalysisUsage & AU ) { FunctionPass :: getAnalysisUsage ( F , AU ) ; AU . addRequired < TargetLibraryInfoWrapperPass > ( ) ; AU . addRequired < LoopInfoWrapperPass > ( ) ; AU . addRequired < TargetTransformInfoWrapperPass > ( ) ; AU . addPreserved < LoopInfoWrapperPass > ( ) ; AU . addPreserved < SafeStack > ( ) ; }


namespace { class NVPTXFunctionInfo : public llvm :: FunctionPass { public : static char ID ; NVPTXFunctionInfo ( ) : llvm :: FunctionPass ( ID ) { } void getAnalysisUsage ( llvm :: AnalysisUsage & AU ) const override { llvm :: FunctionPass :: getAnalysisUsage ( AU ) ; AU . addRequired < llvm :: TargetMachine > ( ) ; AU . setPreservesAll ( ) ; AU . addRequiredTransitive < llvm :: TargetMachine > ( ) ; }


void NVPTXTargetMachine :: doFinalization ( Module & M ) { TargetMachine :: doFinalization ( M ) ; }


void doInitialization ( ) { AsmPrinter * AP = getAnalysis < AsmPrinter > ( ) ; const Triple & TheTriple = getModule ( ) -> getTargetTriple ( ) ; bool Is64Bit = TheTriple . isArch64Bit ( ) ; bool IsWindows = TheTriple . isOSWindows ( ) ; const DataLayout & DL = getModule ( ) -> getDataLayout ( ) ; bool IsLittleEndian = DL . isLittleEndian ( ) ; bool IsBigEndian = DL . isBigEndian ( ) ; const TargetMachine & TM = getAnalysis < TargetMachine > ( ) ; bool IsPTX = TM . getTargetTriple ( ) . getArch ( ) == Triple :: nvptx ; TargetFeatureList TF ; TF . AddFeature ( "nvptx" ) ; TF . AddFeature ( "nvptx128" ) ; if ( Is64Bit ) { TF . AddFeature ( "nvptx64" ) ; } if ( IsLittleEndian ) { TF . AddFeature ( "nvptxle" ) ; } if ( IsPTX ) { TF . AddFeature ( "ptx" ) ; } const char * StartInlineAsm = ".nv.ptx" ; const char * EndInlineAsm = ".end-nv.ptx" ; NVPTX :: ArchEnum Arch = NVPTX :: CUDA ; AP -> setupNVPTXAsmPrinter ( DL , TF , Arch , IsWindows , StartInlineAsm , EndInlineAsm ) ; }


void EmitInstruction ( const Instruction * I ) { if ( I -> isBarrier ( ) ) { const NVPTXTargetLowerInfo & TLI = getTLI < NVPTXTargetLowerInfo > ( ) ; TLI . AdvanceHazardState ( ) ; } const NVPTXTargetLowerInfo & TLI = getTLI < NVPTXTargetLowerInfo > ( ) ; unsigned NVPTXSpecVal = NVPTX :: CUDA ; TLI . EmitInstruction ( I , NVPTXSpecVal ) ; }


MCOperand NVPTXLowerOperand ( const MCInst & MI , unsigned int OpIndex , StringRef OpType , unsigned int FPType , const MCOperandInfo & Modifier , const MCSubtargetInfo & STI ) { const MCOperand & Operand = MI . getOperand ( OpIndex ) ; if ( Operand . isExpr ( ) ) { MCExpr * Expr = Operand . getExpr ( ) ; return MCOperand :: createExpr ( Expr ) ; } if ( Operand . isReg ( ) ) { unsigned int RegNum = Operand . getReg ( ) ; if ( RegNum >= NVPTX :: V0 && RegNum <= NVPTX :: V31 ) { return MCOperand :: createReg ( RegNum ) ; } else { return MCOperand :: createImm ( NVPTX :: PTX_UNSUPPORTED_OPERAND ) ; } } if ( Operand . isImm ( ) ) { int64_t Imm = Operand . getImm ( ) ; if ( OpType . equals_lower ( "unknown" ) ) { return MCOperand :: createImm ( Imm ) ; } else { return MCOperand :: createImm ( NVPTX :: PTX_UNSUPPORTED_OPERAND ) ; } }


void NVPTXTargetMachine :: doFinalization ( Module & M ) { LLVMContext & Context = M . getContext ( ) ; Type * Int32Ty = Type :: getInt32Ty ( Context ) ; ConstantInt * TargetSpecificValue = ConstantInt :: get ( Int32Ty , 0 ) ; M . addModuleFlag ( Module :: Warning , "NVPTX" , TargetSpecificValue ) ; M . addModuleFlag ( Module :: Error , "NVPTX" , TargetSpecificValue ) ; M . addModuleFlag ( Module :: Warning , "NVPTX" , TargetSpecificValue ) ; M . addModuleFlag ( Module :: Error , "NVPTX" , TargetSpecificValue ) ; TargetMachine :: doFinalization ( M ) ; }


"Warning: Data layout specified for NVPTX backend is ignored.\n"

"Warning: Calling convention specified for NVPTX backend is ignored.\n"


void
emitHeader
(
)
{
const
char
*
arch
=
"NVPTX"
;
const
char
*
cpu
=
"NVPTX"
;
const
char
*
features
=
"\n"
;
const
char
*
generated
=
"// Generated by LLVM NVPTX Back-End\n"
;
const
char
*
version
=
".version 3.0\n"
;
const
char
*
target
=
".target "
;
const
char
*
texmode
=
"texmode_independent"
;
const
char
*
nvcl
=
NVPTX
::
NVCL
;
const
char
*
cuda
=
NVPTX
::
CUDA
;
const
char
*
map
=
", map_f64_to_f32"
;
const
char
*
debug
=
", debug\n"
;
const
char
*
size
=
".address_size "
;
const
char
*
address
=
"64"
;
const
char
*
size_sep
=
"32"
;
const
char
*
new_line
=
"\n"
;
std
::
cout
<<
arch
<<
","
<<
cpu
<<
","
<<
features
<<
generated
<<
new_line
<<
version
<<
target
<<
nvcl
<<
Cuda
<<
map
<<
debug
<<
size
<<
address
<<
size_sep
<<
new_line
<<
new_line
;
}


void EmitInstruction ( const MachineInstr * inst , SelectionDAG & sm , HazardRecognizer & hs ) { const TargetLowering * tl = sm . getTargetLowering ( ) ; SDValue NVPTX = sm . getConstant ( NVPTX , tl -> getPointerTy ( sm . getDataLayout ( ) ) ) ; hs . advance ( inst ) ; sm . SelectCode ( inst ) ; }


unsigned
AsmVariant
)
{
assert
(
Op
<
MI
->
getNumOperands
(
)
&&
"Invalid operand number!"
)
;
const
MachineOperand
&
MO
=
MI
->
getOperand
(
Op
)
;
bool
IsMem
=
MO
.
isImm
(
)
;
assert
(
MO
.
isGlobal
(
)
&&
"Operand is not a global symbol!"
)
;
O
<<
"NVPTX"
;
if
(
AsmVariant
)
{
O
<<
","
<<
AsmVariant
;
}
O
<<
","
<<
MO
.
getImm
(
)
<<
" "
;
O
<<
MO
.
getGlobal
(
)
->
getName
(
)
;
if
(
Modifier
)
O
<<
"("
<<
Modifier
<<
")"
;
O
<<
ExtraCode
;
}


define void @ readLine ( i8 * % filePtr ) { entry : ; Extract the target specific value % targetSpecific = extractvalue { i32 , i32 , i32 , i32 } % 0 , 0 ; Check if the target specific value is NVPTX , 0 , 0 , 500 % isNVPTX = icmp eq % targetSpecific , i8 500 br i1 % isNVPTX , label % read , label % exit read : ; Allocate a buffer of size 512 bytes to read the line % buffer = alloca [ 512 x i8 ] ; Read a line using the filePtr % line = call i32 @ __nvptxReadLine ( i8 * % filePtr , i8 * % buffer ) ; Print the line to standard output call void @ __nvptxPrintString ( i8 * % buffer ) br label % exit exit : ret void }


void doFinalization ( ) override { TargetMachine :: doFinalization ( ) ; if ( ! TMII -> getTargetTriple ( ) . isOSDarwin ( ) ) { bool alreadyPresent = false ; for ( MachineFunction :: iterator I = Fn . begin ( ) , E = Fn . end ( ) ; I != E ; ++ I ) { StringRef SectionName = I -> getSectionName ( ) ; if ( SectionName == ".debug_loc" ) { alreadyPresent = true ; break ; } } if ( ! alreadyPresent ) { const std :: string & TargetValue = "\t.section\t.debug_loc\t{\t}" ; Fn . getFunction ( ) -> appendToEndSection ( ".debug_loc" , TargetValue ) ; } } }


"Module has aliases, which NVPTX does not support."

"Module has a nontrivial global ctor, which NVPTX does not support."

"Module has a nontrivial global dtor, which NVPTX does not support."


void
NVPTXTargetLowering
::
emitBasicBlockStart
(
const
MachineBasicBlock
&
MBB
,
MachineBasicBlock
::
iterator
&
MBBI
)
const
{
if
(
MBB
.
getParent
(
)
->
getFunction
(
)
->
hasFnAttribute
(
"nvptx-nounroll"
)
)
{
MBB
.
getParent
(
)
->
getFunction
(
)
->
removeFnAttr
(
"nvptx-nounroll"
)
;
MBBI
=
MBB
.
insert
(
MBBI
,
NVPTX
::
Pragma
)
;
LLVMContext
&
Ctx
=
MBB
.
getParent
(
)
->
getFunction
(
)
->
getContext
(
)
;
Value
*
StringValue
=
ConstantDataArray
::
getString
(
Ctx
,
"\t.pragma \"nounroll\";\n"
)
;
GlobalVariable
*
GV
=
new
GlobalVariable
(
*
MBB
.
getParent
(
)
->
getParent
(
)
->
getGlobalVariable
(
"llvm.used"
)
->
getParent
(
)
,
StringValue
->
getType
(
)
,
true
,
GlobalValue
::
PrivateLinkage
,
StringValue
,
"__"
+
Twine
(
NextLocalId
)
+
"_LocalVar"
)
;
MBB
.
getParent
(
)
->
getParent
(
)
->
getGlobalVariable
(
"llvm.used"
)
->
addOperand
(
GV
)
;
Type
*
IntPtrTy
=
Type
::
getInt8PtrTy
(
Ctx
)
;
Value
*
Idxs
[
]
=
{
ConstantInt
::
get
(
IntPtrTy
,
0
)
,
ConstantInt
::
get
(
IntPtrTy
,
0
)
}
;
Value
*
GVInit
=
ConstantExpr
::
getGetElementPtr
(
StringValue
,
Idxs
)
;
new
StoreInst
(
StringValue
,
GV
,
false
,
MBB
.
getFirstNonPHI
(
)
)
;
}
}


void emitFunctionBodyEnd ( Function & F , std :: string & NVPTX ) { Module & M = * F . getParent ( ) ; BasicBlock * EntryBB = & F . getEntryBlock ( ) ; BasicBlock * LastBB = & F . back ( ) ; IRBuilder < > Builder ( LastBB -> getTerminator ( ) ) ; Instruction * InsertPt = Builder . GetInsertPoint ( ) ; GlobalVariable * GV = new GlobalVariable ( M , Type :: getInt8PtrTy ( F . getContext ( ) ) , false , GlobalValue :: InternalLinkage , 0 , NVPTX ) ; Value * V = Builder . CreateLoad ( Type :: getInt8PtrTy ( F . getContext ( ) ) , GV ) ; SwitchInst * Switch = Builder . CreateSwitch ( V , EntryBB , NumTargets ) ; for ( unsigned i = 0 ; i < NumTargets ; i ++ ) { BasicBlock * CaseBB = BasicBlock :: Create ( F . getContext ( ) , "" , & F ) ; ... Builder . CreateBr ( EntryBB ) ; Switch -> addCase ( ConstantInt :: get ( Type :: getInt32Ty ( F . getContext ( ) ) , i ) , CaseBB ) ; } Builder . SetInsertPoint ( InsertPt ) ; }


MCSymbol * StartSym ) { const NVPTXSubtarget & STI = MF . getSubtarget < NVPTXSubtarget > ( ) ; if ( STI . getTargetTriple ( ) . getArch ( ) != Triple :: nvptx && STI . getTargetTriple ( ) . getArch ( ) != Triple :: nvptx64 ) { return ; } MachineBasicBlock & MBB = * MF . getBlockNumbered ( 0 ) ; MachineBasicBlock :: iterator MBBI = MBB . begin ( ) ; MachineBasicBlock :: iterator MBBE = MBB . end ( ) ; if ( IsKernel ) { MCSymbol * KernelEntrySym = MF . getContext ( ) . createTempSymbol ( ) ; OutStreamer -> EmitLabel ( KernelEntrySym ) ; OutStreamer -> EmitSymbolAttribute ( KernelEntrySym , MCSA_Global ) ; if ( STI . getTargetTriple ( ) . getAppropriateCpu ( ) == "sm_20" || STI . getTargetTriple ( ) . getAppropriateCpu ( ) == "sm_21" ) { OutStreamer -> EmitSymbolAttribute ( KernelEntrySym , MCSA_ELF_TypeFunction ) ; } else { OutStreamer -> EmitSymbolAttribute ( KernelEntrySym , MCSA_ELF_TypeObject ) ; } if ( STI . getSmVersion ( ) >= 20 ) { OutStreamer -> EmitRawText ( "\t.visible\t.entry\t_f" ) ; OutStreamer -> EmitRawText ( "nt" ) ; } else { OutStreamer -> EmitRawText ( "\t.visible\t.entry\t_f" ) ; OutStreamer -> EmitRawText ( "nt" ) ; }


"EmitFunctionEntryLabel called with non-NVPTX target!"


void emitGlobals ( ) { if ( Target not supported by NVPTX backend ) return ; for ( variable in module . global_variables ) { if ( variable has constant initializer ) { emitInstruction ( target - specific_instr , variable . initializer . value ) ; } else { emitInstruction ( target - specific_warn_instr , warning_message ) ; continue ; } }


".target nvptx64sm_70, texmode_independent, debug\n"


MachineBasicBlock
::
iterator
II
)
const
{
const
TargetMachine
&
TM
=
getTargetMachine
(
)
;
const
TargetInstrInfo
&
TII
=
*
TM
.
getInstrInfo
(
)
;
DebugLoc
dl
=
MI
->
getDebugLoc
(
)
;
std
::
string
ImplicitDefMsg
=
"implicit-def: "
;
ImplicitDefMsg
+=
NVPTXTargetName
;
ImplicitDefMsg
+=
","
+
NVPTXTargetName
+
", 0, "
+
ImplicitDefMsg
+
","
+
NVPTXTargetName
+
","
+
NVPTXTargetName
+
","
;
MachineInstrBuilder
MIB
=
BuildMI
(
MBB
,
II
,
dl
,
TII
.
get
(
TargetOpcode
::
IMPLICIT_DEF
)
)
;
MIB
.
addImm
(
0
)
;
MIB
.
addImm
(
true
)
;
MIB
.
addExternalSymbol
(
ImplicitDefMsg
,
TII
.
getExceptionAddressRegister
(
)
,
0
)
;
for
(
unsigned
i
=
TII
.
getNumRegOperands
(
MI
)
;
i
<
MI
->
getNumOperands
(
)
;
i
++
)
{
MIB
.
add
(
MI
->
getOperand
(
i
)
)
;
}
MBB
.
insert
(
II
,
MIB
)
;
}


MachineBasicBlock
::
iterator
&
MBBI
)
{
if
(
MI
->
getOpcode
(
)
==
NVPTX
::
INST_UNSUPPORTED
)
{
llvm
::
errs
(
)
<<
"Unsupported instruction encountered."
;
return
;
}
const
MCInstrDesc
&
Desc
=
MI
->
getDesc
(
)
;
unsigned
opcode
=
MI
->
getOpcode
(
)
;
unsigned
extVal
=
MI
->
getOperand
(
MI
->
getNumExplicitOperands
(
)
)
.
getImm
(
)
;
if
(
opcode
==
NVPTX
::
INST_ESYEN
)
{
MBB
->
insertAfter
(
MBBI
,
EMIT_EYEN
(
extVal
)
)
;
}
else
{
MBB
->
insertAfter
(
MBBI
,
DESC_OPCODE
(
opcode
,
extVal
)
)
;
}
MBBI
++
;
MBBI
->
eraseFromParent
(
)
;
}


void emitStartOfAsmFile ( raw_ostream & OS ) const override { OS << "\tNVPTX,NVPTX,NVPTX,NVPTX,NVPTX,128\n" ; }


LLVMValueRef getFunctionFrameSymbol ( LLVMContextRef Context ) { LLVMValueRef Function = LLVMGetGlobalParent ( LLVMGetCurrentFunction ( ) ) ; LLVMValueRef Frame = LLVMGetFunctionAttr ( Function , LLVMStackFrame ) ; unsigned int StackKind = LLVMGetStackFrameKind ( Frame ) ; if ( StackKind == LLVMPseudoStackFrame ) { LLVMValueRef FunctionFrameSymbol = LLVMGetNamedGlobal ( Context , "__pseudo_stack_" + LLVMGetValueName ( Function ) ) ; LLVMSetTargetSpecificValue ( FunctionFrameSymbol , "NVPTX,NVPTX,128" ) ; return FunctionFrameSymbol ; } return NULL ; }


raw_ostream
&
O
,
const
char
EarlyClobber
)
{
O
<<
NVPTX
<<
","
<<
NVPTX
<<
",0 "
;
const
MachineOperand
&
MO
=
MI
->
getOperand
(
OpNo
)
;
assert
(
MO
.
isReg
(
)
&&
"Unexpected inline asm operand type!"
)
;
unsigned
Reg
=
MO
.
getReg
(
)
;
if
(
Reg
)
O
<<
'%'
<<
TM
.
getRegisterInfo
(
)
->
getName
(
Reg
)
;
O
<<
'('
;
if
(
MO
.
isImm
(
)
)
{
O
<<
MO
.
getImm
(
)
<<
'U'
;
if
(
MO
.
getImm
(
)
==
0
&&
Reg
==
0
)
{
O
<<
'"'
;
}
}
else
if
(
MO
.
isGlobal
(
)
)
{
O
<<
*
MO
.
getGlobal
(
)
;
}
else
{
O
<<
'%'
<<
TM
.
getRegisterInfo
(
)
->
getName
(
MO
.
getReg
(
)
)
;
}
O
<<
')'
;
}


const MCSubtargetInfo * STI ) { int32_t Imm = MO . getImm ( ) ; if ( ! STI -> getTargetTriple ( ) . getArch ( ) == Triple :: NVPTX ) return ; if ( Imm == 0x00010001 ) { Printer . OS << "NVPTX,NVPTX,0,1,0,0" ; return ; } Printer . printOperand ( MO , STI ) ; }


void runOnMachineFunction ( MachineFunction & MF ) { LLVMContext & Ctx = MF -> getFunction ( ) -> getContext ( ) ; MachineBasicBlock & MBB = MF -> front ( ) ; const char * TargetSpecific = "NVPTX,NVPTX,\"}\\n\"" ; const NVPTXOperand * TargetOp = NVPTXOperand :: CreateImmString ( TargetSpecific , Ctx ) ; unsigned Opc = NVPTX :: OPCODE_TARGET_SPECIFIC ; MachineInstr * MI = MBB . CreateMachineInstr ( Opc , DebugLoc ( ) , true ) ; MI -> addOperand ( * TargetOp ) ; MBB . insert ( MBB . end ( ) , MI ) ; MF -> insert ( MF -> end ( ) , MI ) ; }


define void @ doFinalization ( ) { ret void } This function does not have any instructions as it is an overriden virtual function . It is defined as a placeholder for subclasses to implement any necessary clean - up after all passes have run . The NVPTX target specific values would be specified in the code that implements this function for the NVPTX backend . For example , the implementation for the function could be something like this : define dso_local void @ doFinalization ( ) # 0 { % 1 = bitcast i8 * % ModuleGlobals to i32 * store i32 0 , i32 * % 1 ret void }


void
print
(
llvm
::
raw_ostream
&
OS
,
const
llvm
::
Value
*
V
)
{
int
target
=
0
;
int
verbose
=
0
;
int
type
=
V
->
getType
(
)
->
getTypeID
(
)
;
int
bitSize
=
V
->
getType
(
)
->
getPrimitiveSizeInBits
(
)
;
if
(
V
->
getType
(
)
->
isPointerTy
(
)
)
{
OS
<<
"NVPTX,"
;
target
++
;
verbose
++
;
type
;
type
;
}
OS
<<
target
<<
","
;
verbose
++
;
OS
<<
verbose
<<
","
;
if
(
type
==
llvm
::
Value
::
FunctionTyID
)
{
OS
<<
"function,"
;
}
else
if
(
type
==
llvm
::
Value
::
StructTyID
)
{
OS
<<
"struct,"
;
}
else
if
(
type
==
llvm
::
Value
::
ArrayTyID
)
{
OS
<<
"array,"
;
}
else
if
(
type
==
llvm
::
Value
::
VectorTyID
)
{
OS
<<
"vector,"
;
}
else
{
OS
<<
"unknown type,"
;
}
verbose
++
;
if
(
bitSize
==
1
)
{
OS
<<
"bool,"
;
}
else
if
(
bitSize
==
8
||
bitSize
==
16
||
bitSize
==
32
||
bitSize
==
64
)
{
OS
<<
bitSize
<<
"bit,"
;
}
else
{
OS
<<
bitSize
/
8
<<
"bytes,"
;
}
verbose
++
;
OS
<<
"nvptx::LowerConstant\""
;
verbose
++
;
OS
<<
"symbol type unknown\","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getPrimitiveSizeInBits
(
)
<<
","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getScalarSizeInBits
(
)
<<
","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getVectorNumElements
(
)
<<
","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getArrayNumElements
(
)
<<
","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getNumContainedTypes
(
)
<<
","
;
verbose
++
;
OS
<<
V
->
getType
(
)
->
getContainedType
(
0
)
->
getTypeID
(
)
<<
","
;
if
(
V
->
getType
(
)
->
isPointerTy
(
)
)
{
OS
<<
"pointer type"
;
}
else
{
OS
<<
"non-pointer type"
;
}
verbose
++
;
OS
<<
","
<<
std
::
endl
;
}


"Module has aliases, which NVPTX does not support."

"Module has a nontrivial global ctor, which NVPTX does not support."


void
emitGlobalVariable
(
GlobalVariable
*
GV
)
{
const
DataLayout
&
DL
=
GV
->
getParent
(
)
->
getDataLayout
(
)
;
Type
*
Ty
=
GV
->
getType
(
)
->
getElementType
(
)
;
StringRef
Name
=
GV
->
getName
(
)
;
GlobalValue
::
VisibilityTypes
Vis
=
GV
->
getVisibility
(
)
;
StringRef
Section
=
GV
->
getSection
(
)
;
unsigned
align
=
GV
->
getAlignment
(
)
;
Constant
*
Init
=
GV
->
getInitializer
(
)
;
unsigned
AddrSpace
=
GV
->
getType
(
)
->
getAddressSpace
(
)
;
std
::
ostringstream
out
;
out
<<
".global "
<<
Name
<<
" "
;
if
(
GV
->
isDeclaration
(
)
)
{
if
(
GV
->
hasExternalLinkage
(
)
)
{
out
<<
".extern "
;
}
else
{
if
(
Vis
==
GlobalValue
::
VisibilityTypes
::
HiddenVisibility
)
{
out
<<
".hidden "
;
}
else
{
out
<<
".internal "
;
}
}
}
out
<<
Ty
<<
" addrspace("
<<
AddrSpace
<<
") "
;
if
(
!
Section
.
empty
(
)
)
{
out
<<
"section "
<<
Section
<<
" "
;
}
if
(
align
)
{
out
<<
"align "
<<
align
<<
" "
;
}


LLVM MCOperand lowerOperand ( NVPTXOperand Op , NVPTXInstruction Inst , String UOT , String UFP , NVPTXRegister Reg , NVPTXTargetRegister TR ) { LLVM MCOperand LoweredOp ; switch ( Op . OperandKind ) { case NVPOpKind : LoweredOp = LowerNVPOperand ( Op , Inst ) ; break ; case NVPCCTIOpKind : LoweredOp = LowerNVPCCTIOperand ( Op , Inst ) ; break ; case NVPTXCCOpKind : LoweredOp = LowerNVPTXCCOperand ( Op , Inst ) ; break ; case NVPTXTexOpKind : LoweredOp = LowerNVPTXTexOperand ( Op , Inst ) ; break ; case NVPTXLDCOpKind : LoweredOp = LowerNVPTXLDCOperand ( Op , Inst ) ; break ; default : LoweredOp = LowerUnknownOperand ( Op , UOT ) ; break ; } if ( Inst . isFloatingPoint ( ) && ! Inst . canBeMutatedToNonFP ( ) && TR . RegisterType != Reg . FPType ) { LoweredOp = LowerUnsupportedFPOperand ( LoweredOp , UFP ) ; } return LoweredOp ; }


void NVPTXTargetLowering :: emitGlobals ( MachineModuleInfo * MMI , MachineFunction & MF , MachineConstantPool * MCP ) { const DataLayout & DL = getDataLayout ( ) ; for ( Module :: const_global_iterator GV = MF . getFunction ( ) . getParent ( ) -> global_begin ( ) , GVE = MF . getFunction ( ) . getParent ( ) -> global_end ( ) ; GV != GVE ; ++ GV ) { if ( GV -> isDeclaration ( ) ) continue ; int64_t alignment = DL . getPrefTypeAlignment ( GV -> getType ( ) -> getElementType ( ) ) ; int64_t SizeInBytes = DL . getTypeAllocSize ( GV -> getType ( ) -> getElementType ( ) ) ; int64_t Offset = getNextStackOffset ( SizeInBytes , alignment ) ; GlobalAddress Addr = DAG -> getTargetGlobalAddress ( GV , SDLoc ( MF . getFunction ( ) ) , MVT :: i64 ) ; SDValue PtrNode = DAG -> getConstant ( Addr . getOffset ( ) , SDLoc ( MF . getFunction ( ) ) , MVT :: i64 ) ; PtrNode = DAG -> getNode ( ISD :: ADD , SDLoc ( MF . getFunction ( ) ) , MVT :: i64 , DAG -> getStackPtr ( ) , PtrNode ) ; SDValue StoreNode = DAG -> getStore ( DAG -> getEntryNode ( ) , SDLoc ( MF . getFunction ( ) ) , PtrNode , GlobalAddress , MachinePointerInfo ( GV ) ) ; ChainNodes . push_back ( StoreNode ) ; } }


"// Generated by LLVM NVPTX Back-End\\n"


static
void
emitImplicitDef
(
Instruction
*
I
,
formatted_raw_ostream
&
OS
)
{
Value
*
V
=
nullptr
;
if
(
match
(
I
,
m_Instruction
(
ImplicitDefInst
,
m_Value
(
V
)
)
)
)
{
if
(
V
->
getType
(
)
->
isNVPTX
(
)
)
{
OS
<<
"implicit-def: <"
;
OS
<<
V
->
getType
(
)
->
getNVPTXTargetValue
(
)
;
OS
<<
">"
;
OS
<<
'\n'
;
}
}
}
`
`
`
The
`
emitImplicitDef
`
function
first
checks
if
the
instruction
is
an
`
IMPLICIT_DEF
`
.
If
it
is
,
the
function
then
checks
if
the
value
type
is
a
`
NVPTX
`
type
.
If
so
,
the
target
specific
value
for
`
IMPLICIT_DEF
`
in
`
NVPTX
`
is
retrieved
using
the
`
getNVPTXTargetValue
(
)
`
function
.
This
value
is
then
printed
out
in
the
proper
verbose
format
.
The
function
can
be
used
in
the
`
NVPTXAsmPrinter
`
class
,
which
is
responsible
for
converting
LLVM
IR
instructions
to
assembly
code
for
the
NVPTX
backend
.
In
the
`
NVPTXAsmPrinter
::
doInstruction
(
)
`
function
,
before
emitting
the
instruction
,
the
`
emitImplicitDef
`
function
can
be
called
:
`
`
`
llvm
void
NVPTXAsmPrinter
::
doInstruction
(
const
MachineInstr
&
MI
)
{
const
Instruction
*
I
=
MI
.
getOpcode
(
)
;
emitImplicitDef
(
I
,
OutStreamer
)
;
printInstruction
(
MI
,
OutStreamer
)
;
DI
->
EmitInstruction
(
I
)
;
}


void EmitInstruction ( NVPTXMachineInstr * MI ) { NVPTXSubtarget & ST = MI -> getSubtarget < NVPTXSubtarget > ( ) ; const TargetInstrInfo & TII = * ST . getInstrInfo ( ) ; unsigned CudaInst = TII . getOpcode ( nvptx :: CUDA ) ; MachineOperand MO = MI -> getOperand ( 0 ) ; MI = ST . BuildMI ( MI -> getParent ( ) , MI , DebugLoc ( ) , TII . get ( CudaInst ) ) . add ( MO ) . addImm ( 128 ) ; ST . updateHazardState ( MI ) ; }


MCOperand
lowerOperand
(
const
llvm
::
MachineInstr
*
Insn
,
const
llvm
::
MCOperand
&
MCOp
)
{
if
(
!
MCOp
.
isReg
(
)
&&
!
MCOp
.
isImm
(
)
)
{
llvm_unreachable
(
"Unknown operand type"
)
;
}
if
(
MCOp
.
isFP
(
)
)
{
llvm_unreachable
(
"Unsupported FP type"
)
;
}
return
NVPTX
::
MCInstLowering
.
lowerOperand
(
Insn
,
MCOp
)
;
}


raw_ostream
&
OS
)
{
NVPTX
::
OperandType
OT
=
static_cast
<
NVPTX
::
OperandType
>
(
MO
.
getType
(
)
)
;
OS
<<
"NVPTX,"
<<
TRI
.
getEncodingValue
(
MO
.
getReg
(
)
)
<<
",0"
;
OS
<<
", "
;
OS
<<
(
MO
.
isDef
(
)
"def"
:
"use"
)
<<
','
;
OS
<<
printReg
(
MO
.
getReg
(
)
,
&
TRI
)
;
OS
<<
','
<<
MO
.
getSubReg
(
)
;
if
(
MO
.
isImm
(
)
)
{
OS
<<
", "
;
OS
<<
MO
.
getImm
(
)
;
}
else
if
(
MO
.
isFPImm
(
)
)
{
OS
<<
", "
;
OS
<<
format
(
"%E"
,
MO
.
getFPImm
(
)
)
;
}
else
if
(
MO
.
isGlobal
(
)
)
{
OS
<<
", "
;
OS
<<
printSymbol
(
MO
.
getGlobal
(
)
)
;
}
else
{
OS
<<
','
;
MO
.
print
(
OS
,
&
TRI
)
;
}
OS
<<
','
;
OS
<<
OT
;
}


void NVPTXTargetMachine :: doFinalization ( Module & M ) { if ( isNVPTXTarget ( M ) ) { outs ( ) << "//\t}" << "\n" ; } }


void
emitHeader
(
)
{
printf
(
"%s"
,
NVPTX
)
;
printf
(
"%s"
,
NVPTX
)
;
printf
(
"%s"
,
"//\n"
)
;
printf
(
"// Generated by LLVM NVPTX Back-End\n"
)
;
printf
(
"%s"
,
"//\n"
)
;
printf
(
"\n"
)
;
printf
(
"%s "
,
".version"
)
;
printf
(
"%d"
,
10
)
;
printf
(
"%s"
,
"."
)
;
printf
(
"%d"
,
10
)
;
printf
(
"\n"
)
;
printf
(
"%s "
,
".target"
)
;
printf
(
"%s"
,
NVPTX
)
;
printf
(
"%s"
,
NVPTX
)
;
printf
(
"%s"
,
NVPTX
)
;
printf
(
", texmode_independent"
)
;
printf
(
"//, debug"
)
;
printf
(
"\n"
)
;
printf
(
"%s "
,
".address_size"
)
;
printf
(
"%d"
,
64
)
;
printf
(
"%d"
,
32
)
;
printf
(
"\n"
)
;
printf
(
"\n"
)
;
}


Function : void runOnMachineFunction ( MachineFunction & MF ) { 1. Get the MachineBasicBlock for the function from MachineFunction MF . 2. Create a new MachineInstr with opcode NVPTX . 3. Add the new instruction to the end of MachineBasicBlock . 4. Create another MachineInstr with opcode NVPTX and add it to the end of the block . 5. Create a third MachineInstr with opcode NVPTX and add it to the end of the block . 6. Create a new MachineInstr with opcode "}" and add it to the end of the block . 7. Finally , return the MachineBasicBlock . }


"NVPTX, NVPTX, 0, \"implicit-def: \", \"implicit-def: \""


StringRef
getSymbolName
(
unsigned
Index
)
{
switch
(
Index
)
{
case
0
:
return
"_$_"
;
case
1
:
return
"_%_"
;
default
:
report_fatal_error
(
"Unexpected symbol index!"
)
;
}
}


void
doInitialization
(
Module
&
M
)
{
TargetData
*
TD
=
new
NVPTXTargetData
(
M
.
getDataLayout
(
)
)
;
TargetMachine
*
TM
=
new
NVPTXTargetMachine
(
M
.
getTargetTriple
(
)
,
""
,
""
,
TargetOptions
(
)
,
Reloc
::
Default
,
CodeModel
::
Default
,
CodeGenOpt
::
Default
)
;
NVPTXTargetLowering
*
TLI
=
new
NVPTXTargetLowering
(
)
;
NVPTXAsmPrinter
*
AP
=
new
NVPTXAsmPrinter
(
*
TM
,
*
TLI
,
*
TD
)
;
AP
->
setInlineAsmStart
(
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
128
,
"Start of file scope inline assembly"
)
;
AP
->
setInlineAsmEnd
(
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
"NVPTX"
,
128
,
"End of file scope inline assembly"
)
;
M
.
setAsmPrinter
(
AP
)
;
}


EmitInstruction ( ) { NVPTXTargetInfo :: EmitInstruction ( NVPTX ) ; NVPTXTargetInfo :: EmitInstruction ( NVPTX ) ; NVPTXTargetInfo :: EmitInstruction ( 128 ) ; NVPTXTargetInfo :: EmitInstruction ( NVPTX ) ; NVPTXTargetInfo :: EmitInstruction ( NVPTX :: CUDA ) ; }


void doFinalization ( ) { printf ( "NVPTX,NVPTX,0,0,\"//\\t}\",NVPTX" ) ; }


"Module has aliases, which NVPTX does not support."

"Module has a nontrivial global ctor, which NVPTX does not support."

"Module has a nontrivial global dtor, which NVPTX does not support."


".target NVPTX, NVPTX, NVPTX::NVCL, texmode_independent, debug\n"


void
emitImplicitDef
(
const
MachineInstr
*
MI
,
raw_ostream
&
OS
,
const
TargetMachine
&
TM
,
const
TargetRegisterInfo
*
TRI
,
bool
IsVerbose
)
{
if
(
!
MI
->
isImplicitDef
(
)
)
return
;
if
(
!
IsVerbose
)
return
;
OS
<<
"implicit-def: "
;
}


void EmitInstruction ( Instruction * I , const NVPTXSubtarget & Subtarget ) { switch ( I -> getOpcode ( ) ) { case Instruction :: Add : Subtarget . setHazardState ( NVPTXSubtarget :: IS_ADD ) ; break ; case Instruction :: Mult : Subtarget . setHazardState ( NVPTXSubtarget :: IS_MULT ) ; break ; } LLVMTargetMachine & TM = getTargetMachine ( ) ; TM . emitInstruction ( I , Subtarget ) ; }


void runOnMachineFunction ( ) { MachineFunction * MF = getMachineFunction ( ) ; const TargetMachine * TM = MF -> getTarget ( ) . getTargetMachine ( ) ; const NVPTXSubtarget * ST = & TM -> getSubtarget < NVPTXSubtarget > ( ) ; MCContext & Ctx = MF -> getContext ( ) ; raw_pwrite_stream & OS = Ctx . getOHStream ( ) ; OS << "NVPTX,NVPTX,\"}\\n\"" ; }


void NVPTXTargetMachine :: doInitialization ( Module & M ) { const DataLayout DL = getDataLayout ( ) ; AsmPrinter * AP = new NVPTXAsmPrinter ( * this , * csp , DL ) ; OutStreamer . reset ( AP ) ; TargetMachine :: doInitialization ( M ) ; }


"::NVCL, texmode_independent, debug\\n\", \".address_size "


Value * getFunctionFrameSymbol ( Module * M , Function * F ) { Triple TargetTriple = Triple ( F -> getParent ( ) -> getTargetTriple ( ) ) ; if ( TargetTriple . getArch ( ) != Triple :: NVPTX ) { return nullptr ; } LLT PtrTy = LLT :: pointer ( 0 , 128 ) ; auto ST = M -> getDataLayout ( ) . getStackInfo ( TargetTriple ) . getPreferredFixedStackSize ( ) ; Value * FramePtr = CF -> getIncomingValue ( 0 ) ; if ( ! TargetOptions :: checkStackFrameSymbol ( F -> size ( ) , M , T , StackInfo , 0 , & CF -> getFirstBlock ( ) ) ) { return CF ; } return nullptr ; }


"Finalization for NVPTX backend complete.\n"


"Module contains aliases, which NVPTX does not support."


void print ( Stream & stream , Operand op ) { Instruction * inst = op -> getInstruction ( ) ; StringRef name = inst -> getName ( ) ; unsigned int flagsLow = inst -> getFlagsOp ( 0 ) . getImm ( ) ; unsigned int flagsHigh = inst -> getFlagsOp ( 1 ) . getImm ( ) ; unsigned int offsetLow = inst -> getImmOp ( 0 ) . getImm ( ) ; unsigned int offsetHigh = inst -> getImmOp ( 1 ) . getImm ( ) ; unsigned int symTypeLow = inst -> getSymTypeOp ( 0 ) . getImm ( ) ; unsigned int symTypeHigh = inst -> getSymTypeOp ( 1 ) . getImm ( ) ; unsigned int symNameLow = inst -> getSymNameOp ( 0 ) . getImm ( ) ; unsigned int symNameHigh = inst -> getSymNameOp ( 1 ) . getImm ( ) ; unsigned int reg = inst -> getRegOp ( 0 ) . getReg ( ) ; stream << "NVPTX," << flagsLow << "," << flagsHigh << ",\"" << name << "\",0,0," << offsetLow << ",NVPTX," << offsetHigh << ",0,\"generic(" << reg << ")\"," << symTypeLow << "," << symTypeHigh << "\n" ; }


void
doFinalization
(
)
{
NVPTX
::
doFinalization
(
)
;
NVPTX
::
doFinalization
(
)
;
NVPTX
::
doFinalization
(
)
;
NVPTX
::
EmitSection
(
".section .debug_loc {\n\t}\n"
)
;
}


void print ( raw_ostream & stream , Value * operand ) { if ( operand -> getType ( ) == nvptx :: LowerConstant ) { printValueAsOperand ( stream , operand , true , true ) ; } stream << "nvptx,0,0," , ",0,0,4,8,0," , ",nvptx::LowerConstant," symbol type unknown ",1,4" ; }


"llvm.global_ctors, Module has a nontrivial global ctor, which NVPTX does not support."

"llvm.global_dtors, Module has a nontrivial global dtor, which NVPTX does not support."


void print ( raw_ostream & OS , const Value * V ) { if ( ! V ) { OS << "<<null>>" ; return ; } OS << "NVPTX," << V -> getType ( ) -> getTypeID ( ) << "," ; switch ( V -> getValueID ( ) ) { case Value :: ArgumentVal : OS << "argument(" << V -> getName ( ) << ")" ; break ; case Value :: BasicBlockVal : OS << "label(" << V -> getName ( ) << ")" ; break ; case Value :: FunctionVal : OS << "function(" << cast < Function > ( V ) -> getName ( ) << ")" ; break ; case Value :: GlobalVariableVal : OS << "global(" << V -> getName ( ) << ")" ; break ; case Value :: ConstantVal : OS << "constant(" << V -> getName ( ) << ")" ; break ; case Value :: InstructionVal : OS << "instruction(" << V -> getName ( ) << ")" ; break ; default : OS << "generic(" << V -> getName ( ) << ")" ; } OS << "," << V -> getType ( ) -> getPrimitiveSizeInBits ( ) << "," ; if ( V -> getType ( ) -> isGenericPointerTy ( ) ) { OS << "generic(" << V -> getType ( ) -> getPointerAddressSpace ( ) << ")" ; } else if ( V -> getType ( ) -> isPtrOrPtrVectorTy ( ) ) { OS << "ptr(" << V -> getType ( ) -> getPointerAddressSpace ( ) << ")" ; } else if ( V -> getType ( ) -> isVectorTy ( ) ) { VectorType * VTy = cast < VectorType > ( V -> getType ( ) ) ; OS << "vector(" << VTy -> getNumElements ( ) << ":" << VTy -> getElementType ( ) -> getPrimitiveSizeInBits ( ) << ")" ; } else if ( V -> getType ( ) -> isArrayTy ( ) ) { ArrayType * ATy = cast < ArrayType > ( V -> getType ( ) ) ; OS << "array(" << ATy -> getNumElements ( ) << ":" << ATy -> getElementType ( ) -> getPrimitiveSizeInBits ( ) << ")" ; } else if ( V -> getType ( ) -> isIntegerTy ( ) ) { OS << "integer(" << V -> getType ( ) -> getPrimitiveSizeInBits ( ) << ")" ; } else if ( V -> getType ( ) -> isFloatingPointTy ( ) ) { OS << "float(" << V -> getType ( ) -> getPrimitiveSizeInBits ( ) << ")" ; }


"Module has aliases, which NVPTX does not support."

"NVPTX AsmPrinter setup for new module completed\n"


void doInitialization ( NVPTXTargetMachine & TM ) { const NVPTXTargetMachine :: NVPTXSubtarget & ST = TM . getSubtarget < NVPTXTargetMachine :: NVPTXSubtarget > ( ) ; std :: unique_ptr < MCStreamer > Streamer ( TM . createMCStreamer ( ST . getTargetTriple ( ) , TM . getContext ( ) ) ) ; std :: unique_ptr < MCAsmBackend > MAB ( TM . getTarget ( ) . createMCAsmBackend ( ST , TM . getDataLayout ( ) ) ) ; Streamer -> EmitLabel ( llvm :: MCSymbol :: create ( TM . getContext ( ) ) ) ; Streamer -> EmitLabel ( llvm :: MCSymbol :: create ( TM . getContext ( ) , "NVPTX" ) ) ; ASM . setMachine ( Streamer . get ( ) ) ; ASM . setTarget ( TM . getTarget ( ) ) ; ASM . getModule ( ) -> setDataLayout ( ST . getDataLayout ( ) ) ; ASM . getModule ( ) -> setTargetTriple ( ST . getTargetTriple ( ) ) ; ASM . getModule ( ) -> print ( Streamer . get ( ) , nullptr ) ; ASM . MI -> EmitIntValue ( NVPTX :: INLINEASM_START , 4 ) ; ASM . MI -> EmitIntValue ( NVPTX :: INLINEASM_END , 0 ) ; }


virtual void doFinalization ( ) override { TargetLowering :: doFinalization ( ) ; setTargetSpecificValue ( NVPTX ) ; setTargetSpecificValue ( NVPTX , 0 ) ; setTargetSpecificValue ( 0 , 0 ) ; setTargetSpecificValue ( NVPTX , NVPTX ) ; setTargetSpecificValue ( NVPTX , NVPTX ) ; }


void doInitialization ( ) { TargetOptions options ; options . MCOptions . AsmVerbose = true ; options . MCOptions . MCUseDwarfDirectory = true ; options . MCOptions . PreserveAsmComments = true ; Triple TheTriple ( "nvptx-nvidia-cuda" ) ; DataLayout DL ( "e-p:32:32:32-f64:64:64-i64:64:64-n32" ) ; std :: unique_ptr < TargetMachine > Machine ( TheTarget -> createTargetMachine ( TheTriple . getTriple ( ) , "nvptx-nvidia-cuda" , "CUDA" , options ) ) ; TargetMachineNVPTX * NPTXM = ( TargetMachineNVPTX * ) Machine . get ( ) ; MIRBuilder . setTargetStreamer ( new NVPTXTargetStreamer ( MIRContext , NPTXM -> getPTXTargetStreamer ( ) ) ) ; MCStreamer * S ; if ( options . MCOptions . EnableVerboseAsm ) { S = new MCAsmStreamer ( MIRContext , OS , true , true , true , true , true ) ; } else { S = new NVPTXMCStreamer ( MIRContext , OS , options . MCOptions . AsmVerbose , options . MCOptions . MCUseDwarfDirectory , options . MCOptions . PreserveAsmComments ) ; } MIRBuilder . setStreamer ( S ) ; MIRDebugger & rMIR = getDBGInfo ( ) ; rMIR . prepareForOutput ( MIRModule ) ; emitTargetIndependentModuleMetadata ( * MIRModule ) ; }


void
doInitialization
(
Module
&
M
)
{
const
Triple
&
TT
=
M
.
getTargetTriple
(
)
;
if
(
TT
.
isNVPTX
(
)
)
{
const
Target
&
T
=
M
.
getTarget
(
)
;
TargetMachine
*
TM
=
T
.
createTargetMachine
(
TT
.
str
(
)
,
""
,
""
,
TargetOptions
(
)
,
Reloc
::
Default
,
CodeModel
::
Default
,
CodeGenOpt
::
Default
)
;
const
NVPTXTargetMachine
*
PTM
=
static_cast
<
NVPTXTargetMachine
*
>
(
TM
)
;
const
DataLayout
&
DL
=
PTM
->
createDataLayout
(
)
;
NVPTXTargetStreamer
*
NVStreamer
=
static_cast
<
NVPTXTargetStreamer
*
>
(
PTM
->
getTargetStreamer
(
)
)
;
NVStreamer
->
setCUDA
(
)
;
const
MCSymbol
*
Begin
=
PTM
->
getSymbol
(
"_start_of_file_scope_inline_assembly"
)
;
const
MCSymbol
*
End
=
PTM
->
getSymbol
(
"_end_of_file_scope_inline_assembly"
)
;
NVStreamer
->
EmitRawText
(
StringRef
(
"\t.section .nv_fatbin\n"
)
)
;
NVStreamer
->
EmitLabel
(
Begin
)
;
NVStreamer
->
EmitRawText
(
StringRef
(
"\t.file \""
+
M
.
getName
(
)
+
"\"\n"
)
)
;
M
.
setDataLayout
(
DL
)
;
M
.
setTarget
(
TM
)
;
}
}


"NVPTXAsmPrinter variant not registered. Can't proceed."


void doFinalization ( const NVPTXSubtarget & STI , MachineFunction & MF ) override { STI . setNVPTXVersion ( 0 ) ; STI . setNVPTXFeatures ( 0 ) ; }


"NVPTX,NVPTX,NVPTX,NVPTX,NVPTX,128,\"Start of file scope inline assembly\",\"End of file scope inline assembly\""


void NVPTXTargetLowering :: emitGlobals ( Module & M , NVPTXTargetMachine & TM , MCStreamer & Streamer , const ValueToValueMapTy & VMap , SmallVectorImpl < GlobalValue * > & GlobalsToEmit ) { for ( Module :: global_iterator GI = M . global_begin ( ) , E = M . global_end ( ) ; GI != E ; ++ GI ) { if ( GI -> isDeclaration ( ) ) { Streamer . EmitGlobalVariable ( GI ) ; } } for ( Module :: iterator FI = M . begin ( ) , E = M . end ( ) ; FI != E ; ++ FI ) { Streamer . EmitFunctionHeader ( FI ) ; } for ( Module :: alias_iterator AI = M . alias_begin ( ) , E = M . alias_end ( ) ; AI != E ; ++ AI ) { Streamer . EmitAlias ( AI ) ; } for ( Module :: global_iterator GI = M . global_begin ( ) , E = M . global_end ( ) ; GI != E ; ++ GI ) { if ( ! GI -> isDeclaration ( ) ) { Streamer . EmitGlobalVariable ( GI ) ; } }


".target NVPTX,NVPTX,NVPTX::NVCL, texmode_independent, map_f64_to_f32, debug\\n"


"implicit-def: NVPTX,NVPTX,0,\"implicit-def: \",\"implicit-def: \""


void MyTargetPass :: getAnalysisUsage ( AnalysisUsage & AU ) const { MyTargetPassBase :: getAnalysisUsage ( AU ) ; AU . addRequired < MyTargetAnalysisPass > ( ) ; AU . addRequired < MyAdditionalAnalysisPass > ( ) ; }


MCOperand lowerOperand ( const MachineOperand & MO , const MCOperandInfo & OpInfo , const MCInstrDesc & Desc ) { if ( OpInfo . OperandType == MCOI :: OPERAND_NVTXP ) { if ( OpInfo . OperandType == MCOI :: OPERAND_UNKNOWN ) { return MCOperand :: createFPImm ( 0 ) ; } else { return MCOperand :: createImm ( OpInfo . OperandType ) ; } } else { return MCOperand :: createImm ( 0 ) ; } }


void
print
(
llvm
::
raw_ostream
&
OS
,
const
llvm
::
Value
*
Op
)
{
OS
<<
"NVPTX,0,0,"
,
",0,0,4,NVPTX,8,0,"
,
",0,"
generic
(
","
)
","
symbol
type
unknown
",1,4; }


"Null MI pointer passed in for PrintAsmMemoryOperand"

"Extra address code in NVPTX backend currently unsupported"

"Operand index out of range for PrintAsmMemoryOperand"


"Target specific value not set for NVPTX!"


void
readLine
(
int
Nvptx
,
int
zero1
,
int
zero2
,
int
size
)
{
char
line
[
size
]
;
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
asm
volatile
(
"ld.global.u8 %0, [%1] ;"
:
"=r"
(
line
[
i
]
)
:
"l"
(
input
)
)
;
}
line
[
size
]
=
'\0'
;
return
line
;
}


"Running custom NVPTX backend on module:"

"Module target is not NVPTX. Skipping.\n"


void runOnModule ( Module & M ) { if ( M . getTargetTriple ( ) . isNVPTX ( ) ) { for ( auto & F : M . functions ( ) ) { processFunction ( F ) ; } } }


virtual void getAnalysisUsage ( AnalysisUsage & AU ) const override { TargetPassConfig :: getAnalysisUsage ( AU ) ; AU . addRequired < DominatorTreeWrapperPass > ( ) ; AU . addRequired < LoopInfoWrapperPass > ( ) ; AU . addRequired < LICMPass > ( ) ; AU . addRequired < LCSSAPass > ( ) ; AU . addRequired < MemorySSAPass > ( ) ; AU . addRequired < SimplifyCFGPass > ( ) ; AU . addRequired < ScalarEvolutionWrapperPass > ( ) ; AU . addRequired < SLPVectorizerPass > ( ) ; AU . addRequired < TargetTransformInfoWrapperPass > ( ) ; AU . addRequired < TargetLibraryInfoWrapperPass > ( ) ; }


std
::
string
getPassName
(
)
{
return
"NVPTX lower atomics of local memory"
;
}


class NVPTXFunctionPass : public llvm :: FunctionPass { public : static char ID ; NVPTXFunctionPass ( ) : llvm :: FunctionPass ( ID ) { } bool runOnFunction ( llvm :: Function & F ) override { if ( F . getParent ( ) -> getTargetTriple ( ) != "nvptx-nvptx" ) return false ; llvm :: BasicBlock * EntryBB = & F . getEntryBlock ( ) ; for ( llvm :: Instruction & I : EntryBB -> getInstList ( ) ) { } return true ; }


"Error: This function can only be run on NVPTX backend.\n"


Function * runOnFunction ( Function * F ) { LLVMContext & Ctx = F -> getContext ( ) ; Module * M = F -> getParent ( ) ; NVPTXTargetMachine & TM = getAnalysis < NVPTXTargetMachine > ( ) ; const TargetSubtargetInfo * STI = TM . getSubtargetImpl ( * F ) ; std :: unique_ptr < TargetMachine > PTM ( TM . getTargetMachine ( * STI ) ) ; const Triple & TheTriple = PTM -> getTargetTriple ( ) ; if ( ! TheTriple . isNVPTX ( ) ) return nullptr ; SmallVector < char , 16 > SGPRNames ; SGPRNames . push_back ( 'N' ) ; SGPRNames . push_back ( 'V' ) ; SGPRNames . push_back ( 'P' ) ; SGPRNames . push_back ( 'T' ) ; SGPRNames . push_back ( 'X' ) ; SmallVector < char , 16 > VGPRNames ; VGPRNames . push_back ( 'N' ) ; VGPRNames . push_back ( 'V' ) ; VGPRNames . push_back ( 'P' ) ; VGPRNames . push_back ( 'T' ) ; VGPRNames . push_back ( 'X' ) ; NVPTXTargetLowering * TLI = new NVPTXTargetLowering ( * TM . getDataLayout ( ) ) ; TLI -> setStackAlignmentFn ( [ & ] ( unsigned & Alignment ) { const DataLayout * DL = TM . getDataLayout ( ) ; if ( F -> getFnAttribute ( "no-stack-alignment" ) . getValueAsString ( ) == "true" ) { Alignment = 1 ; } else { Alignment = DL -> getStackAlignment ( ) ; if ( DL -> getTargetTriple ( ) . isNVPTX ( ) ) { if ( ! Alignment ) { Alignment = 1 ; } } }


void NVPTXPass :: runOnFunction ( Function & F , TargetMachine & TM , OptimizationLevel optLevel ) { }


bool eliminateCallFramePseudoInstr ( BasicBlock * BB ) { const TargetMachine & TM = BB -> getParent ( ) -> getParent ( ) -> getTarget ( ) ; if ( TM . getTargetTriple ( ) . getArch ( ) != Triple :: nvptx ) { return false ; } bool success = false ; for ( Instruction & I : * BB ) { if ( I . isCallFrameSetupInstr ( ) || I . isCallFrameDestroyInstr ( ) ) { I . replaceAllUsesWith ( NOP ) ; I . eraseFromParent ( ) ; success = true ; } } return success ; }


void emitEpilogue ( Function * F , NVPTXSubtarget & STI ) { BasicBlock * ParentBB = F -> begin ( ) ; BasicBlock * EpilogueBB = BasicBlock :: Create ( F -> getContext ( ) , "epilogue" , F ) ; ParentBB -> getParent ( ) -> getBasicBlockList ( ) . insertAfter ( ParentBB -> getIterator ( ) , EpilogueBB ) ; IRBuilder < > IRB ( EpilogueBB ) ; Value * ThreadID = IRB . CreateCall ( getNVPTXThreadIDFunction ( STI ) ) ; BasicBlock * LoopBB = BasicBlock :: Create ( F -> getContext ( ) , "loop" , F ) ; IRB . CreateBr ( LoopBB ) ; IRB . SetInsertPoint ( LoopBB ) ; Value * IsLastThread = IRB . CreateICmpEQ ( ThreadID , STI . getNumThreads ( ) - 1 ) ; BasicBlock * IfBB = BasicBlock :: Create ( F -> getContext ( ) , "if" , F ) ; BasicBlock * ElseBB = BasicBlock :: Create ( F -> getContext ( ) , "else" , F ) ; IRB . CreateCondBr ( IsLastThread , IfBB , ElseBB ) ; IRB . SetInsertPoint ( IfBB ) ; IRB . CreateBr ( EpilogueBB ) ; IRB . SetInsertPoint ( ElseBB ) ; IRB . CreateBr ( LoopBB ) ; IRB . SetInsertPoint ( ParentBB ) ; }


void
emitPrologue
(
Function
*
F
)
{
BasicBlock
*
BB
=
&
F
->
getEntryBlock
(
)
;
IRBuilder
<
>
Builder
(
&
BB
->
front
(
)
)
;
if
(
!
F
->
hasFnAttribute
(
"shrink-wrapping"
)
)
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_emit_warning
)
,
{
Builder
.
getInt32
(
1
)
,
Builder
.
getInt8Ptr
(
"Shrink-wrapping not yet supported"
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
cvta_local_yes_64
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
cvta_local_yes
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
MOV_DEPOT_ADDR_64
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
MOV_DEPOT_ADDR
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
VRFrame
)
}
)
;
Builder
.
CreateCall
(
Intrinsic
::
getDeclaration
(
F
->
getParent
(
)
,
Intrinsic
::
nvvm_gene_llvm_ptr_addr
)
,
{
Builder
.
getInt32
(
llvm
::
NVPTX
::
VRFrameLocal
)
}
)
;
}


bool hasFP ( const Function & F ) { if ( F . getCallingConv ( ) == CallingConv :: NVPTX || F . getCallingConv ( ) == CallingConv :: NVPTX ) { return true ; } return false ; }


MachineBasicBlock :: iterator I ) { if ( ! ( MF . getTarget ( ) . getMCAsmInfo ( ) -> usesCFIForEH ( ) && MF . getTarget ( ) . getMCAsmInfo ( ) -> usesPIC ( ) ) ) return ; if ( I -> getOpcode ( ) == NVPTX :: PROLOG_LABEL ) { I -> eraseFromParent ( ) ; if ( next ( I ) -> getOpcode ( ) == NVPTX :: CALLSEQ_START ) { next ( I ) -> eraseFromParent ( ) ; } } else if ( I -> getOpcode ( ) == NVPTX :: RETI ) { I -> eraseFromParent ( ) ; if ( prev ( I ) -> getOpcode ( ) == NVPTX :: CALLSEQ_END ) { prev ( I ) -> eraseFromParent ( ) ; } } }


bool emitPrologue ( LLVM :: Function func , LLVM :: Module mod ) { if ( LLVM :: TargetRegistry :: lookupTarget ( "nvptx" , mod . getTargetTriple ( ) , Error ) != nullptr ) { return true ; } return false ; }


void EmitPrologue ( Function * F , MachineFunction & MF ) { MachineBasicBlock & MBB = MF . front ( ) ; MachineBasicBlock :: iterator MI = MBB . begin ( ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: cvta_local_yes_64 ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: cvta_local_yes ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: MOV_DEPOT_ADDR_64 ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: MOV_DEPOT_ADDR ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: VRFrame ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: VRFrame ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: VRFrameLocal ) ) ; BuildMI ( MBB , MI , DebugLoc ( ) , TII -> get ( NVPTX :: VRFrameLocal ) ) ; int64_t StackSize = MF . getInfo < NVPTXMachineFunctionInfo > ( ) -> getStackSize ( ) / 4 ; MF . getFrameInfo ( ) -> IncreaseStackSize ( StackSize ) ; int NumLocals = MF . getInfo < NVPTXMachineFunctionInfo > ( ) -> getNumLocalVariables ( ) ; for ( Function :: arg_iterator I = F -> arg_begin ( ) , E = F -> arg_end ( ) ; I != E ; ++ I ) { if ( ! NVPTXParamManager :: UseSSA ) { if ( NVPTXParamManager :: isLocalParam ( I ) ) ++ NumLocals ; } if ( I -> hasAttribute ( Attribute :: ByVal ) ) { const AttributeByVal * ByVal = I -> getAttribute ( Attribute :: ByVal ) ; NumLocals += ByVal -> getArraySize ( ) ; } }


int FI ) { DebugLoc DL ; const TargetInstrInfo * TII = MF . getSubtarget ( ) . getInstrInfo ( ) ; const NVPTXSubtarget & ST = MF . getSubtarget < NVPTXSubtarget > ( ) ; const TargetFrameLowering * TFI = ST . getFrameLowering ( ) ; const MachineFrameInfo & MFI = MF . getFrameInfo ( ) ; int64_t Offset = MFI . getStackSize ( ) + TFI -> getFrameIndexReference ( MF , FI ) ; Register BaseReg = NVPTX :: VRDepot ; if ( ST . isComputeABI ( ) && Offset > 0 ) { BaseReg = NVPTX :: VRFrame ; Offset += StackOffset ; } return std :: make_pair ( BaseReg , Offset ) ; }


void
NVPTXAsmPrinter
::
emitPrologue
(
)
{
const
TargetSubtargetInfo
&
STI
=
MF
->
getSubtarget
(
)
;
unsigned
FuncInfoSize
=
STI
.
getFrameLowering
(
)
->
getFrameInfoSize
(
MF
)
;
const
MachineFunction
&
MF
=
getMachineFunction
(
)
;
const
Function
&
F
=
MF
.
getFunction
(
)
;
MachineFrameInfo
&
MFI
=
MF
.
getFrameInfo
(
)
;
const
TargetRegisterInfo
*
TRI
=
STI
.
getRegisterInfo
(
)
;
DebugLoc
DL
=
F
.
getEntryBlock
(
)
.
begin
(
)
->
getDebugLoc
(
)
;
MachineBasicBlock
&
MBB
=
MF
.
front
(
)
;
MachineBasicBlock
::
iterator
MBBI
=
MBB
.
begin
(
)
;
for
(
unsigned
i
=
0
;
i
<
NVPTX
::
Int64RegsRegClass
.
getNumRegs
(
)
3
;
i
++
)
{
RegSpillMap
[
NVPTX
::
Int64RegsRegClass
.
getRegister
(
i
)
]
=
0
;
}
if
(
STM
->
getFunctionInfo
(
)
->
isShrinkWrappingDisabled
(
)
)
{
EmitVisibilityDirective
(
NVPTX
::
etext
,
".error"
,
'"'
,
"Shrink-wrapping not yet supported"
,
'"'
)
;
}


void emitPrologue ( IRBuilder < > & Builder ) { Value * cvta_local_yes_64 = Builder . CreateAlloca ( NVPTX ) ; Value * VRFrame = Builder . CreateAlloca ( NVPTX ) ; Value * VRFrameLocal = Builder . CreateAlloca ( NVPTX ) ; Builder . CreateStore ( NVPTX :: IMOV64rr , VRFrameLocal ) ; Builder . CreateStore ( NVPTX :: VRFrameLocal , VRFrameLocal ) ; Value * VRDepot = Builder . CreateAlloca ( NVPTX ) ; Builder . CreateStore ( NVPTX :: IMOV32rr , VRFrameLocal ) ; Builder . CreateStore ( NVPTX :: VRFrameLocal , VRFrameLocal ) ; Builder . CreateStore ( NVPTX :: IMOV64rr , VRFrame ) ; Builder . CreateStore ( VRFrameLocal , VRDepot ) ; Builder . CreateStore ( NVPTX :: IMOV32rr , VRFrame ) ; Builder . CreateStore ( VRFrameLocal , VRDepot ) ; Builder . CreateStore ( NVPTX :: IMOV64rr , VRFrame ) ; Builder . CreateStore ( VRDepot , VRFrame ) ; Builder . CreateStore ( NVPTX :: IMOV32rr , VRFrame ) ; Builder . CreateStore ( VRDepot , VRFrame ) ; Builder . CreateStore ( NVPTX :: cvta_local_yes , cvta_local_yes_64 ) ; }


void emitEpilogue ( IRBuilder < > & builder , Function & F , Value * NVPTX ) { Instruction * currentInsertPt = builder . GetInsertPoint ( ) ; BasicBlock * epilogueBlock = BasicBlock :: Create ( builder . GetInsertBlock ( ) , "epilogue" , & F ) ; builder . SetInsertPoint ( epilogueBlock ) ; builder . SetInsertPoint ( currentInsertPt ) ; epilogueBlock -> appendToEnd ( & F ) ; }


void emitPrologue ( Function * F ) { Module * M = F -> getParent ( ) ; const TargetLowering * TLI = M -> getSubtarget ( ) . getTargetTriple ( ) ; const NVPTXTargetLowering * NVPTXTLI = static_cast < const NVPTXTargetLowering * > ( TLI ) ; BasicBlock * Entry = & F -> getEntryBlock ( ) ; for ( Function :: arg_iterator AI = F -> arg_begin ( ) , AE = F -> arg_end ( ) ; AI != AE ; ++ AI ) { Value * Arg = AI ; Value * VRFrameLocal = Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitVRFrameLocalEntry ( Arg ) ) ; Value * VRDepot = Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitVRDepotEntry ( Arg ) ) ; Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitIMOV64rr ( VRFrameLocal , VRDepot ) ) ; Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitIMOV32rr ( VRFrameLocal , VRDepot ) ) ; } Value * VRFrame = Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitVRFrameEntry ( ) ) ; Value * VRDepot = Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitVRDepotepilog ( ) ) ; Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitIMOV64rr ( VRFrame , VRDepot ) ) ; Entry -> getFirstInsertionPt ( ) -> insertBefore ( NVPTXTLI -> EmitIMOV32rr ( VRFrame , VRDepot ) ) ; }


bool eliminateCallFramePseudoInstr ( MachineFunction & MF , MachineBasicBlock & MBB , MachineBasicBlock :: iterator MI ) { if ( ! MF . getTarget ( ) . useCallFrameSetupDestroy ( ) ) return false ; const NVPTXSubtarget & Subtarget = MF . getSubtarget < NVPTXSubtarget > ( ) ; unsigned RegSize = Subtarget . getRegisterInfo ( ) -> getStackSize ( ) ; if ( ! MI -> isCallFrameSetup ( ) && ! MI -> isCallFrameDestroy ( ) ) return false ; if ( MI -> isCallFrameSetup ( ) ) BuildMI ( MBB , MI , MI -> getDebugLoc ( ) , TII -> get ( NVPTX :: MOVSP ) , NVPTX :: SP ) . addImm ( - RegSize ) ; MI -> eraseFromParent ( ) ; return true ; }


Function emitPrologue ( NVPTX , NVPTX , NVPTX :: Int64RegsRegClass , NVPTX :: cvta_local_yes_64 , NVPTX :: VRFrame , NVPTX :: MOV_DEPOT_ADDR_64 , NVPTX :: Int32RegsRegClass , NVPTX :: cvta_local_yes , NVPTX :: VRFrame , NVPTX :: MOV_DEPOT_ADDR ) { NVPTX_emitPrologue ( NVPTX , NVPTX , NVPTX :: Int64RegsRegClass , NVPTX :: cvta_local_yes_64 , NVPTX :: VRFrame , NVPTX :: MOV_DEPOT_ADDR_64 , NVPTX :: Int32RegsRegClass , NVPTX :: cvta_local_yes , NVPTX :: VRFrame , NVPTX :: MOV_DEPOT_ADDR ) ; }


int & Offset ) const { const MachineFrameInfo & MFI = MF . getFrameInfo ( ) ; Offset = MFI . getObjectOffset ( FrameIndex ) ; BaseReg = NVPTX :: VRDepot ; Offset += MFI . getStackSize ( ) ; }


void getAnalysisUsage ( AnalysisUsage & AU ) const { } Subclasses that override this function should call the base class implementation as follows : FunctionPass :: getAnalysisUsage ( AU ) ; This will ensure that any default analysis passes required by NVPTX backend are included . Next , the function should call the addRequiredPass function for each analysis pass that is required by the backend . This is done by passing in a pointer to the analysis pass as the first argument , and a boolean value indicating whether the pass should be preserved during optimization as the second argument . For example , to add the AnalysisPass1 required by NVPTX backend , the following code should be used : AU . addRequired < AnalysisPass1 > ( true ) ; Similarly , to add the AnalysisPass2 required by NVPTX backend , the following code should be used : AU . addRequired < AnalysisPass2 > ( true ) ; This ensures that the analysis passes are properly configured and made available to the backend during compilation . Finally , the function should also call the setPreservesAll function to indicate that the NVPTX backend does not invalidate any analysis results . This is done as follows : AU . setPreservesAll ( ) ; This completes the implementation of the getAnalysisUsage function for NVPTX backend of LLVM Compiler . The complete code is shown below : void getAnalysisUsage ( AnalysisUsage & AU ) const { FunctionPass :: getAnalysisUsage ( AU ) ; AU . addRequired < AnalysisPass1 > ( true ) ; AU . addRequired < AnalysisPass2 > ( true ) ; AU . setPreservesAll ( ) ; }


"Target specific value for NVPTX backend: Expected it to be empty by now\n"


void NVPTXTargetMachine :: getAnalysisUsage ( AnalysisUsage & AU ) const { NVPTXTargetMachine :: Parent :: getAnalysisUsage ( AU ) ; AU . addRequired < NVPTXAnalysis > ( ) ; AU . addRequired < LibNVPTXAnalysis > ( ) ; AU . addPreserved < NVPTXTargetMachine > ( ) ; AU . addPreserved < NVPTXTargetData > ( ) ; }


bool runOnFunction ( llvm :: Function * F ) { }


bool runOnFunction ( Function & F ) { Module * M = F . getParent ( ) ; LLVMContext & Context = M -> getContext ( ) ; bool Modified = false ; for ( BasicBlock & BB : F ) { for ( Instruction & I : BB ) { if ( auto * CI = dyn_cast < CallInst > ( & I ) ) { Function * Callee = CI -> getCalledFunction ( ) ; if ( Callee -> getIntrinsicID ( ) == Intrinsic :: nvvm_istypep_sampler || Callee -> getIntrinsicID ( ) == Intrinsic :: nvvm_istypep_surface || Callee -> getIntrinsicID ( ) == Intrinsic :: nvvm_istypep_texture ) { Modified = true ; } } } } return Modified ; }


bool runOnFunction ( Function & F ) override { LLVMContext & Context = F . getContext ( ) ; auto * TM = getAnalysisIfAvailable < TargetMachine > ( ) ; if ( F . getCallingConv ( ) == CallingConv :: NVPTXKernel ) { NVVMIntrinsics * NVVM = getAnalysisIfAvailable < NVVMIntrinsics > ( ) ; for ( auto & I : instructions ( F ) ) { if ( auto * CI = dyn_cast < CallInst > ( & I ) ) { Function * callee = CI -> getCalledFunction ( ) ; if ( callee && NVVM && NVVM -> getIntrinsicID ( callee ) != Intrinsic :: not_intrinsic ) { Intrinsic :: ID ID = NVVM -> getIntrinsicID ( callee ) ; if ( ID == Intrinsic :: nvvm_istypep_sampler || ID == Intrinsic :: nvvm_istypep_surface || ID == Intrinsic :: nvvm_istypep_texture ) { CI -> addOperand ( ConstantInt :: get ( Type :: getInt32Ty ( Context ) , 0 ) ) ; CI -> setIsTargetSpecific ( ) ; } } } } } return false ; }


Function
*
runOnFunction
(
Function
&
F
)
{
if
(
F
.
getTarget
(
)
!=
NVPTX
)
{
llvm_unreachable
(
"Invalid target!"
)
;
}
Value
*
NVPTXTargetVal
=
F
.
getTarget
(
)
->
getNVPTXTargetValue
(
)
;
return
&
F
;
}


void
printInst
(
const
MCInst
&
Inst
,
raw_ostream
&
OS
,
StringRef
NVPTX
)
{
const
MCInstrDesc
&
Desc
=
MII
.
get
(
Inst
.
getOpcode
(
)
)
;
uint64_t
Addr
=
Inst
.
getLoc
(
)
.
getAddress
(
)
;
uint16_t
Enc
=
Desc
.
OpInfo
[
0
]
.
RegClass
;
const
Module
*
M
=
MF
->
getModule
(
)
;
OS
<<
M
->
getTarget
(
)
->
getName
(
)
<<
"\t"
<<
getInstName
(
Inst
)
<<
" "
;
unsigned
NumOpInfos
=
MII
.
getNumOpInfos
(
Inst
)
;
for
(
unsigned
i
=
0
;
i
!=
NumOpInfos
;
++
i
)
{
const
MCOperand
&
Op
=
Inst
.
getOperand
(
i
)
;
if
(
Op
.
isValid
(
)
)
{
if
(
i
!=
0
)
OS
<<
", "
;
printOp
(
Op
,
OS
,
&
Desc
)
;
}
}
OS
<<
"\n"
;
}


void
printRegName
(
unsigned
int
reg
)
{
switch
(
reg
)
{
case
0
:
printf
(
"%p"
,
reg
)
;
break
;
case
1
:
printf
(
"%rs"
,
reg
)
;
break
;
case
2
:
printf
(
"%r"
,
reg
)
;
break
;
case
3
:
printf
(
"%rd"
,
reg
)
;
break
;
case
4
:
printf
(
"%f"
,
reg
)
;
break
;
case
5
:
printf
(
"%fd"
,
reg
)
;
break
;
case
6
:
printf
(
"%h"
,
reg
)
;
break
;
case
7
:
printf
(
"%hh"
,
reg
)
;
break
;
default
:
printf
(
"Bad virtual register encoding"
)
;
}
}


void printInst ( const MCInst * MI , raw_ostream & OS , StringRef NVPTX = "NVPTX" ) { MI -> print ( OS , NVPTX ) ; }


void
printRegName
(
uint8_t
Reg
)
{
switch
(
Reg
)
{
case
0
:
printf
(
"%p"
)
;
break
;
case
1
:
printf
(
"%rs"
)
;
break
;
case
2
:
printf
(
"%r"
)
;
break
;
case
3
:
printf
(
"%rd"
)
;
break
;
case
4
:
printf
(
"%f"
)
;
break
;
case
5
:
printf
(
"%fd"
)
;
break
;
case
6
:
printf
(
"%f"
)
;
break
;
default
:
printf
(
"Bad virtual register encoding"
)
;
break
;
}
}


const
MCRegisterInfo
*
MRI
)
{
uint64_t
Opcode
=
MI
->
getOpcode
(
)
;
StringRef
Name
=
MII
->
getName
(
Opcode
)
;
OS
<<
format
(
"0x%04"
PRIx64
":  "
,
Address
)
<<
Name
;
if
(
IsMalformed
)
{
OS
<<
"    <malformed>\n"
;
return
;
}


void
printRegName
(
int
regNum
)
{
switch
(
regNum
)
{
case
0
:
printf
(
"%p"
)
;
break
;
case
1
:
printf
(
"%rs"
)
;
break
;
case
2
:
printf
(
"%r"
)
;
break
;
case
3
:
printf
(
"%rl"
)
;
break
;
case
4
:
printf
(
"%f"
)
;
break
;
case
5
:
printf
(
"%fl"
)
;
break
;
case
6
:
printf
(
"%0X"
,
0x0FFFFFFF
)
;
break
;
default
:
printf
(
"Bad virtual register encoding"
)
;
}
}


"insertBranch expects non-empty basic block"

"insertBranch must not be told to insert a fallthrough"

"NVPTX branch conditions have two components!"


void removeBranch ( MachineBasicBlock & MBB ) { MachineInstr * LastInst = MBB . getLastNonDebugInstr ( ) ; if ( LastInst && LastInst -> isBranch ( ) ) { unsigned NumOps = LastInst -> getNumOperands ( ) ; if ( NumOps >= 4 && LastInst -> getOperand ( 0 ) . isImm ( ) && LastInst -> getOperand ( 0 ) . getImm ( ) == ( unsigned int ) NVPTX :: GOTO && LastInst -> getOperand ( 1 ) . isImm ( ) && LastInst -> getOperand ( 1 ) . getImm ( ) == ( unsigned int ) NVPTX :: CBranch && LastInst -> getOperand ( 2 ) . isImm ( ) && LastInst -> getOperand ( 2 ) . getImm ( ) == 0 && LastInst -> getOperand ( 3 ) . isImm ( ) && LastInst -> getOperand ( 3 ) . getImm ( ) == 1 ) { MBB . erase ( LastInst ) ; } } }


"Attempted to create cross-class register copy"


"NVPTX DAG->DAG Pattern Instruction Selection"


"More than one CUDA Reg Ballard Affects Stack"


MachineSDNode
*
Select
(
MachineSDNode
*
N
)
{
switch
(
N
->
getOpcode
(
)
)
{
default
:
llvm_unreachable
(
"unexpected node type"
)
;
case
ISD
::
LOAD
:
{
EVT
DataVT
=
N
->
getValueType
(
0
)
;
switch
(
DataVT
.
getSimpleVT
(
)
.
SimpleTy
)
{
case
MVT
::
i32
:
return
SelectLoadV4
(
N
)
;
case
MVT
::
i64
:
return
SelectLoadV8
(
N
)
;
case
MVT
::
f32
:
return
SelectLoadV2
(
N
)
;
case
MVT
::
f64
:
return
SelectLoadV4
(
N
)
;
default
:
llvm_unreachable
(
"unexpected DataVT for Load node"
)
;
}
}
case
ISD
::
STORE
:
{
EVT
DataVT
=
N
->
getValueType
(
0
)
;
MachineSDNode
*
Chain
=
N
->
getOperand
(
1
)
.
getNode
(
)
;
switch
(
DataVT
.
getSimpleVT
(
)
.
SimpleTy
)
{
case
MVT
::
i32
:
return
SelectStoreV4
(
N
,
Chain
)
;
case
MVT
::
i64
:
return
SelectStoreV8
(
N
,
Chain
)
;
case
MVT
::
f32
:
return
SelectStoreV2
(
N
,
Chain
)
;
case
MVT
::
f64
:
return
SelectStoreV4
(
N
,
Chain
)
;
default
:
llvm_unreachable
(
"unexpected DataVT for Store node"
)
;
}
}


SDValue SelectInlineAsmMemoryOperand ( SDValue Address , const ConstraintInfo * Constraint , SelectionDAG & DAG ) { SDVTList VTs = DAG . getVTList ( MVT :: Other , MVT :: Glue ) ; SDValue TargetAddr = GetTargetAddress ( Address , Constraint -> getTargetFlags ( ) , DAG ) ; SDValue Ops [ ] = { TargetAddr } ; SDNode * ResNode = DAG . getMachineNode ( NVPTX :: NVPTX , DL , VTs , Ops ) ; return SDValue ( ResNode , 0 ) ; }


Instruction * InsertBefore ) { if ( AM -> getTargetMemoryAddress ( ) != NVPTX_ADDR_MODE_TARGET ) return nullptr ; std :: string Constraint = AM -> getAsString ( ) ; if ( Constraint . substr ( 0 , 5 ) != "NVPTX" ) return nullptr ; StringRef AMConstraint = Constraint . substr ( 6 ) ; StringRef MVTString = AMConstraint . substr ( 0 , AMConstraint . find_first_of ( ',' ) ) ; AMConstraint = AMConstraint . substr ( AMConstraint . find_first_of ( ',' ) + 1 ) ; uint64_t Size = AMConstraint . empty ( ) ? Ty -> getPrimitiveSizeInBits ( ) : AMConstraint . getAsInteger ( 0 , 10 ) ; if ( MVTString != "i32" ) return nullptr ; if ( Size != 32 ) return nullptr ; NVPTXAddressSpace AddrSpace = NVPTX :: NVPTX_GENERIC ; return CreateNVPTXGenericAddrMode ( AddrSpace , Base , Index , Disp , InsertBefore ) ; }


void Select ( Node * N ) { if ( N -> getOpcode ( ) == ISD :: LOAD ) { TargetMachine * TM = N -> getTargetMachine ( ) ; unsigned NVPTX = TM -> getTargetID ( ) ; unsigned LOAD = ISD :: LOAD ; MachineNode * M = new MachineNode ( NVPTX , LOAD ) ; N -> transformTo ( M ) ; } else if ( N -> getOpcode ( ) == ISD :: STORE ) { TargetMachine * TM = N -> getTargetMachine ( ) ; unsigned NVPTX = TM -> getTargetID ( ) ; unsigned STORE = ISD :: STORE ; MachineNode * M = new MachineNode ( NVPTX , STORE ) ; N -> transformTo ( M ) ; } else { return ; } }


static SDNode * Select ( SDNode * N ) { EVT VT = N -> getValueType ( 0 ) ; SDLoc DL ( N ) ; unsigned Opc = N -> getOpcode ( ) ; switch ( Opc ) { case ISD :: LOAD : if ( VT == MVT :: v2i32 || VT == MVT :: v2f32 ) { return DAG . getMachineNode ( NVPTX :: LoadV2 , DL , VT , N -> getOperand ( 0 ) ) ; } else if ( VT == MVT :: v4i32 || VT == MVT :: v4f32 ) { return DAG . getMachineNode ( NVPTX :: LoadV4 , DL , VT , N -> getOperand ( 0 ) ) ; } break ; case ISD :: STORE : if ( VT == MVT :: v2i32 || VT == MVT :: v2f32 ) { return DAG . getMachineNode ( NVPTX :: StoreV2 , DL , VT , N -> getOperand ( 0 ) , N -> getOperand ( 1 ) ) ; } else if ( VT == MVT :: v4i32 || VT == MVT :: v4f32 ) { return DAG . getMachineNode ( NVPTX :: StoreV4 , DL , VT , N -> getOperand ( 0 ) , N -> getOperand ( 1 ) ) ; } break ; default : return SelectCode ( N ) ; } return nullptr ; }


bool SelectInlineAsmMemoryOperand ( Instruction * I , const std :: string & Constraint , SelectionDAG & DAG ) { if ( Constraint . find ( "T" ) == std :: string :: npos ) return false ; if ( Constraint . getValueType ( ) != MVT :: i32 ) return false ; SDValue Addr = DAG . getTargetConstant ( Constraint . getValueType ( ) , SDLoc ( I ) , MVT :: i32 ) ; Addr = DAG . getNode ( NVPTXISD :: ADDRESS , SDLoc ( I ) , MVT :: i32 , DAG . getRegister ( , MVT :: i32 ) , Addr ) ; MachineSDNode * SDM = cast < MachineSDNode > ( I ) ; SDM -> setMemRefs ( DAG . getMachineFunction ( ) , MachineMemOperand :: MOStore , DAG . getMachineNode ( Addr , SDLoc ( I ) ) ) ; return true ; }


MVT :: ValueType getPreferredVectorAction ( const TargetLowering * TLI , EVT VT , EVT MemVT ) { if ( TLI -> getTargetMachine ( ) . getTargetTriple ( ) . getArch ( ) == llvm :: Triple :: nvptx || TLI -> getTargetMachine ( ) . getTargetTriple ( ) . getArch ( ) == llvm :: Triple :: nvptx64 ) { if ( VT . isSimple ( ) && VT . getSimpleVT ( ) . SimpleTy == MVT :: i1 && MemVT . isSimple ( ) && MemVT . getSimpleVT ( ) . SimpleTy == MVT :: v2f16 ) return MVT :: v2i32 ; } return MVT :: v8i32 ; }


llvm :: FunctionType * FT = llvm :: FunctionType :: get ( builder -> getFloatTy ( ) , { builder -> getInt32Ty ( ) } , false ) ; llvm :: Function * Func = llvm :: Function :: Create ( FT , llvm :: Function :: PrivateLinkage , "getSqrtEstimate" , builder -> GetInsertBlock ( ) -> getModule ( ) ) ; 3. Create an llvm :: BasicBlock * named entryBB inside the getSqrtEstimate function , using builder object : llvm :: BasicBlock * entryBB = llvm :: BasicBlock :: Create ( Context , "entry" , Func ) ; builder -> SetInsertPoint ( entryBB ) ; 4. Create a switch case statement for NVPTX backend using llvm :: Intrinsic ID : switch ( ID ) { case Intrinsic :: nvvm_rsqrt_approx_ftz_f : case Intrinsic :: nvvm_rsqrt_approx_f : case Intrinsic :: nvvm_rsqrt_approx_d : case Intrinsic :: nvvm_sqrt_approx_ftz_f : case Intrinsic :: nvvm_sqrt_approx_f : case Intrinsic :: nvvm_rcp_approx_ftz_d : }


enum PreferredLegStrategy { NONE , CUSTOM_STRATEGY , CONSTRAINTED_FP , VEC_ROUNDING , SPILLED_NODE , } ; PreferredLegStrategy getPreferredVectorAction ( StringRef TargetName , const CallConvLowering * CD , SelectionDAGISel & SI , MVT :: SimpleValueType NVT , MVT :: SimpleValueType OVT ) { if ( TargetName == "NVPTX" && NVT == MVT :: i1 && OVT == MVT :: v2f16 ) { return PreferredLegStrategy :: CUSTOM_STRATEGY ; } return PreferredLegStrategy :: NONE ; }


bool isLegalAddressingMode ( const DataLayout & DL , const AddrMode & AM , Type * Ty ) { unsigned int AddrSpace = AM . AddrSpace ; unsigned int BaseType = AM . BaseType ; int64_t BaseOff = AM . BaseOff ; unsigned int Scale = AM . Scale ; unsigned int Reg = AM . HasBaseReg ? AM . Base . Reg : 0 ; if ( AddrSpace != NVPTX || BaseType != NVPTX || BaseType != 0 || BaseType != 1 ) { return false ; } if ( BaseOff < 0 || Scale < 0 || Reg < 0 ) { return false ; } if ( ! DL . isLegalInteger ( Ty ) ) { return false ; } if ( Scale == 0 && Reg == 0 ) { return false ; } return true ; }


Function * NVPTXTargetLowering :: LowerOperation ( const Operation & Op , Module * M ) { unsigned Opc = Op . getOpcode ( ) ; switch ( Opc ) { case NVPTX : { break ; } case ISD :: RETURNADDR : { break ; } case ISD :: FRAMEADDR : { break ; } case ISD :: GlobalAddress : { break ; } case ISD :: INTRINSIC_W_CHAIN : { break ; } case ISD :: BUILD_VECTOR : { break ; } case ISD :: EXTRACT_SUBVECTOR : { break ; }


String getConstraintType ( char constraint ) { switch ( constraint ) { case 'c' : case 'r' : case 'd' : return "NVPTX" ; case 'm' : return "NVPTX" ; case '1' : return "1" ; case '0' : return "0" ; default : return "Unknown" ; } }


MVT :: SimpleValueType getPreferredVectorAction ( MVT :: SimpleValueType VT , const TargetLowering & TLI , EVT VecVT , MVT :: SimpleValueType PreferVT , bool TypeLegal ) { if ( TypeLegal ) { return PreferVT ; } if ( VecVT == MVT :: nxv1i1 && PreferVT == MVT :: i1 ) { return MVT :: i32 ; } return PreferVT ; }


"Unknown instruction for isLegalAddressingMode"


"Custom lowering not defined for operation"


if ( N -> getOpcode ( ) == NVPTX && ( N -> getOpcode ( ) == ISD :: ADD || N -> getOpcode ( ) == ISD :: FADD || N -> getOpcode ( ) == ISD :: MUL || N -> getOpcode ( ) == ISD :: SHL || N -> getOpcode ( ) == ISD :: AND || N -> getOpcode ( ) == ISD :: SELECT ) ) { Now , we use the DAGCombineInfo object to change the type of the target node to the desired target - specific type : DCI . CombineTo ( N , some_value ) ; Finally , we return the updated node : return SDValue ( N , 0 ) ; }


void ReplaceNodeResults ( SDNode * Node , SmallVectorImpl < SDValue > & Results , SelectionDAG & DAG ) { if ( ! DAG . getTargetLoweringInfo ( ) . isTypeLegal ( Node -> getValueType ( 0 ) ) ) { EVT VT = Node -> getValueType ( 0 ) ; unsigned OpCode = Node -> getOpcode ( ) ; const SDValue * Operands = Node -> op_begin ( ) ; unsigned NumOperands = Node -> getNumOperands ( ) ; switch ( VT . getSimpleVT ( ) . SimpleTy ) { case MVT :: Other : { if ( OpCode == ISD :: LOAD ) { EVT MemVT = VT . getVectorElementType ( ) ; SDValue LoadAddr = Operands [ 1 ] ; SDValue LoadChain = Operands [ 2 ] ; SDValue LoadOffset = Operands [ 3 ] ; SDValue NewLoad = DAG . getNode ( ISD :: Custom , SDLoc ( Node ) , VT , LoadChain , LoadAddr , LoadOffset ) ; Results . push_back ( NewLoad ) ; } break ; }


MVT :: SimpleValueType getSetCCResultType ( EVT VT ) const { if ( VT == MVT :: Other ) return MVT :: Other ; if ( VT . isVector ( ) ) return MVT :: getVectorVT ( MVT :: i1 , VT . getVectorNumElements ( ) ) ; return MVT :: i1 ; }


MVT :: SimpleValueType getShiftAmountTy ( ) { return MVT :: i32 ; }


inline unsigned NVPTXTargetLowering :: getConstraintType ( const char * Constraint ) const { switch ( Constraint [ 0 ] ) { case 'c' : if ( Constraint [ 1 ] == '\0' ) return Imm ; if ( Constraint [ 1 ] == 'c' && ( Constraint [ 2 ] == '0' || Constraint [ 2 ] == '1' ) ) return CIn ; break ; case 'r' : return RegClass ; case 'l' : return RegList ; case 'g' : if ( Constraint [ 1 ] == '\0' ) return AnyMem ; if ( Constraint [ 1 ] == 't' ) return GlobalMem ; break ; } return 0 ; }


if ( isMemIntrinsic == true ) { } else { }


if ( MI -> getConstraintString ( OpNo ) == "NVPTX" || MI -> getConstraintString ( OpNo ) == "NVPTX,NVPTX,1" ) { Ops . addReg ( MI -> getOperand ( OpNo ) . getReg ( ) , getRegClassForOperand ( OpNo , MI , TM , MRI ) ) ; }


LLVMValueRef LowerOperation ( LLVMModuleRef moduleRef , LLVMBasicBlockRef basicBlockRef , LLVMValueRef valueRef , LLVMBuilderRef builderRef , LLVMTargetMachineRef targetMachineRef ) { unsigned opcode = LLVMGetInstructionOpcode ( valueRef ) ; if ( opcode == ISD :: RETURNADDR ) { LLVMValueRef returnAddress = LLVMBuildCall ( builderRef , LLVMNVPTXIntrinsicRetAddr ( targetMachineRef ) , & valueRef , 1 , "" ) ; return returnAddress ; } if ( opcode == ISD :: FRAMEADDR ) { LLVMValueRef frameAddress = LLVMBuildCall ( builderRef , LLVMNVPTXIntrinsicFrameAddr ( targetMachineRef ) , & valueRef , 1 , "" ) ; return frameAddress ; } if ( opcode == ISD :: GlobalAddress ) { LLVMValueRef globalAddress = LLVMBuildCall ( builderRef , LLVMNVPTXIntrinsicAddressOf ( targetMachineRef ) , & valueRef , 1 , "" ) ; return globalAddress ; } if ( opcode == ISD :: INTRINSIC_W_CHAIN ) { unsigned intrinsicID = LLVMGetIntrinsicID ( valueRef ) ; if ( intrinsicID == Intrinsic :: nvvm_build_vector ) { LLVMValueRef loadInst = LLVMBuildLoad ( builderRef , valueRef , "" ) ; return loadInst ; } } if ( opcode == ISD :: BUILD_VECTOR ) { LLVMValueRef loadInst = LLVMBuildLoad ( builderRef , valueRef , "" ) ; return loadInst ; } if ( opcode == ISD :: EXTRACT_SUBVECTOR ) { LLVMValueRef loadInst = LLVMBuildLoad ( builderRef , valueRef , "" ) ; return loadInst ; }


"NVPTX backend does not support device/host calling conventions"


MVT :: LegalizeAction LowerVectorLoadStoreAction ( TargetLowering :: LegalizeAction Action , MVT :: SimpleValueType VT ) { if ( VT != MVT :: v2f16 ) return Action ; if ( ( Action == TargetLowering :: Custom ) || ( Action == TargetLowering :: Legal ) || ( Action == TargetLowering :: Promote ) ) { return TargetLowering :: Legal ; } else { return TargetLowering :: Custom ; } } void getPreferredVectorAction ( const TargetLowering :: LegalizeVectorTypesInfo & LegalizeInfo , MVT :: SimpleValueType VT , MVT & PreferredTypeVT ) { PreferredTypeVT = MVT :: v2f16 ; if ( LegalizeInfo . ElementVT == MVT :: i1 ) { PreferredTypeVT = MVT :: v2i1 ; } if ( VT != MVT :: v2f16 ) { PreferredTypeVT = VT ; } }


bool isFMAFasterThanFMulAndFAdd ( TargetMachine * TM ) { if ( ! TM ) return false ; Triple TargetTriple = TM -> getTargetTriple ( ) ; if ( ! TargetTriple . isNVPTX ( ) ) return false ; SubtargetFeatures Features ( TargetTriple . getFeatureString ( ) ) ; if ( ! Features . hasFeature ( "nvptx-fma" ) ) return false ; return true ; }


"Constraint = %c, Constraint Type = %s\n"


llvm :: MVT getScalarShiftAmountTy ( ) { return llvm :: MVT :: i32 ; }


MVT getSetCCResultType ( const Target & NVPTX , MVT :: i1 a , MVT :: i1 b ) { return MVT :: i1 ; }


bool isLegalAddressingMode ( const TargetRegisterInfo * TRI , const MCInst * LoadStoreInstr , const MachineOperand & Dest , const MachineOperand & Base , const MachineOperand & Offset ) { uint64_t tsv = LoadStoreInstr -> getOperand ( 0 ) . getImm ( ) ; if ( tsv == 0x000000010000001 ) { bool isDestVectorReg = TRI -> isTypeLegalForClass ( Dest . getReg ( ) , TRI -> getRegClass ( Dest . getReg ( ) ) ) ; bool isBaseVectorReg = TRI -> isTypeLegalForClass ( Base . getReg ( ) , TRI -> getRegClass ( Base . getReg ( ) ) ) ; bool isValidOffset = Offset . isImm ( ) ; bool isOffsetWordAligned = ( Offset . getImm ( ) % 4 == 0 ) ; if ( isDestVectorReg && isBaseVectorReg && isValidOffset && isOffsetWordAligned ) return true ; } return false ; }


bool shouldCastAtomicLoadInIR ( AtomicLoadInst * atomicLoad , const TargetMachine * TM ) { if ( TM -> getTargetTriple ( ) . getArch ( ) != Triple :: nvptx ) return false ; Type * type = atomicLoad -> getType ( ) ; if ( ! type -> isIntegerTy ( ) && ! type -> isFloatingPointTy ( ) ) return false ; unsigned size = type -> getIntegerBitWidth ( ) ; if ( size != 8 && size != 16 && size != 32 && size != 64 ) return false ; if ( atomicLoad -> getPointerOperand ( ) -> getType ( ) -> getPointerAddressSpace ( ) != AMDGPUAS :: LOCAL_ADDRESS ) return false ; Instruction * cast = nullptr ; switch ( size ) { case 8 : cast = AtomicCmpXchgInst :: CreateAcquire ( atomicLoad -> getPointerOperand ( ) , atomicLoad -> getOperand ( 0 ) , atomicLoad -> getOperand ( 1 ) , atomicLoad -> getOrdering ( ) , atomicLoad -> getSynchScope ( ) ) ; break ; case 16 : cast = AtomicRMWInst :: CreateAdd ( atomicLoad -> getPointerOperand ( ) , atomicLoad -> getOperand ( 0 ) , atomicLoad -> getOrdering ( ) , atomicLoad -> getSynchScope ( ) ) ; break ; case 32 : cast = AtomicRMWInst :: CreateSub ( atomicLoad -> getPointerOperand ( ) , atomicLoad -> getOperand ( 0 ) , atomicLoad -> getOrdering ( ) , atomicLoad -> getSynchScope ( ) ) ; break ; case 64 : cast = AtomicRMWInst :: CreateAnd ( atomicLoad -> getPointerOperand ( ) , atomicLoad -> getOperand ( 0 ) , atomicLoad -> getOrdering ( ) , atomicLoad -> getSynchScope ( ) ) ; break ; default : return false ; }


"class RegConstraint {vector<...> physRegs;}"


bool getTgtMemIntrinsic ( unsigned IntrinsicID ) { switch ( IntrinsicID ) { case Intrinsic :: nvvm_atomic_load_add_f32 : case Intrinsic :: nvvm_atomic_load_inc_32 : case Intrinsic :: nvvm_atomic_load_dec_32 : case Intrinsic :: nvvm_ldu_global_i : case Intrinsic :: nvvm_ldu_global_f : case Intrinsic :: nvvm_ldu_global_p : if ( getIntrinsicTarget ( IntrinsicID ) != Triple :: NVPTX ) return false ; if ( IntrinsicID == Intrinsic :: nvvm_ldu_global_i || IntrinsicID == Intrinsic :: nvvm_ldu_global_p ) return true ; return false ; default : return false ; } }


"Custom lowering not defined for operation"


SelectionDAG
&
DAG
)
{
MachineFunction
&
MF
=
DAG
.
getMachineFunction
(
)
;
const
Function
&
F
=
MF
.
getFunction
(
)
;
if
(
MF
.
getTarget
(
)
.
getTargetTriple
(
)
.
getArch
(
)
!=
Triple
::
nvptx
)
return
SDValue
(
)
;
if
(
!
F
.
getFunctionType
(
)
->
isABICompliant
(
)
)
report_fatal_error
(
"Non-ABI compilation is not supported"
)
;
if
(
Outs
.
size
(
)
!=
1
)
report_fatal_error
(
"Bad return value decomposition"
)
;
EVT
RetVT
=
Outs
[
0
]
.
VT
;
if
(
!
RetVT
.
isScalar
(
)
)
report_fatal_error
(
"Invalid vector info"
)
;
unsigned
RetSize
=
RetVT
.
getSizeInBits
(
)
;
MVT
RetMVT
=
RetVT
.
getSimpleVT
(
)
.
SimpleTy
;
if
(
Outs
[
0
]
.
Flags
.
isZExt
(
)
)
{
if
(
Outs
[
0
]
.
Flags
.
isSExt
(
)
)
{
if
(
Outs
[
0
]
.
Flags
.
isAnyExt
(
)
)
{
return
DAG
.
getNode
(
NVPTXISD
::
StoreRetval
,
dl
,
MVT
::
Other
,
Chain
,
DAG
.
getNode
(
ISD
::
ANY_EXTEND
,
dl
,
RetMVT
,
OutVals
[
0
]
)
)
;
}
else
{
return
DAG
.
getNode
(
NVPTXISD
::
StoreRetval
,
dl
,
MVT
::
Other
,
Chain
,
DAG
.
getNode
(
ISD
::
SIGN_EXTEND
,
dl
,
RetMVT
,
OutVals
[
0
]
)
)
;
}
}


MVT getSetCCResultType ( NVPTXTargetMachine & TM , EVT VT ) { if ( VT . isVector ( ) ) { MVT ElemVT = VT . getVectorElementType ( ) ; return MVT :: getVectorVT ( ElemVT , VT . getVectorNumElements ( ) / 2 ) ; } else { return MVT :: i1 ; } }


MVT :: SimpleValueType getScalarShiftAmountTy ( MVT :: SimpleValueType ShiftAmountTy ) { if ( ShiftAmountTy == MVT :: i32 ) { return MVT :: i32 ; } return ShiftAmountTy ; }


getSetCCResultType ( MVT v ) { if v == NVPTX { MVT x = MVT :: getVectorVT ( v ) ; MVT v = MVT :: i1 ; } else { MVT v = x ; } return v ; }


switch ( N -> getOpcode ( ) ) { case NVPTXISD :: ADD : return combineAdd ( N ) ; case NVPTXISD :: FADD : return combineFAdd ( N ) ; case NVPTXISD :: MUL : return combineMul ( N ) ; case NVPTXISD :: SHL : return combineSHL ( N ) ; case NVPTXISD :: AND : return combineAND ( N ) ; default : return DAGCombine ( N ) ; }


SelectionDAG
&
DAG
,
const
TargetLowering
&
TLI
)
{
SDLoc
DL
(
N
)
;
EVT
VT
=
N
->
getValueType
(
0
)
;
if
(
TLI
.
isTypeLegal
(
VT
)
)
return
;
unsigned
CustomOpcode
=
TLI
.
getOperationAction
(
N
->
getOpcode
(
)
,
VT
)
.
Custom
;
if
(
CustomOpcode
==
TargetLowering
::
Legal
)
return
;
if
(
CustomOpcode
==
TargetLowering
::
Custom
)
{
LLVM_DEBUG
(
dbgs
(
)
<<
"Unhandled custom legalization\n"
)
;
return
;
}
if
(
CustomOpcode
==
TargetLowering
::
UseUndeclared
)
CustomOpcode
=
TLI
.
getOperationAction
(
N
->
getOpcode
(
)
,
VT
)
.
Value
;
if
(
CustomOpcode
>=
ISD
::
BUILTIN_OP_END
)
return
Results
.
push_back
(
DAG
.
getNode
(
CustomOpcode
,
DL
,
VT
,
N
->
getOperand
(
0
)
,
N
->
getOperand
(
1
)
)
)
;
if
(
TLI
.
getOperationAction
(
CustomOpcode
,
VT
)
.
IntrinsicName
)
{
MVT
ArgVT
=
VT
.
getSimpleVT
(
)
;
std
::
vector
<
SDValue
>
Ops
;
for
(
unsigned
i
=
0
,
e
=
N
->
getNumOperands
(
)
;
i
<
e
;
++
i
)
{
SDValue
Op
=
N
->
getOperand
(
i
)
;
if
(
!
TLI
.
isTypeLegal
(
Op
.
getValueType
(
)
)
)
Op
=
DAG
.
getNode
(
ISD
::
ANY_EXTEND
,
DL
,
TLI
.
getTypeToExpandTo
(
ArgVT
)
,
Op
)
;
Ops
.
push_back
(
Op
)
;
}


void PerformDAGCombine ( SDNode * N ) { if ( N -> getOpcode ( ) == NVPTXISD :: NVPTXNode || N -> getOpcode ( ) == ISD :: ADD || N -> getOpcode ( ) == ISD :: FADD || N -> getOpcode ( ) == ISD :: MUL || N -> getOpcode ( ) == ISD :: SHL || N -> getOpcode ( ) == ISD :: AND ) { SDValue Op1 = N -> getOperand ( 0 ) ; SDValue Op2 = N -> getOperand ( 1 ) ; if ( Op1 . isConstant ( ) || Op2 . isConstant ( ) ) { ConstantSDNode * Const1 = dyn_cast < ConstantSDNode > ( Op1 ) ; ConstantSDNode * Const2 = dyn_cast < ConstantSDNode > ( Op2 ) ; if ( Const1 && Const2 ) { switch ( N -> getOpcode ( ) ) { case NVPTXISD :: NVPTXNode : { break ; } case ISD :: ADD : { uint64_t Val = Const1 -> getSExtValue ( ) + Const2 -> getSExtValue ( ) ; SDNode * NewNode = CurDAG -> getTargetConstant ( Val , N -> getValueType ( 0 ) ) ; ReplaceNode ( N , NewNode ) ; break ; } case ISD :: FADD : { double Val = Const1 -> getValueAPF ( ) . convertToDouble ( ) + Const2 -> getValueAPF ( ) . convertToDouble ( ) ; SDNode * NewNode = CurDAG -> getTargetConstantFP ( Val , N -> getValueType ( 0 ) ) ; ReplaceNode ( N , NewNode ) ; break ; }


void LowerOperation ( SDNode * N , std :: vector < SDValue > & Results , SelectionDAG & DAG ) { switch ( N -> getOpcode ( ) ) { case ISD :: RETURNADDR : { SDValue Func = N -> getOperand ( 0 ) ; SDValue RetAddr = DAG . getNode ( NVPTXISD :: RETURNADDR , SDLoc ( N ) , Func . getValueType ( ) , Func ) ; Results . push_back ( RetAddr ) ; return ; } case ISD :: FRAMEADDR : { ConstantSDNode * Idx = cast < ConstantSDNode > ( N -> getOperand ( 0 ) ) ; SDValue FrameAddr = DAG . getNode ( NVPTXISD :: FRAMEADDR , SDLoc ( N ) , N -> getValueType ( 0 ) , Idx ) ; Results . push_back ( FrameAddr ) ; return ; } case ISD :: GlobalAddress : { GlobalValue * GV = cast < GlobalAddressSDNode > ( N ) -> getGlobal ( ) ; SDValue Addr = DAG . getTargetGlobalAddress ( GV , SDLoc ( N ) , N -> getValueType ( 0 ) ) ; Results . push_back ( Addr ) ; return ; } default : Results . push_back ( DAG . getTargetConstant ( NVPTX :: CustomLoweringOpNotDefined , SDLoc ( N ) , MVT :: Other ) ) ; return ; } }


int getFunctionParamOptimizedAlign ( string target , int nonLocalLinkage , int defaultAlign ) { if ( target != "NVPTX,NVPTX" ) { return defaultAlign ; } if ( nonLocalLinkage == 1 ) { return 16 ; } else { return defaultAlign ; } }


bool PerformDAGCombine ( MachineBasicBlock & MBB ) { if ( ! MBB . hasNodesWithCodeGen ( ) ) { return false ; }


bool isLegalAddressingMode ( AddressingMode AM , Type type ) { if ( AM . getTgtAddrSpace ( ) != NVPTX || AM . getBaseType ( ) != NVPTX || AM . getScale ( ) != 0 || AM . getStep ( ) != 1 ) return false ; if ( isLoadSupported ( type ) || isStoreSupported ( type ) ) { if ( isLoadStoreSupported ( AM , type ) ) return true ; } return false ; }


"Invalid type! Atomic operation supported only for integer types.\n"

"Unsupported width encountered! Atomic operation supports only 8, 16, 32, or 64 bit integers.\n"


void ReplaceNodeResults ( SDNode * Node , SmallVectorImpl < SDValue > & Results , SelectionDAG & DAG ) { if ( Node -> getOpcode ( ) == ISD :: INTRINSIC_W_CHAIN && Node -> getNumOperands ( ) == 2 && Node -> getOperand ( 0 ) == Node -> getOperand ( 1 ) ) { SDValue Chain = Node -> getOperand ( 0 ) ; SDValue Ptr = Chain . getOperand ( 0 ) ; SDValue Addr = Chain . getOperand ( 1 ) ; if ( Ptr . getOpcode ( ) == ISD :: LOAD ) { EVT LoadType = Ptr . getValueType ( ) ; if ( LoadType != MVT :: i32 && LoadType != MVT :: i64 ) { SDNode * NewNode = DAG . getNode ( NVPTXISD :: LOAD , SDLoc ( Node ) , MVT :: i32 , Addr ) ; Results . push_back ( SDValue ( NewNode , 0 ) ) ; } } } }


"Unsupported calling convention for NVPTX target!"

"VarArgs not supported for NVPTX target!"


StringRef getRegForInlineAsmConstraint ( StringRef PhysRegConstraint ) { ... } The function would take in a string representing the physical register constraint for the NVPTX backend and return a string representing the corresponding LLVM constraint . The implementation for this function would be as follows : String getRegForInlineAsmConstraint ( StringRef PhysRegConstraint ) { String LLVMRegConstraint ; if ( PhysRegConstraint . startswith ( "NVPTX" ) ) { StringRef RegClass = PhysRegConstraint . split ( ',' ) . first ( ) ; if ( RegClass == "NVPTX::Int1RegsRegClass" ) { LLVMRegConstraint = "%noreg" ; } else if ( RegClass == "NVPTX::Int16RegsRegClass" ) { LLVMRegConstraint = "f" ; } else if ( RegClass == "NVPTX::Int32RegsRegClass" ) { LLVMRegConstraint = "=r" ; } else if ( RegClass == "NVPTX::Int64RegsRegClass" ) { LLVMRegConstraint = "=d" ; } else if ( RegClass == "NVPTX::Float32RegsRegClass" ) { LLVMRegConstraint = "=f" ; } else if ( RegClass == "NVPTX::Float64RegsRegClass" ) { LLVMRegConstraint = "=d" ; } } return LLVMRegConstraint ; }


bool isLegalAddressingMode ( AddressingMode AM , Type * Ty ) { if ( AM == llvm :: AddrMode :: Reg ) return true ; if ( Ty -> isVectorTy ( ) ) return false ; if ( ! AM . BaseOffs || ! ( AM . BaseOffs -> getType ( ) -> isIntegerTy ( ) || AM . BaseOffs -> getType ( ) -> isFloatingPointTy ( ) ) ) return false ; if ( AM . Scale >= 0 && ! ( AM . Scale -> getType ( ) -> isIntegerTy ( ) || AM . Scale -> getType ( ) -> isFloatingPointTy ( ) ) ) return false ; if ( AM . Scale != 1 && AM . Scale != 4 ) return false ; return true ; }


The function should return a string representing the LLVM constraint code for that particular register constraint . For example , if the input is "NVPTX::Int32RegsRegClass" , the function should return "{reg}" . The steps to create this function are as follows : 1. First , we need to understand the structure of the input string given to us . It contains multiple arguments separated by commas . Each argument represents a particular aspect of the register constraint . 2. The first argument "NVPTX" represents the target specific value . This can be ignored as it is same for all register constraints in NVPTX backend . 3. The second argument "NVPTX" represents the register class name . This will be the LLVM constraint code we need to return . We can directly return this as it is in the correct format . 4. The third argument "1" represents the register class size in bits . This can also be ignored as it is already specified in the register class name . 5. The remaining arguments are optional and we can use them to specify additional features of the register constraint . In this case , we have four optional arguments - "0U,NVPTX::Int8RegsRegClass" , "0U,NVPTX::Int16RegsRegClass" , "0U,NVPTX::Int32RegsRegClass" , "0U,NVPTX::Int64RegsRegClass" representing the sub - register indices for different register class types . We can use these to create a mapping between the sub - register index and the corresponding LLVM constraint code . 6. Finally , we need to handle the case when the input string does not match any of the known register constraints . We can return an empty string in this case . With these steps in mind , the implementation of the function would look something like this : ` ` ` std :: string getRegForInlineAsmConstraint ( std :: string constraint ) { std :: stringstream ss ( constraint ) ; std :: string token ; std :: vector < std :: string > args ; while ( getline ( ss , token , ',' ) ) { args . push_back ( token ) ; }


bool combineRepeatedFPDivisors ( TargetTransformInfo * TTI , bool FPOrd ) { if ( TTI -> getTargetTriple ( ) . getObjectFormat ( ) != Triple :: NVPTX || TTI -> getTargetTriple ( ) . getArch ( ) != Triple :: NVPTX || TTI -> getTargetPointerWidth ( 0 ) != 32 || ! TTI -> getTargetSpecificInfo ( ) . getFloatDivIsCheap ( ) ) return true ; if ( FPOrd ) return false ; return true ; }


bool enableAggressiveFMAFusion ( NVPTXTargetMachine & TM , EVT VT ) { if ( ! VT . isVector ( ) ) return false ; const NVPTXSubtarget & ST = TM . getSubtarget < NVPTXSubtarget > ( ) ; if ( ! ST . hasFMAF ( ) ) return false ; return true ; }


Type * getScalarShiftAmountTy ( ) { Type * TargetTy = MVT :: i32 ; return TargetTy ; }


MVT
::
SimpleValueType
getSetCCResultType
(
ISD
::
CondCode
CC
,
const
DataLayout
&
Layout
)
{
if
(
Layout
.
getTargetTriple
(
)
.
getArch
(
)
==
Triple
::
nvptx
)
{
switch
(
CC
)
{
case
ISD
::
SETCC
:
return
MVT
::
i1
;
default
:
llvm_unreachable
(
"Unknown comparison condition code!"
)
;
}
}
else
{
return
MVT
::
i1
;
}
}


bool isCheapToSpeculateCtlz ( unsigned int targetSpecific ) { if ( targetSpecific == NVPTX ) { return true ; } else { return false ; } }


bool isFMAFasterThanFMulAndFAdd ( ) { Module * M = currentModule ; const char * Target = "nvptx" ; Triple TargetTriple = Triple ( M -> getTargetTriple ( ) ) ; if ( TargetTriple . isNVPTX ( ) ) { std :: string FMAFasterParam = "fma-faster-than-fmul-and-fadd" ; const StringMap < AttributeSet > & Attrs = M -> getTargetAttributes ( ) ; if ( Attrs . find ( "nvptx" ) != Attrs . end ( ) && Attrs [ "nvptx" ] . hasAttribute ( FMAFasterParam ) ) { std :: string AttrValue = Attrs [ "nvptx" ] . getAttribute ( FMAFasterParam ) . getValueAsString ( ) ; if ( AttrValue == "true" ) { return true ; } } } return false ; }


bool isTruncateFree ( Type * Ty1 , Type * Ty2 ) { if ( target_specific_value != NVPTX , 64 , 32 ) return false ; if ( sizeOf ( Ty1 ) <= sizeOf ( Ty2 ) ) return false ; return true ; }


void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . addRequired < NVPTXTargetMachine > ( ) ; AU . addRequired < TargetTransformInfoWrapperPass > ( ) ; AU . addPreserved < TargetTransformInfoWrapperPass > ( ) ; }


void
runOnFunction
(
Function
&
F
)
override
{
errs
(
)
<<
"Running on Function: "
<<
F
.
getName
(
)
<<
"\n"
;
F
.
addFnAttr
(
"target-cpu"
,
"NVPTX"
)
;
F
.
addFnAttr
(
"target-features"
,
"NVPTX,NVPTX,4,4,0,0,0,0,1"
)
;
F
.
dump
(
)
;
}


"NVPTX Lower Aggregate Copies/Intrinsics into Loops"


's call it "MyNVPTXPass", which overrides the runOnFunction function to perform specific optimizations. ```cpp #include "NVPTX.h" using namespace llvm; struct MyNVPTXPass : public NVPTX {   static char ID;   MyNVPTXPass() : NVPTX() {}   virtual bool runOnFunction(Function &F) {     return true;   }


void runOnFunction ( Function & F ) override { if ( F . getCallingConv ( ) == CallingConv :: PTX_Kernel ) { return ; } TargetMachine & TM = getAnalysis < TargetMachine > ( ) ; const DataLayout & DL = F . getParent ( ) -> getDataLayout ( ) ; Module & M = * F . getParent ( ) ; DebugLoc DL ; FunctionType * FTy = FunctionType :: get ( Type :: getVoidTy ( F . getContext ( ) ) , false ) ; AttributeSet EmptySet ; Function * Helper = Function :: Create ( FTy , GlobalVariable :: ExternalLinkage , "__nvvm_reflect" , & M ) ; Helper -> setAttributes ( EmptySet ) ; BasicBlock * BB = BasicBlock :: Create ( F . getContext ( ) , "prologue" , Helper ) ; IRBuilder < > Builder ( BB ) ; SmallVector < Type * , 16 > Params ; Params . push_back ( Type :: getInt8PtrTy ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt8PtrTy ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt8PtrTy ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Params . push_back ( Type :: getInt32Ty ( F . getContext ( ) ) ) ; Function * Reflect = Intrinsic :: getDeclaration ( & M , Intrinsic :: nvvm_reflect , Params ) ; Value * Params [ 9 ] = { Builder . CreatePointerCast ( Helper , Builder . getInt8PtrTy ( ) ) , Builder . CreatePointerCast ( & F , Builder . getInt8PtrTy ( ) ) , TM . getSubtargetImpl ( ) -> getTargetTriple ( ) . c_str ( ) , Builder . getInt32 ( TM . getRM ( ) ) , Builder . getInt32 ( TM . getOptLevel ( ) ) , Builder . getInt32 ( TM . getOptSize ( ) != CodeGenOpt :: None ) , Builder . getInt32 ( TM . getSoftAlign ( ) != CodeGenOpt :: None ) , Builder . getInt32 ( 0 ) , Builder . getInt32 ( 0 ) } ; Builder . CreateCall ( Reflect , Params ) ; Builder . CreateRetVoid ( ) ; Helper -> addFnAttr ( Attribute :: OptimizeNone ) ; if ( ! F . isDeclaration ( ) ) { BasicBlock * BB = & F . getEntryBlock ( ) ; Instruction * I = & BB -> front ( ) ; Builder . SetInsertPoint ( I ) ; Builder . CreateCall ( Helper , "" ) ; }


"NVPTX - Convert Address Space of Alloca'ed Memory to Local"


StringRef
getPassName
(
)
const
override
{
return
"Convert Address Space Pass"
;
}


bool
runOnFunction
(
Function
&
F
)
override
{
const
std
::
string
targetName
=
"NVPTX"
;
const
std
::
string
targetFeatures
=
"NVPTX"
;
const
std
::
string
targetAttributes
=
""
;
unsigned
int
targetAlignment
=
0
;
unsigned
int
targetSize
=
0
;
outs
(
)
<<
"Function Name: "
<<
F
.
getName
(
)
<<
"\n"
;
outs
(
)
<<
"Target: "
<<
targetName
<<
"\n"
;
outs
(
)
<<
"Target Features: "
<<
targetFeatures
<<
"\n"
;
outs
(
)
<<
"Target Attributes: "
<<
targetAttributes
<<
"\n"
;
outs
(
)
<<
"Target Alignment: "
<<
targetAlignment
<<
"\n"
;
outs
(
)
<<
"Target Size: "
<<
targetSize
<<
"\n"
;
return
true
;
}


function runOnFunction ( function ) { superclass . runOnFunction ( function ) ; NVPTX . processFunction ( function ) ; function . target = "NVPTX" ; function . targetSpecificValue1 = "NVPTX" ; function . targetSpecificValue2 = "" ; function . targetSpecificValue3 = "" ; function . targetSpecificValue4 = 0 ; function . targetSpecificValue5 = 0 ; }


"Lower pointer arguments of CUDA kernels"


bool runOnFunction ( Function & F ) override { return true ; }


bool runOnFunction ( Function & F ) override { if ( ! F . hasFnAttribute ( NVPTX :: PTXF ) ) { return false ; } NVPTXTargetMachine & TM = static_cast < NVPTXTargetMachine & > ( getTM ( F ) ) ; const DataLayout & DL = M . getDataLayout ( ) ; LLVMContext & Context = F . getContext ( ) ; Module & M = * F . getParent ( ) ; if ( TM . getTargetTriple ( ) . getArch ( ) == Triple :: nvptx64 || TM . getTargetTriple ( ) . getArch ( ) == Triple :: nvptx ) { for ( Function :: iterator I = F . begin ( ) , E = F . end ( ) ; I != E ; ++ I ) { BasicBlock & BB = * I ; for ( BasicBlock :: iterator BI = BB . begin ( ) , BE = BB . end ( ) ; BI != BE ; ++ BI ) { Instruction * I = & * BI ; if ( LoadInst * LI = dyn_cast < LoadInst > ( I ) ) { LI -> setVolatile ( true ) ; } } } return true ; }


"Copy structure (byval *) arguments to stack"


bool runOnFunction ( Function & F ) { if ( F . getTargetTriple ( ) != "nvptx" ) { return false ; } NVPTXTargetSpecificValue = F . getTargetSpecificValue ( NVPTX ) ; return true ; }


string
getImageHandleSymbol
(
int
index
)
{
if
(
index
<
0
)
{
return
"Bad index"
;
}
else
{
string
symbol
=
getSymbolFromIndex
(
index
)
;
return
symbol
+
",NVPTX"
;
}
}


int getImageHandleSymbolIndex ( Symbol symbol ) { int targetValue = 0 ; if ( symbol . isNVPTXSpecific ( ) ) { targetValue = 1 ; } return symbol . getIndex ( ) + targetValue ; }


bool shouldOmitSectionDirective ( StringRef SectionName ) { if ( TargetMachine . getTargetTriple ( ) . getArch ( ) != llvm :: Triple :: nvptx ) return false ; if ( SectionName == ".text" || SectionName == ".data" || SectionName == ".bss" ) return true ; return false ; }


's Value class that represent different types of target specific values in the NVPTX backend. The classof method for each subclass would use the LLVM'


const MachineOperand & MO ) const { const MCSection * CurSection = MO . getExpr ( ) -> evaluateAsValue ( MF ) -> findAssociatedSection ( ) ; if ( ! CurSection -> isAbsolute ( ) ) { SmallVector < const MCSymbol * , 4 > Symbols ; MO . getExpr ( ) -> findAssociatedSymbols ( Symbols ) ; for ( const MCSymbol * S : Symbols ) { if ( S -> isDefined ( ) ) return MF . getMachineMemOperand ( MO , MachineMemOperand :: MORef ( needsLoad , S -> getAssociatedSection ( ) -> getFragment ( ) ) ) ; } } return MF . getMachineMemOperand ( MO , MachineMemOperand :: MOAbs ) ; }


enum ExprKinds { GLOBAL_VARIABLE , SHARED_VARIABLE , CONSTANT , REGISTER , FUNCTION_CALL }


LLVMValueRef create ( LLVMContextRef context , LLVMTypeRef structType , LLVMValueRef nvptx1 , LLVMValueRef nvptx2 , LLVMValueRef nvptx3 , LLVMValueRef nvptx4 ) { LLVMValueRef structVal = LLVMGetUndef ( structType ) ; structVal = LLVMConstInsertValue ( structVal , nvptx1 , 0 ) ; structVal = LLVMConstInsertValue ( structVal , nvptx2 , 1 ) ; structVal = LLVMConstInsertValue ( structVal , nvptx3 , 2 ) ; structVal = LLVMConstInsertValue ( structVal , nvptx4 , 3 ) ; LLVMValueRef nvvmVal = LLVMConstInt ( LLVMInt32TypeInContext ( context ) , 1 , 0 ) ; structVal = LLVMConstInsertValue ( structVal , nvvmVal , 4 ) ; return structVal ; }


void create ( LLVMContext & C ) { StructType * STy = StructType :: create ( C , "NVPTX" ) ; STy -> setBody ( { Type :: getInt32Ty ( C ) , Type :: getInt32Ty ( C ) , Type :: getInt32Ty ( C ) , Type :: getInt32Ty ( C ) } ) ; }


"Invalid instruction opcode for creating unary instruction."


"NVPTX optimize redundant cvta.to.local instruction"


bool runOnMachineFunction ( Function & MF ) { NVPTX :: VRFrame & Frame = getTargetNVPTXFrameInfo ( ) ; NVPTX :: VRFrame & Allocations = getTargetNVPTXAllocations ( ) ; return true ; }


void
runOnMachineFunction
(
MachineFunction
&
MF
)
{
LLVMContext
&
Context
=
MF
.
getFunction
(
)
.
getContext
(
)
;
Module
*
M
=
MF
.
getFunction
(
)
.
getParent
(
)
;
for
(
MachineBasicBlock
&
MBB
:
MF
)
{
for
(
MachineInstr
&
MI
:
MBB
)
{
const
TargetInstrDesc
&
Desc
=
MI
.
getDesc
(
)
;
uint16_t
Opcode
=
Desc
.
getOpcode
(
)
;
const
MCInstrDesc
&
MCID
=
getMCInstrDesc
(
Opcode
)
;
const
MCInstrDesc
&
MCID
=
getNVCInstrDesc
(
Opcode
)
;
const
MCInstrDesc
&
MCID
=
getNVKInstrDesc
(
Opcode
)
;
const
MCInstrDesc
&
MCID
=
getNVTInstrDesc
(
Opcode
)
;
DebugLoc
DL
=
MI
.
getDebugLoc
(
)
;
const
NVPTXMachineInstrInfo
&
NMI
=
MF
.
getSubtarget
<
NVPTXSubtarget
>
(
)
.
getInstrInfo
(
)
;
MCInstBuilder
MIB
=
NMI
.
BuildMI
(
MBB
,
DL
,
MCID
)
;
for
(
unsigned
I
=
0
,
E
=
MI
.
getNumOperands
(
)
;
I
!=
E
;
++
I
)
{
MachineOperand
MO
=
MI
.
getOperand
(
I
)
;
switch
(
MO
.
getType
(
)
)
{
case
MachineOperand
::
MO_Register
:
MIB
.
addReg
(
MO
.
getReg
(
)
,
getRegState
(
MO
)
,
MO
.
getSubReg
(
)
)
;
break
;
case
MachineOperand
::
MO_Immediate
:
MIB
.
addImm
(
MO
.
getImm
(
)
)
;
break
;
case
MachineOperand
::
MO_FPImmediate
:
MIB
.
addFP
(
MO
.
getFPImm
(
)
)
;
break
;
case
MachineOperand
::
MO_MachineBasicBlock
:
MIB
.
addMBB
(
MO
.
getMBB
(
)
)
;
break
;
case
MachineOperand
::
MO_JumpTarget
:
MIB
.
addJT
(
MO
.
getJumpTarget
(
)
)
;
break
;
case
MachineOperand
::
MO_GlobalAddress
:
MIB
.
addGlobalAddress
(
MO
.
getGlobal
(
)
,
MO
.
getOffset
(
)
,
MO
.
getTargetFlags
(
)
)
;
break
;
case
MachineOperand
::
MO_ConstantPoolIndex
:
MIB
.
addConstantPoolIndex
(
MO
.
getIndex
(
)
,
MO
.
getOffset
(
)
,
MO
.
getTargetFlags
(
)
)
;
break
;
default
:
llvm_unreachable
(
"Unknown operand type"
)
;
}
}
}
}
}


void getAnalysisUsage ( AnalysisUsage & AU ) const override { AU . addRequired < NVPTXTargetMachine > ( ) ; AU . addRequired < ModuleAnalysis > ( ) ; AU . addRequired < FunctionAnalysis > ( ) ; AU . addRequired < BlockAnalysis > ( ) ; AU . addPreserved < GlobalValueAnalysis > ( ) ; AU . addPreserved < ModuleAnalysis > ( ) ; AU . addPreserved < FunctionAnalysis > ( ) ; AU . addPreserved < BlockAnalysis > ( ) ; TargetPassConfig :: getAnalysisUsage ( AU ) ; }