Skip to content

Commit 0af7e64

Browse files
Implement support for @llvm.sadd.sat intrinsic. (#1524)
* Implement support for @llvm.sadd.sat intrinsic. * Rename LowerSaddWithOverflow to LowerSaddIntrinsics.
1 parent 9b280f4 commit 0af7e64

File tree

7 files changed

+255
-171
lines changed

7 files changed

+255
-171
lines changed

include/LLVMSPIRVLib.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void initializeSPIRVLowerBoolLegacyPass(PassRegistry &);
5757
void initializeSPIRVLowerConstExprLegacyPass(PassRegistry &);
5858
void initializeSPIRVLowerOCLBlocksLegacyPass(PassRegistry &);
5959
void initializeSPIRVLowerMemmoveLegacyPass(PassRegistry &);
60-
void initializeSPIRVLowerSaddWithOverflowLegacyPass(PassRegistry &);
60+
void initializeSPIRVLowerSaddIntrinsicsLegacyPass(PassRegistry &);
6161
void initializeSPIRVRegularizeLLVMLegacyPass(PassRegistry &);
6262
void initializeSPIRVToOCL12LegacyPass(PassRegistry &);
6363
void initializeSPIRVToOCL20LegacyPass(PassRegistry &);
@@ -183,7 +183,7 @@ ModulePass *createSPIRVLowerOCLBlocksLegacy();
183183
ModulePass *createSPIRVLowerMemmoveLegacy();
184184

185185
/// Create a pass for lowering llvm.sadd.with.overflow
186-
ModulePass *createSPIRVLowerSaddWithOverflowLegacy();
186+
ModulePass *createSPIRVLowerSaddIntrinsicsLegacy();
187187

188188
/// Create a pass for regularize LLVM module to be translated to SPIR-V.
189189
ModulePass *createSPIRVRegularizeLLVMLegacy();

lib/SPIRV/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ add_llvm_library(LLVMSPIRVLib
1414
SPIRVLowerConstExpr.cpp
1515
SPIRVLowerMemmove.cpp
1616
SPIRVLowerOCLBlocks.cpp
17-
SPIRVLowerSaddWithOverflow.cpp
17+
SPIRVLowerSaddIntrinsics.cpp
1818
SPIRVReader.cpp
1919
SPIRVRegularizeLLVM.cpp
2020
SPIRVToLLVMDbgTran.cpp
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//===- SPIRVLowerSaddIntrinsics.cpp - Lower llvm.sadd.* -------------------===//
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+
// Copyright (c) 2020 Intel Corporation. All rights reserved.
9+
//
10+
// Permission is hereby granted, free of charge, to any person obtaining a
11+
// copy of this software and associated documentation files (the "Software"),
12+
// to deal with the Software without restriction, including without limitation
13+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
14+
// and/or sell copies of the Software, and to permit persons to whom the
15+
// Software is furnished to do so, subject to the following conditions:
16+
//
17+
// Redistributions of source code must retain the above copyright notice,
18+
// this list of conditions and the following disclaimers.
19+
// Redistributions in binary form must reproduce the above copyright notice,
20+
// this list of conditions and the following disclaimers in the documentation
21+
// and/or other materials provided with the distribution.
22+
// Neither the names of Intel Corporation, nor the names of its
23+
// contributors may be used to endorse or promote products derived from this
24+
// Software without specific prior written permission.
25+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
31+
// THE SOFTWARE.
32+
//
33+
//===----------------------------------------------------------------------===//
34+
//
35+
// This file implements lowering of llvm.sadd.* into basic LLVM
36+
// operations. Probably, in the future this pass can be generalized for other
37+
// function calls
38+
//
39+
//===----------------------------------------------------------------------===//
40+
#define DEBUG_TYPE "spv-lower-llvm_sadd_intrinsics"
41+
42+
#include "SPIRVLowerSaddIntrinsics.h"
43+
#include "LLVMSaddWithOverflow.h"
44+
45+
#include "LLVMSPIRVLib.h"
46+
#include "SPIRVError.h"
47+
#include "libSPIRV/SPIRVDebug.h"
48+
49+
#include "llvm/IR/IRBuilder.h"
50+
#include "llvm/IR/IntrinsicInst.h"
51+
#include "llvm/IR/Module.h"
52+
#include "llvm/IRReader/IRReader.h"
53+
#include "llvm/Linker/Linker.h"
54+
#include "llvm/Support/SourceMgr.h"
55+
56+
using namespace llvm;
57+
using namespace SPIRV;
58+
59+
namespace SPIRV {
60+
61+
void SPIRVLowerSaddIntrinsicsBase::replaceSaddOverflow(Function &F) {
62+
assert(F.getIntrinsicID() == Intrinsic::sadd_with_overflow);
63+
64+
StringRef IntrinsicName = F.getName();
65+
std::string FuncName = "llvm_sadd_with_overflow_i";
66+
if (IntrinsicName.endswith(".i16"))
67+
FuncName += "16";
68+
else if (IntrinsicName.endswith(".i32"))
69+
FuncName += "32";
70+
else if (IntrinsicName.endswith(".i64"))
71+
FuncName += "64";
72+
else {
73+
assert(false &&
74+
"Unsupported overloading of llvm.sadd.with.overflow intrinsic");
75+
return;
76+
}
77+
78+
// Redirect @llvm.sadd.with.overflow.* call to the function we have in
79+
// the loaded module @llvm_sadd_with_overflow_*
80+
Function *ReplacementFunc = Mod->getFunction(FuncName);
81+
if (!ReplacementFunc) { // This function needs linking.
82+
Mod->getOrInsertFunction(FuncName, F.getFunctionType());
83+
// Read LLVM IR with the intrinsic's implementation
84+
SMDiagnostic Err;
85+
auto MB = MemoryBuffer::getMemBuffer(LLVMSaddWithOverflow);
86+
auto SaddWithOverflowModule =
87+
parseIR(MB->getMemBufferRef(), Err, *Context,
88+
[&](StringRef) { return Mod->getDataLayoutStr(); });
89+
if (!SaddWithOverflowModule) {
90+
std::string ErrMsg;
91+
raw_string_ostream ErrStream(ErrMsg);
92+
Err.print("", ErrStream);
93+
SPIRVErrorLog EL;
94+
EL.checkError(false, SPIRVEC_InvalidLlvmModule, ErrMsg);
95+
return;
96+
}
97+
98+
// Link in the intrinsic's implementation.
99+
if (!Linker::linkModules(*Mod, std::move(SaddWithOverflowModule),
100+
Linker::LinkOnlyNeeded))
101+
TheModuleIsModified = true;
102+
103+
ReplacementFunc = Mod->getFunction(FuncName);
104+
assert(ReplacementFunc && "How did we not link in the necessary function?");
105+
}
106+
107+
F.replaceAllUsesWith(ReplacementFunc);
108+
}
109+
110+
void SPIRVLowerSaddIntrinsicsBase::replaceSaddSat(Function &F) {
111+
assert(F.getIntrinsicID() == Intrinsic::sadd_sat);
112+
113+
SmallVector<IntrinsicInst *, 4> Intrinsics;
114+
for (User *U : F.users()) {
115+
if (auto *II = dyn_cast<IntrinsicInst>(U))
116+
Intrinsics.push_back(II);
117+
}
118+
119+
// Get the corresponding sadd_with_overflow intrinsic for the sadd_sat.
120+
Type *IntTy = F.getFunctionType()->getReturnType();
121+
Function *SaddO =
122+
Intrinsic::getDeclaration(Mod, Intrinsic::sadd_with_overflow, IntTy);
123+
124+
// Replace all uses of the intrinsic with equivalent code relying on
125+
// sadd_with_overflow
126+
IRBuilder<> Builder(F.getContext());
127+
unsigned BitWidth = IntTy->getIntegerBitWidth();
128+
Value *IntMin = Builder.getInt(APInt::getSignedMinValue(BitWidth));
129+
Value *ShiftWidth = Builder.getIntN(BitWidth, BitWidth - 1);
130+
131+
for (IntrinsicInst *II : Intrinsics) {
132+
Builder.SetInsertPoint(II);
133+
// {res, overflow} = @llvm.sadd_with_overflow(a, b)
134+
// sadd_sat(a, b) => overflow ? (res >> bitwidth) ^ intmin : res;
135+
Value *StructRes =
136+
Builder.CreateCall(SaddO, {II->getArgOperand(0), II->getArgOperand(1)});
137+
Value *Sum = Builder.CreateExtractValue(StructRes, 0);
138+
Value *Overflow = Builder.CreateExtractValue(StructRes, 1);
139+
Value *OverflowedRes =
140+
Builder.CreateXor(Builder.CreateAShr(Sum, ShiftWidth), IntMin);
141+
Value *Result = Builder.CreateSelect(Overflow, OverflowedRes, Sum);
142+
II->replaceAllUsesWith(Result);
143+
II->eraseFromParent();
144+
}
145+
146+
// Now replace the sadd_with_overflow intrinsic itself.
147+
replaceSaddOverflow(*SaddO);
148+
}
149+
150+
bool SPIRVLowerSaddIntrinsicsBase::runLowerSaddIntrinsics(Module &M) {
151+
Context = &M.getContext();
152+
Mod = &M;
153+
for (Function &F : M) {
154+
Intrinsic::ID IntrinId = F.getIntrinsicID();
155+
if (IntrinId == Intrinsic::sadd_with_overflow)
156+
replaceSaddOverflow(F);
157+
else if (IntrinId == Intrinsic::sadd_sat)
158+
replaceSaddSat(F);
159+
}
160+
161+
verifyRegularizationPass(M, "SPIRVLowerSaddIntrinsics");
162+
return TheModuleIsModified;
163+
}
164+
165+
llvm::PreservedAnalyses
166+
SPIRVLowerSaddIntrinsicsPass::run(llvm::Module &M,
167+
llvm::ModuleAnalysisManager &MAM) {
168+
return runLowerSaddIntrinsics(M) ? llvm::PreservedAnalyses::none()
169+
: llvm::PreservedAnalyses::all();
170+
}
171+
172+
SPIRVLowerSaddIntrinsicsLegacy::SPIRVLowerSaddIntrinsicsLegacy()
173+
: ModulePass(ID) {
174+
initializeSPIRVLowerSaddIntrinsicsLegacyPass(
175+
*PassRegistry::getPassRegistry());
176+
}
177+
178+
bool SPIRVLowerSaddIntrinsicsLegacy::runOnModule(Module &M) {
179+
return runLowerSaddIntrinsics(M);
180+
}
181+
182+
char SPIRVLowerSaddIntrinsicsLegacy::ID = 0;
183+
184+
} // namespace SPIRV
185+
186+
INITIALIZE_PASS(SPIRVLowerSaddIntrinsicsLegacy,
187+
"spv-lower-llvm_sadd_intrinsics",
188+
"Lower llvm.sadd.* intrinsics", false, false)
189+
190+
ModulePass *llvm::createSPIRVLowerSaddIntrinsicsLegacy() {
191+
return new SPIRVLowerSaddIntrinsicsLegacy();
192+
}

lib/SPIRV/SPIRVLowerSaddWithOverflow.h renamed to lib/SPIRV/SPIRVLowerSaddIntrinsics.h

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- SPIRVLowerSaddWithOverflowBase.h - sadd lowering --------*- C++ -*-===//
1+
//===- SPIRVLowerSaddIntrinsics.h - sadd lowering --------------*- C++ -*-===//
22
//
33
// The LLVM/SPIR-V Translator
44
//
@@ -32,42 +32,41 @@
3232
//
3333
//===----------------------------------------------------------------------===//
3434

35-
#ifndef SPIRV_SPIRVLOWERSADDWITHOVERFLOW_H
36-
#define SPIRV_SPIRVLOWERSADDWITHOVERFLOW_H
35+
#ifndef SPIRV_SPIRVLOWERSADDINTRINSICS_H
36+
#define SPIRV_SPIRVLOWERSADDINTRINSICS_H
3737

38-
#include "llvm/IR/InstVisitor.h"
3938
#include "llvm/IR/PassManager.h"
4039
#include "llvm/Pass.h"
4140

4241
namespace SPIRV {
4342

44-
class SPIRVLowerSaddWithOverflowBase
45-
: public llvm::InstVisitor<SPIRVLowerSaddWithOverflowBase> {
43+
class SPIRVLowerSaddIntrinsicsBase {
4644
public:
47-
SPIRVLowerSaddWithOverflowBase() : Context(nullptr), Mod(nullptr) {}
48-
virtual ~SPIRVLowerSaddWithOverflowBase() {}
49-
virtual void visitIntrinsicInst(llvm::CallInst &I);
45+
SPIRVLowerSaddIntrinsicsBase() : Context(nullptr), Mod(nullptr) {}
5046

51-
bool runLowerSaddWithOverflow(llvm::Module &M);
47+
bool runLowerSaddIntrinsics(llvm::Module &M);
5248

5349
private:
50+
void replaceSaddOverflow(llvm::Function &F);
51+
void replaceSaddSat(llvm::Function &F);
52+
5453
llvm::LLVMContext *Context;
5554
llvm::Module *Mod;
5655
bool TheModuleIsModified = false;
5756
};
5857

59-
class SPIRVLowerSaddWithOverflowPass
60-
: public llvm::PassInfoMixin<SPIRVLowerSaddWithOverflowPass>,
61-
public SPIRVLowerSaddWithOverflowBase {
58+
class SPIRVLowerSaddIntrinsicsPass
59+
: public llvm::PassInfoMixin<SPIRVLowerSaddIntrinsicsPass>,
60+
public SPIRVLowerSaddIntrinsicsBase {
6261
public:
6362
llvm::PreservedAnalyses run(llvm::Module &M,
6463
llvm::ModuleAnalysisManager &MAM);
6564
};
6665

67-
class SPIRVLowerSaddWithOverflowLegacy : public llvm::ModulePass,
68-
public SPIRVLowerSaddWithOverflowBase {
66+
class SPIRVLowerSaddIntrinsicsLegacy : public llvm::ModulePass,
67+
public SPIRVLowerSaddIntrinsicsBase {
6968
public:
70-
SPIRVLowerSaddWithOverflowLegacy();
69+
SPIRVLowerSaddIntrinsicsLegacy();
7170

7271
bool runOnModule(llvm::Module &M) override;
7372

@@ -76,4 +75,4 @@ class SPIRVLowerSaddWithOverflowLegacy : public llvm::ModulePass,
7675

7776
} // namespace SPIRV
7877

79-
#endif // SPIRV_SPIRVLOWERSADDWITHOVERFLOW_H
78+
#endif // SPIRV_SPIRVLOWERSADDINTRINSICS_H

0 commit comments

Comments
 (0)