LLVM: lib/Target/RISCV/RISCVFoldMemOffset.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

21#include

22

23using namespace llvm;

24

25#define DEBUG_TYPE "riscv-fold-mem-offset"

26#define RISCV_FOLD_MEM_OFFSET_NAME "RISC-V Fold Memory Offset"

27

28namespace {

29

31public:

32 static char ID;

33

35

37

38 bool foldOffset(Register OrigReg, int64_t InitialOffset,

41

42 void getAnalysisUsage(AnalysisUsage &AU) const override {

45 }

46

48};

49

50

51class FoldableOffset {

52 std::optional<int64_t> Offset;

53

54public:

55 bool hasValue() const { return Offset.has_value(); }

56 int64_t getValue() const { return *Offset; }

57

58 FoldableOffset &operator=(int64_t RHS) {

60 return *this;

61 }

62

67 return *this;

68 }

69

71};

72

73}

74

75char RISCVFoldMemOffset::ID = 0;

77 false, false)

78

80 return new RISCVFoldMemOffset();

81}

82

83

84

85

86

87

88

89

90bool RISCVFoldMemOffset::foldOffset(

93

94 DenseMap<Register, int64_t> RegToOffsetMap;

95

96

97 RegToOffsetMap[OrigReg] = InitialOffset;

98

99 std::queue Worklist;

100 Worklist.push(OrigReg);

101

102 while (!Worklist.empty()) {

104 Worklist.pop();

105

107 return false;

108

109 for (auto &User : MRI.use_nodbg_instructions(Reg)) {

110 FoldableOffset Offset;

111

112 switch (User.getOpcode()) {

113 default:

114 return false;

115 case RISCV::ADD:

116 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

117 I != RegToOffsetMap.end())

119 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());

120 I != RegToOffsetMap.end())

122 break;

123 case RISCV::SH1ADD:

124 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

125 I != RegToOffsetMap.end())

126 Offset = (uint64_t)I->second << 1;

127 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());

128 I != RegToOffsetMap.end())

130 break;

131 case RISCV::SH2ADD:

132 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

133 I != RegToOffsetMap.end())

134 Offset = (uint64_t)I->second << 2;

135 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());

136 I != RegToOffsetMap.end())

138 break;

139 case RISCV::SH3ADD:

140 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

141 I != RegToOffsetMap.end())

142 Offset = (uint64_t)I->second << 3;

143 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());

144 I != RegToOffsetMap.end())

146 break;

147 case RISCV::ADD_UW:

148 case RISCV::SH1ADD_UW:

149 case RISCV::SH2ADD_UW:

150 case RISCV::SH3ADD_UW:

151

152 if (User.getOperand(1).getReg() == Reg)

153 return false;

154 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());

155 I != RegToOffsetMap.end())

157 break;

158 case RISCV::SLLI: {

159 unsigned ShAmt = User.getOperand(2).getImm();

160 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

161 I != RegToOffsetMap.end())

162 Offset = (uint64_t)I->second << ShAmt;

163 break;

164 }

165 case RISCV::LB:

166 case RISCV::LBU:

167 case RISCV::SB:

168 case RISCV::LH:

169 case RISCV::LH_INX:

170 case RISCV::LHU:

171 case RISCV::FLH:

172 case RISCV::SH:

173 case RISCV::SH_INX:

174 case RISCV::FSH:

175 case RISCV::LW:

176 case RISCV::LW_INX:

177 case RISCV::LWU:

178 case RISCV::FLW:

179 case RISCV::SW:

180 case RISCV::SW_INX:

181 case RISCV::FSW:

182 case RISCV::LD:

183 case RISCV::FLD:

184 case RISCV::SD:

185 case RISCV::FSD: {

186

187 if (User.getOperand(0).getReg() == Reg)

188 return false;

189

190

191 if (User.getOperand(2).isImm())

192 return false;

193

194

195

196 if (User.getOperand(1).getReg() == OrigReg)

197 return false;

198

199 auto I = RegToOffsetMap.find(User.getOperand(1).getReg());

200 if (I == RegToOffsetMap.end())

201 return false;

202

203 int64_t LocalOffset = User.getOperand(2).getImm();

205 int64_t CombinedOffset = (uint64_t)LocalOffset + (uint64_t)I->second;

207 return false;

208

209 FoldableInstrs[&User] = CombinedOffset;

210 continue;

211 }

212 }

213

214

215 assert(Offset.hasValue() && "Expected an offset");

216

217

218

219 int64_t OffsetVal = Offset.getValue();

220 auto P =

221 RegToOffsetMap.try_emplace(User.getOperand(0).getReg(), OffsetVal);

222 if (P.second) {

223 Worklist.push(User.getOperand(0).getReg());

224 } else if (P.first->second != OffsetVal) {

225 P.first->second = OffsetVal;

226 Worklist.push(User.getOperand(0).getReg());

227 }

228 }

229 }

230

231 return true;

232}

233

234bool RISCVFoldMemOffset::runOnMachineFunction(MachineFunction &MF) {

236 return false;

237

238

240 return false;

241

243

244 bool MadeChange = false;

245 for (MachineBasicBlock &MBB : MF) {

247

248

249 if (MI.getOpcode() != RISCV::ADDI)

250 continue;

251

252

253 if (MI.getOperand(1).isReg() || MI.getOperand(2).isImm())

254 continue;

255

256

257 if (MI.getOperand(1).getReg() == RISCV::X0)

258 continue;

259

260 int64_t Offset = MI.getOperand(2).getImm();

262

263 DenseMap<MachineInstr *, int64_t> FoldableInstrs;

264

265 if (!foldOffset(MI.getOperand(0).getReg(), Offset, MRI, FoldableInstrs))

266 continue;

267

268 if (FoldableInstrs.empty())

269 continue;

270

271

272

273 for (auto [MemMI, NewOffset] : FoldableInstrs)

274 MemMI->getOperand(2).setImm(NewOffset);

275

276 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());

277 MRI.clearKillFlags(MI.getOperand(1).getReg());

278 MI.eraseFromParent();

279 }

280 }

281

282 return MadeChange;

283}

unsigned const MachineRegisterInfo * MRI

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

Promote Memory to Register

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

#define RISCV_FOLD_MEM_OFFSET_NAME

Definition RISCVFoldMemOffset.cpp:26

Represent the analysis usage information of a pass.

LLVM_ABI void setPreservesCFG()

This function should be called by the pass, iff they do not:

iterator find(const_arg_type_t< KeyT > Val)

std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)

FunctionPass class - This class is used to implement most global optimizations.

bool hasOptSize() const

Optimize this function for size (-Os) or minimum size (-Oz).

MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...

void getAnalysisUsage(AnalysisUsage &AU) const override

getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.

MachineRegisterInfo & getRegInfo()

getRegInfo - Return information about the registers currently in use.

Function & getFunction()

Return the LLVM function that this machine code represents.

MachineRegisterInfo - Keep track of information for virtual and physical registers,...

Wrapper class representing virtual and physical registers.

constexpr bool isVirtual() const

Return true if the specified register number is in the virtual register namespace.

StringRef - Represent a constant reference to a string, i.e.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ User

could "use" a pointer

This is an optimization pass for GlobalISel generic memory operations.

FunctionPass * createRISCVFoldMemOffsetPass()

constexpr bool isInt(int64_t x)

Checks if an integer fits into the given bit width.

APInt operator*(APInt a, uint64_t RHS)

LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator+=(DynamicAPInt &A, int64_t B)

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...