OpenASIP 2.2
Loading...
Searching...
No Matches
ConstantTransformer.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2015 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file ConstantTransformer.cc
26 *
27 * Implementation of ConstantTransformer class.
28 *
29 * @author Pekka Jääskeläinen 2015
30 * @note reting: red
31 */
32
33#include "CompilerWarnings.hh"
34
35IGNORE_COMPILER_WARNING("-Wunused-parameter")
36
37#include "ConstantTransformer.hh"
38
39#include "MachineInfo.hh"
40#include "TCETargetMachine.hh"
41#include "OperationPool.hh"
42#include "Operation.hh"
43#include "Operand.hh"
44
45#include <llvm/CodeGen/MachineFunction.h>
46#include <llvm/CodeGen/MachineBasicBlock.h>
47#include <llvm/MC/MCInstrInfo.h>
48#include <llvm/CodeGen/TargetInstrInfo.h>
49#include <llvm/CodeGen/TargetSubtargetInfo.h>
50#include <llvm/CodeGen/TargetOpcodes.h>
51#include <llvm/CodeGen/MachineInstrBuilder.h>
52
54
55#include <sstream>
56
57using llvm::MachineBasicBlock;
58using llvm::MachineFunction;
59using llvm::MachineOperand;
62
63#define sub "SUB"
64
66
67bool
69 return false;
70}
71
72/**
73 * In case the given operandId is an input operand in the
74 * MachineInstr, returns the corresponding OSAL operand id
75 * (starting from 1), 0 otherwise.
76 */
77unsigned
79 const Operation& operation,
80 const llvm::MachineInstr& instr,
81 unsigned operandId) {
82
83 const TCETargetMachine& tm =
84 dynamic_cast<const TCETargetMachine&>(
85 instr.getParent()->getParent()->getTarget());
86
87 TCEString operationName = tm.operationName(instr.getDesc().getOpcode());
88 bool hasGuard = operationName[0] == '?' || operationName[0] == '!';
89
90 unsigned osalIndex = 0;
91 for (unsigned operandI = 0; operandI < instr.getNumOperands(); ++operandI) {
92 const MachineOperand& mo = instr.getOperand(operandI);
93 if (hasGuard && operandI == 0) continue;
94 // Output or metadata.
95 if ((mo.isReg() && (mo.isDef() || mo.isImplicit())) || mo.isMetadata())
96 continue;
97 ++osalIndex;
98 if (operandI == operandId) return osalIndex;
99 // LLVM machineinstructions always present the addresses in the
100 // base + offset form, thus consume two input operands per one
101 // OSAL operand. Skip the offset operand in case the OSAL operation
102 // only the takes a single absolute address.
103 if (operation.operand(osalIndex).isAddress() &&
104 !operation.isBaseOffsetMemOperation()) {
105 ++operandI;
106 }
107 }
108
109 return 0;
110}
111
112bool
114
115 const TCETargetMachine& tm =
116 dynamic_cast<const TCETargetMachine&>(mf.getTarget());
118
119 OperationPool osal;
120
121 bool changed = false;
122 for (MachineFunction::iterator i = mf.begin(); i != mf.end(); i++) {
123 MachineBasicBlock& mbb = *i;
124 for (MachineBasicBlock::iterator j = mbb.begin();
125 j != mbb.end(); j++) {
126 const llvm::MachineInstr* mi = &*j;
127 unsigned opc = mi->getOpcode();
128
129 const llvm::MCInstrDesc& opDesc = mi->getDesc();
130 if (opDesc.isReturn()) {
131 continue;
132 }
133 if (opc == llvm::TargetOpcode::DBG_VALUE
134 || opc == llvm::TargetOpcode::DBG_LABEL
135 || opc == llvm::TargetOpcode::DBG_INSTR_REF
136 || opc == llvm::TargetOpcode::DBG_VALUE_LIST
137 || opc == llvm::TargetOpcode::DBG_PHI
138 || opc == llvm::TargetOpcode::KILL) {
139 continue;
140 }
141
142 TCEString opname = tm.operationName(opc);
143 if (opname == "") continue;
144 bool hasGuard = opname[0] == '?' || opname[0] == '!';
145 if (hasGuard) opname = opname.substr(1);
146
147 const Operation& op = osal.operation(opname.c_str());
148 if (op.isNull() || op.isBranch() || op.isCall() ||
149 op.readsMemory()) {
150 // isNull = INLINE asm, a pseudo asm block or similar.
151 // TODO: add support for at least INLINE and MOVE.
152
153 // In case the operation reads memory, assume the
154 // possible immediate operand is a global address
155 // we cannot fix at this point.
156 // TODO: Fix global address constants. Needs to have new type
157 // of data symbol/relocation info in case an address
158 // constant is broken down.
159
160 continue;
161 }
162
163 for (unsigned operandI = 0; operandI < mi->getNumOperands();
164 ++operandI) {
165
166 const MachineOperand& mo = mi->getOperand(operandI);
167 if (!mo.isImm()) continue;
168
169 unsigned inputIndex = osalInputIndex(op, *mi, operandI);
170 if (inputIndex == 0) continue;
171 const Operand& operand = op.operand(inputIndex);
172 if (operand.isNull() || !operand.isInput()) {
173 continue; // ignore output operands
175 << "Input " << inputIndex
176 << " not found for operation "
177 << opname << std::endl;
178 assert(false);
179 }
180 assert(operand.isInput());
181 size_t operandWidth = operand.width();
182
184 mach_, mo.getImm(), operandWidth)) continue;
185
186 // check if it's possible to convert C to SUB(0, -C) such
187 // that it can be encoded for the target
190 mach_, -mo.getImm()) && /* SUB is 32b */
192
193 const llvm::MCInstrInfo* iinfo =
194 mf.getTarget().getSubtargetImpl(
195 mf.getFunction())->getInstrInfo();
196 // RV_HIGH = SUB 0 -X
197 BuildMI(
198 mbb, j, j->getDebugLoc(), iinfo->get(plugin.opcode(sub)),
199 plugin.rvHighDRegNum()).addImm(0).addImm(-mo.getImm());
200
201 // replace the original instruction's immediate operand
202 // with the RV_HIGH
203 llvm::MachineInstrBuilder mib =
204 BuildMI(mbb, j, j->getDebugLoc(), j->getDesc());
205 for (unsigned opr = 0; opr < j->getNumOperands(); ++opr) {
206 MachineOperand& orig = j->getOperand(opr);
207 if (opr == operandI) {
208 mib.add(MachineOperand::CreateReg(
209 plugin.rvHighDRegNum(), false));
210 continue;
211 }
212 mib.add(orig);
213 orig.clearParent();
214 }
215
216 // the original instruction can be now deleted
217 j->eraseFromParent();
218 // start scanning the MBB from the beginning due to
219 // possibly invalidated iterators from adding the
220 // new instructions
221 j = mbb.begin();
222 changed = true;
223 } else {
224 std::ostringstream errMsg;
225 errMsg << "Program uses constant '"
226 << mo.getImm() << "'";
227 if (Application::verboseLevel() > 0) {
228 errMsg << " -> " << opname
229 << " (llvm opc = " << opc << ")";
230 }
231 errMsg << " that cannot be encoded "
232 << "for the machine by the current compiler.";
233 throw CompileError(
234 __FILE__, __LINE__, __func__, errMsg.str());
235 }
236 }
237 }
238
239 }
240 return changed;
241}
242
243bool
245 return false;
246}
#define __func__
#define assert(condition)
#define IGNORE_COMPILER_WARNING(X)
#define POP_COMPILER_DIAGS
unsigned osalInputIndex(const Operation &operation, const llvm::MachineInstr &instr, unsigned operandId)
#define sub
static std::ostream & errorStream()
static int verboseLevel()
bool doFinalization(llvm::Module &M)
const TTAMachine::Machine & mach_
bool doInitialization(llvm::Module &M)
bool runOnMachineFunction(llvm::MachineFunction &mf)
static bool canEncodeImmediateInteger(const TTAMachine::Machine &mach, int64_t imm, unsigned destWidth=UINT_MAX)
static bool supportsOperation(const TTAMachine::Machine &mach, TCEString operation)
virtual bool isAddress() const
Definition Operand.cc:328
virtual bool isInput() const
Definition Operand.cc:145
virtual int width() const
Definition Operand.cc:318
virtual bool isNull() const
Definition Operand.hh:130
Operation & operation(const char *name)
virtual bool readsMemory() const
Definition Operation.cc:242
virtual bool isCall() const
Definition Operation.cc:318
virtual bool isBaseOffsetMemOperation() const
Definition Operation.cc:323
bool isNull() const
virtual bool isBranch() const
Definition Operation.cc:306
virtual Operand & operand(int id) const
Definition Operation.cc:541
virtual unsigned rvHighDRegNum()=0
virtual unsigned opcode(TCEString operationName) const =0
Returns the opcode for the given osal operation, undefined if not found.
std::string operationName(unsigned opc) const
virtual TCETargetMachinePlugin & targetPlugin() const