Skip to content

Commit 334c71d

Browse files
Konstantin VladimirovNikitaRudenkoIntelAnton SidorenkoAlexeySachkov
authored andcommitted
Implementation of SPV_INTEL_inline_assembly extension
Extension is published as #1290 Co-Authored-By: Nikita Rudenko <[email protected]> Co-Authored-By: Anton Sidorenko <[email protected]> Co-Authored-By: Alexey Sachkov <[email protected]>
1 parent e3d6c68 commit 334c71d

17 files changed

+568
-69
lines changed

llvm-spirv/include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ EXT(SPV_INTEL_blocking_pipes)
1515
EXT(SPV_INTEL_function_pointers)
1616
EXT(SPV_INTEL_kernel_attributes)
1717
EXT(SPV_INTEL_io_pipes)
18+
EXT(SPV_INTEL_inline_assembly)

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
//===----------------------------------------------------------------------===//
3939
#include "SPIRVReader.h"
4040
#include "OCLUtil.h"
41+
#include "SPIRVAsm.h"
4142
#include "SPIRVBasicBlock.h"
4243
#include "SPIRVExtInst.h"
4344
#include "SPIRVFunction.h"
@@ -57,6 +58,7 @@
5758
#include "llvm/IR/DerivedTypes.h"
5859
#include "llvm/IR/Dominators.h"
5960
#include "llvm/IR/IRBuilder.h"
61+
#include "llvm/IR/InlineAsm.h"
6062
#include "llvm/IR/Instructions.h"
6163
#include "llvm/IR/IntrinsicInst.h"
6264
#include "llvm/IR/LegacyPassManager.h"
@@ -1516,6 +1518,9 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
15161518
case OpFunction:
15171519
return mapValue(BV, transFunction(static_cast<SPIRVFunction *>(BV)));
15181520

1521+
case OpAsmINTEL:
1522+
return mapValue(BV, transAsmINTEL(static_cast<SPIRVAsmINTEL *>(BV)));
1523+
15191524
case OpLabel:
15201525
return mapValue(BV, BasicBlock::Create(*Context, BV->getName(), F));
15211526

@@ -2112,6 +2117,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
21122117
return mapValue(BV, Call);
21132118
}
21142119

2120+
case OpAsmCallINTEL:
2121+
return mapValue(
2122+
BV, transAsmCallINTEL(static_cast<SPIRVAsmCallINTEL *>(BV), F, BB));
2123+
21152124
case OpFunctionPointerCallINTEL: {
21162125
SPIRVFunctionPointerCallINTEL *BC =
21172126
static_cast<SPIRVFunctionPointerCallINTEL *>(BV);
@@ -2380,6 +2389,24 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
23802389
return F;
23812390
}
23822391

2392+
Value *SPIRVToLLVM::transAsmINTEL(SPIRVAsmINTEL *BA) {
2393+
assert(BA);
2394+
bool HasSideEffect = BA->hasDecorate(DecorationSideEffectsINTEL);
2395+
return InlineAsm::get(
2396+
cast<FunctionType>(transType(BA->getFunctionType())),
2397+
BA->getInstructions(), BA->getConstraints(), HasSideEffect,
2398+
/* IsAlignStack */ false, InlineAsm::AsmDialect::AD_ATT);
2399+
}
2400+
2401+
CallInst *SPIRVToLLVM::transAsmCallINTEL(SPIRVAsmCallINTEL *BI, Function *F,
2402+
BasicBlock *BB) {
2403+
assert(BI);
2404+
auto *IA = cast<InlineAsm>(transValue(BI->getAsm(), F, BB));
2405+
auto Args = transValue(BM->getValues(BI->getArguments()), F, BB);
2406+
return CallInst::Create(cast<FunctionType>(IA->getFunctionType()), IA, Args,
2407+
BI->getName(), BB);
2408+
}
2409+
23832410
/// LLVM convert builtin functions is translated to two instructions:
23842411
/// y = i32 islessgreater(float x, float z) ->
23852412
/// y = i32 ZExt(bool LessOrGreater(float x, float z))

llvm-spirv/lib/SPIRV/SPIRVReader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class SPIRVToLLVM {
103103
Instruction *transSGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);
104104
bool transFPContractMetadata();
105105
bool transKernelMetadata();
106+
Value *transAsmINTEL(SPIRVAsmINTEL *BA);
107+
CallInst *transAsmCallINTEL(SPIRVAsmCallINTEL *BI, Function *F,
108+
BasicBlock *BB);
106109
bool transNonTemporalMetadata(Instruction *I);
107110
bool transSourceLanguage();
108111
bool transSourceExtension();

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
#include "SPIRVWriter.h"
4242
#include "LLVMToSPIRVDbgTran.h"
43+
#include "SPIRVAsm.h"
4344
#include "SPIRVBasicBlock.h"
4445
#include "SPIRVEntry.h"
4546
#include "SPIRVEnum.h"
@@ -60,6 +61,7 @@
6061
#include "llvm/IR/Constants.h"
6162
#include "llvm/IR/DerivedTypes.h"
6263
#include "llvm/IR/Function.h"
64+
#include "llvm/IR/InlineAsm.h"
6365
#include "llvm/IR/InstrTypes.h"
6466
#include "llvm/IR/Instructions.h"
6567
#include "llvm/IR/IntrinsicInst.h"
@@ -1268,6 +1270,10 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
12681270
return BV ? mapValue(V, BV) : nullptr;
12691271
}
12701272

1273+
if (InlineAsm *IA = dyn_cast<InlineAsm>(V))
1274+
if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_inline_assembly))
1275+
return mapValue(V, transAsmINTEL(IA));
1276+
12711277
if (CallInst *CI = dyn_cast<CallInst>(V))
12721278
return mapValue(V, transCallInst(CI, BB));
12731279

@@ -1777,6 +1783,11 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II,
17771783
}
17781784

17791785
SPIRVValue *LLVMToSPIRV::transCallInst(CallInst *CI, SPIRVBasicBlock *BB) {
1786+
assert(CI);
1787+
if (isa<InlineAsm>(CI->getCalledOperand()) &&
1788+
BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_inline_assembly))
1789+
return transAsmCallINTEL(CI, BB);
1790+
17801791
if (CI->isIndirectCall())
17811792
return transIndirectCallInst(CI, BB);
17821793
return transDirectCallInst(CI, BB);
@@ -1830,6 +1841,32 @@ SPIRVValue *LLVMToSPIRV::transIndirectCallInst(CallInst *CI,
18301841
BB);
18311842
}
18321843

1844+
SPIRVValue *LLVMToSPIRV::transAsmINTEL(InlineAsm *IA) {
1845+
assert(IA);
1846+
1847+
// TODO: intention here is to provide information about actual target
1848+
// but in fact spir-64 is substituted as triple when translator works
1849+
// eventually we need to fix it (not urgent)
1850+
StringRef TripleStr(M->getTargetTriple());
1851+
auto AsmTarget = static_cast<SPIRVAsmTargetINTEL *>(
1852+
BM->getOrAddAsmTargetINTEL(TripleStr.str()));
1853+
auto SIA = BM->addAsmINTEL(
1854+
static_cast<SPIRVTypeFunction *>(transType(IA->getFunctionType())),
1855+
AsmTarget, IA->getAsmString(), IA->getConstraintString());
1856+
if (IA->hasSideEffects())
1857+
SIA->addDecorate(DecorationSideEffectsINTEL);
1858+
return SIA;
1859+
}
1860+
1861+
SPIRVValue *LLVMToSPIRV::transAsmCallINTEL(CallInst *CI, SPIRVBasicBlock *BB) {
1862+
assert(CI);
1863+
auto IA = cast<InlineAsm>(CI->getCalledOperand());
1864+
return BM->addAsmCallINTELInst(
1865+
static_cast<SPIRVAsmINTEL *>(transValue(IA, BB, false)),
1866+
transArguments(CI, BB, SPIRVEntry::createUnique(OpAsmCallINTEL).get()),
1867+
BB);
1868+
}
1869+
18331870
bool LLVMToSPIRV::transAddressingMode() {
18341871
Triple TargetTriple(M->getTargetTriple());
18351872

llvm-spirv/lib/SPIRV/SPIRVWriter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class LLVMToSPIRV : public ModulePass {
100100
SPIRVValue *transCallInst(CallInst *Call, SPIRVBasicBlock *BB);
101101
SPIRVValue *transDirectCallInst(CallInst *Call, SPIRVBasicBlock *BB);
102102
SPIRVValue *transIndirectCallInst(CallInst *Call, SPIRVBasicBlock *BB);
103+
SPIRVValue *transAsmINTEL(InlineAsm *Asm);
104+
SPIRVValue *transAsmCallINTEL(CallInst *Call, SPIRVBasicBlock *BB);
103105
bool transDecoration(Value *V, SPIRVValue *BV);
104106
SPIRVWord transFunctionControlMask(Function *);
105107
SPIRVFunction *transFunctionDecl(Function *F);
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===- SPIRVAsm.h - --*- C++ -*-===//
2+
//
3+
// The LLVM/SPIRV Translator
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
/// \file
10+
///
11+
/// This file defines the inline assembler entries defined in SPIRV spec with op
12+
/// codes.
13+
///
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef SPIRV_LIBSPIRV_SPIRVASM_H
17+
#define SPIRV_LIBSPIRV_SPIRVASM_H
18+
19+
#include "SPIRVEntry.h"
20+
#include "SPIRVInstruction.h"
21+
#include "SPIRVValue.h"
22+
23+
namespace SPIRV {
24+
25+
class SPIRVAsmTargetINTEL : public SPIRVEntry {
26+
public:
27+
static const SPIRVWord FixedWC = 2;
28+
static const Op OC = OpAsmTargetINTEL;
29+
// Complete constructor
30+
SPIRVAsmTargetINTEL(SPIRVModule *M, SPIRVId TheId,
31+
const std::string &TheTarget)
32+
: SPIRVEntry(M, FixedWC + getSizeInWords(TheTarget), OC, TheId),
33+
Target(TheTarget) {
34+
validate();
35+
}
36+
// Incomplete constructor
37+
SPIRVAsmTargetINTEL() : SPIRVEntry(OC) {}
38+
SPIRVCapVec getRequiredCapability() const override {
39+
return getVec(CapabilityAsmINTEL);
40+
}
41+
SPIRVExtSet getRequiredExtensions() const override {
42+
return getSet(ExtensionID::SPV_INTEL_inline_assembly);
43+
}
44+
const std::string &getTarget() const { return Target; }
45+
46+
protected:
47+
void validate() const override {
48+
SPIRVEntry::validate();
49+
assert(WordCount > FixedWC);
50+
assert(OpCode == OC);
51+
}
52+
_SPIRV_DEF_ENCDEC2(Id, Target)
53+
std::string Target;
54+
};
55+
56+
class SPIRVAsmINTEL : public SPIRVValue {
57+
public:
58+
static const SPIRVWord FixedWC = 5;
59+
static const Op OC = OpAsmINTEL;
60+
// Complete constructor
61+
SPIRVAsmINTEL(SPIRVModule *M, SPIRVTypeFunction *TheFunctionType,
62+
SPIRVId TheId, SPIRVAsmTargetINTEL *TheTarget,
63+
const std::string &TheInstructions,
64+
const std::string &TheConstraints)
65+
: SPIRVValue(M,
66+
FixedWC + getSizeInWords(TheInstructions) +
67+
getSizeInWords(TheConstraints),
68+
OC, TheFunctionType->getReturnType(), TheId),
69+
Target(TheTarget), FunctionType(TheFunctionType),
70+
Instructions(TheInstructions), Constraints(TheConstraints) {
71+
validate();
72+
}
73+
// Incomplete constructor
74+
SPIRVAsmINTEL() : SPIRVValue(OC) {}
75+
SPIRVCapVec getRequiredCapability() const override {
76+
return getVec(CapabilityAsmINTEL);
77+
}
78+
SPIRVExtSet getRequiredExtensions() const override {
79+
return getSet(ExtensionID::SPV_INTEL_inline_assembly);
80+
}
81+
const std::string &getInstructions() const { return Instructions; }
82+
const std::string &getConstraints() const { return Constraints; }
83+
SPIRVTypeFunction *getFunctionType() const { return FunctionType; }
84+
85+
protected:
86+
_SPIRV_DEF_ENCDEC6(Type, Id, FunctionType, Target, Instructions, Constraints)
87+
void validate() const override {
88+
SPIRVValue::validate();
89+
assert(WordCount > FixedWC);
90+
assert(OpCode == OC);
91+
}
92+
SPIRVAsmTargetINTEL *Target;
93+
SPIRVTypeFunction *FunctionType;
94+
std::string Instructions;
95+
std::string Constraints;
96+
};
97+
98+
class SPIRVAsmCallINTEL : public SPIRVInstruction {
99+
public:
100+
static const SPIRVWord FixedWC = 4;
101+
static const Op OC = OpAsmCallINTEL;
102+
// Complete constructor
103+
SPIRVAsmCallINTEL(SPIRVId TheId, SPIRVAsmINTEL *TheAsm,
104+
const std::vector<SPIRVWord> &TheArgs,
105+
SPIRVBasicBlock *TheBB)
106+
: SPIRVInstruction(FixedWC + TheArgs.size(), OC, TheAsm->getType(), TheId,
107+
TheBB),
108+
Asm(TheAsm), Args(TheArgs) {
109+
validate();
110+
}
111+
// Incomplete constructor
112+
SPIRVAsmCallINTEL() : SPIRVInstruction(OC) {}
113+
SPIRVCapVec getRequiredCapability() const override {
114+
return getVec(CapabilityAsmINTEL);
115+
}
116+
SPIRVExtSet getRequiredExtensions() const override {
117+
return getSet(ExtensionID::SPV_INTEL_inline_assembly);
118+
}
119+
bool isOperandLiteral(unsigned int Index) const override { return false; }
120+
void setWordCount(SPIRVWord TheWordCount) override {
121+
SPIRVEntry::setWordCount(TheWordCount);
122+
Args.resize(TheWordCount - FixedWC);
123+
}
124+
const std::vector<SPIRVWord> &getArguments() const { return Args; }
125+
126+
SPIRVAsmINTEL *getAsm() const { return Asm; }
127+
128+
protected:
129+
_SPIRV_DEF_ENCDEC4(Type, Id, Asm, Args)
130+
void validate() const override {
131+
SPIRVInstruction::validate();
132+
assert(WordCount >= FixedWC);
133+
assert(OpCode == OC);
134+
assert(getBasicBlock() && "Invalid BB");
135+
assert(getBasicBlock()->getModule() == Asm->getModule());
136+
}
137+
SPIRVAsmINTEL *Asm;
138+
std::vector<SPIRVWord> Args;
139+
};
140+
141+
} // namespace SPIRV
142+
#endif // SPIRV_LIBSPIRV_SPIRVASM_H

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
//===----------------------------------------------------------------------===//
3939

4040
#include "SPIRVEntry.h"
41+
#include "SPIRVAsm.h"
4142
#include "SPIRVBasicBlock.h"
4243
#include "SPIRVDebug.h"
4344
#include "SPIRVDecorate.h"

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ template <> inline void SPIRVMap<Decoration, SPIRVCapVec>::init() {
366366
ADD_VEC_INIT(DecorationReferencedIndirectlyINTEL,
367367
{CapabilityIndirectReferencesINTEL});
368368
ADD_VEC_INIT(DecorationIOPipeStorageINTEL, {CapabilityIOPipeINTEL});
369+
ADD_VEC_INIT(DecorationSideEffectsINTEL, {CapabilityAsmINTEL});
369370
}
370371

371372
template <> inline void SPIRVMap<BuiltIn, SPIRVCapVec>::init() {

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,9 @@ inline bool isValid(spv::Op V) {
893893
case OpSubgroupImageBlockWriteINTEL:
894894
case OpSubgroupImageMediaBlockReadINTEL:
895895
case OpSubgroupImageMediaBlockWriteINTEL:
896+
case OpAsmTargetINTEL:
897+
case OpAsmINTEL:
898+
case OpAsmCallINTEL:
896899
case OpVmeImageINTEL:
897900
case OpTypeVmeImageINTEL:
898901
case OpTypeAvcImePayloadINTEL:

0 commit comments

Comments
 (0)