Skip to content

Commit cd6c3e9

Browse files
committed
feat: add support for F and D RISC-V extensions
1 parent 52d5bf4 commit cd6c3e9

8 files changed

Lines changed: 621 additions & 123 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,18 @@ llvm-bleach currently comes with documentation for all of 3 distributed tools:
5050
- [mctomir](./docs/mctomir.md) - machine code to MIR lifter
5151
- [bleach-config-gen](./docs/bleach-config-gen.md) - helper tool to generate
5252
architecture configs for llvm-bleach from available templates.
53+
54+
### Platform Support
55+
56+
#### RISC-V
57+
58+
Currently llvm-bleach supports rv64/rv32 basic instruction sets for I configurations.
59+
Supported extensions include:
60+
61+
- M - Integer multiplication and division
62+
- F - Single-precision floating-point operations
63+
- D - Double-precision floating-point operations
64+
65+
> [!NOTE]
66+
> mctomir tool for lifting machine code to LLVM MIR potentially support all
67+
> architectures supported by LLVM but is not yet propperly tested

include/mctomir/mctomir-transform.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class translator_t final {
116116
uint64_t size);
117117
MachineBasicBlock *get_or_create_mbb_for_address(uint64_t address,
118118
MachineFunction &mfunc);
119+
void fill_operands(MachineInstrBuilder &builder, const MCInst &inst,
120+
const MCInstrDesc &desc, bool is_branch);
119121
void add_operand_to_mib(MachineInstrBuilder &mib, const MCOperand &mc_op,
120122
unsigned op_idx, const MCInstrDesc &desc);
121123
MachineInstr *create_machine_instr(const translated_inst &tinst,

lib/lifter/lifter.cpp

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,16 @@ void create_basic_blocks_for_mfunc(MachineFunction &src, MachineFunction &dst,
102102
std::unordered_map<MachineBasicBlock *, MachineBasicBlock *> block_map;
103103
// One cannot simply loop over mfunc as we insert new blocks into it
104104
for (auto &mbb : src) {
105+
assert(all_of(mbb.successors(),
106+
[&](auto *succ) { return succ->getParent() == &src; }));
105107
auto [new_mblock, new_block] = clone_basic_block(mbb, dst);
106108
m2b.insert({new_mblock, new_block});
107-
block_map.insert({&mbb, new_mblock});
109+
block_map.try_emplace(&mbb, new_mblock);
108110
}
109111
for (auto &mbb : dst) {
110-
for (auto *succ : mbb.successors())
112+
for (auto *succ : mbb.successors()) {
111113
replace_uses_of_block_with(mbb, *succ, *block_map.at(succ));
114+
}
112115
}
113116
for (auto &block : dst.getFunction()) {
114117
for (auto &inst : block)
@@ -124,18 +127,6 @@ void create_basic_blocks_for_mfunc(MachineFunction &src, MachineFunction &dst,
124127
return succ->getParent() == mbb.getParent();
125128
});
126129
}));
127-
128-
for (auto &mbb : dst) {
129-
for (auto &minst : mbb) {
130-
if (minst.isBranch()) {
131-
auto dst_mbb = llvm::find_if(minst.operands(),
132-
[](auto &op) { return op.isMBB(); });
133-
assert(dst_mbb != minst.operands_end());
134-
assert(!block_map.count(dst_mbb->getMBB()));
135-
assert(dst_mbb->getMBB()->getParent() == &dst);
136-
}
137-
}
138-
}
139130
}
140131

141132
void fill_module_with_instrs(Module &m, const instr_impl &instrs) {
@@ -284,8 +275,9 @@ void load_registers(BasicBlock &block, BasicBlock::iterator pos, reg2vals &rmap,
284275
for (auto &&[idx, rclass] : reg_stats | views::enumerate) {
285276
auto *array_type = state.getElementType(idx);
286277
auto *arr_idx = ConstantInt::get(ctx, APInt(32, idx));
287-
auto *array_ptr = builder.CreateGEP(
288-
&state, state_arg, ArrayRef<Value *>{arr_idx}, rclass.get_name());
278+
auto *array_ptr = builder.CreateGEP(&state, state_arg,
279+
ArrayRef<Value *>{const_zero, arr_idx},
280+
rclass.get_name());
289281
for (auto &&[reg_idx, val] : rmap | views::filter([&rclass](auto r) {
290282
return rclass.contains(r.first);
291283
}) | views::enumerate) {
@@ -642,8 +634,13 @@ auto generate_branch(const MachineInstr &minst, BasicBlock &bb,
642634
auto name = get_instruction_name(minst, *iinfo);
643635
auto *m = bb.getParent()->getParent();
644636
auto *func = m->getFunction(name);
645-
if (!func)
646-
throw std::runtime_error("Could not find \"" + name + "\" in module");
637+
if (!func) {
638+
std::string instr;
639+
raw_string_ostream ss(instr);
640+
minst.print(ss);
641+
throw std::runtime_error("Could not find \"" + name +
642+
"\" in module: " + instr);
643+
}
647644
auto op_to_val = [&](auto &mop) {
648645
return operand_to_value(mop, bb, target_machine, rmap, reg_stats, insts);
649646
};
@@ -788,8 +785,8 @@ static auto generate_load_store_from_stack(
788785
auto *offset = [&] -> Value * {
789786
if (offset_it == uses.end())
790787
return ConstantInt::get(ctx, APInt(64, 0));
791-
return ConstantInt::get(ctx,
792-
APInt(64, -offset_it->getImm() / reg_bytesize));
788+
auto off = -offset_it->getImm() / reg_bytesize;
789+
return ConstantInt::get(ctx, APInt(64, off));
793790
}();
794791
auto *sp =
795792
get_stack_pointer_value(instrs, rmap, builder, target_machine, reg_stats);
@@ -806,15 +803,21 @@ static auto generate_load_store_from_stack(
806803
auto *iinfo = target_machine.getMCInstrInfo();
807804
auto name = get_instruction_name(minst, *iinfo);
808805
auto *m = bb.getParent()->getParent();
809-
auto *func = m->getFunction(name);
810-
if (!func)
811-
throw std::runtime_error("Could not find \"" + name + "\" in module");
806+
812807
auto *inserted = [&] -> Value * {
813808
// Loading value from stack
814809
if (minst.mayLoad()) {
815810
if (minst.mayStore())
816811
throw std::runtime_error("Unsupported stack manipulation. Instruction "
817812
"can both load and store");
813+
auto *func = m->getFunction(name);
814+
if (!func) {
815+
std::string instr;
816+
raw_string_ostream ss(instr);
817+
minst.print(ss);
818+
throw std::runtime_error("Could not find \"" + name +
819+
"\" in module: " + instr);
820+
}
818821
auto *ret_type = func->getFunctionType()->getReturnType();
819822
return builder.CreateLoad(ret_type, addr);
820823
}
@@ -829,8 +832,9 @@ static auto generate_load_store_from_stack(
829832
return builder.CreateStore(value, addr);
830833
}();
831834
// save result to register
832-
if (!minst.defs().empty())
835+
if (!minst.defs().empty()) {
833836
builder.CreateStore(inserted, rmap.at(minst.defs().begin()->getReg()));
837+
}
834838
return inserted;
835839
}
836840

@@ -929,18 +933,16 @@ static bool is_return(const MachineInstr &minst, const instr_impl &instrs,
929933
static bool is_call(const MachineInstr &minst, const TargetMachine &tmachine) {
930934
if (minst.isCall())
931935
return true;
932-
if (minst.isPseudo())
933-
return false;
934936
// TODO: create mia only once
935937
MCInst inst;
936938
inst.setOpcode(minst.getOpcode());
937939
std::unique_ptr<MCInstrAnalysis> mia(
938940
tmachine.getTarget().createMCInstrAnalysis(tmachine.getMCInstrInfo()));
939941
assert(mia);
940-
return mia->isCall(inst) && std::find_if(minst.operands_begin(),
941-
minst.operands_end(), [](auto &o) {
942-
return o.isGlobal();
943-
}) != minst.operands_end();
942+
return (mia->isCall(inst) || minst.isUnconditionalBranch()) &&
943+
std::find_if(minst.operands_begin(), minst.operands_end(),
944+
[](auto &o) { return o.isGlobal(); }) !=
945+
minst.operands_end();
944946
}
945947
static bool is_indirect_branch(const MachineInstr &minst,
946948
const instr_impl &instrs,
@@ -955,7 +957,9 @@ static bool is_indirect_branch(const MachineInstr &minst,
955957

956958
static bool is_branch(const MachineInstr &minst,
957959
const TargetMachine &tmachine) {
958-
if (minst.isBranch())
960+
if (minst.isBranch() &&
961+
std::find_if(minst.operands_begin(), minst.operands_end(),
962+
[](auto &o) { return o.isMBB(); }) != minst.operands_end())
959963
return true;
960964
// TODO: create mia only once
961965
MCInst inst;
@@ -1017,18 +1021,21 @@ auto generate_instruction(const MachineInstr &minst, BasicBlock &bb,
10171021
if (is_call(minst, target_machine))
10181022
return generate_call(minst, builder, bb, rmap, target_machine, state,
10191023
reg_stats, functions_nop);
1020-
if (minst.mayLoadOrStore()) {
1021-
// Instructions that are not considered stack manipulation are generated
1022-
// just like any other instruction
1023-
if (is_stack_manipulation(minst, sptrack))
1024-
return generate_load_store_from_stack(minst, builder, bb, rmap, instrs,
1025-
target_machine, state, reg_stats);
1024+
if (is_stack_manipulation(minst, sptrack)) {
1025+
return generate_load_store_from_stack(minst, builder, bb, rmap, instrs,
1026+
target_machine, state, reg_stats);
10261027
}
1028+
10271029
// TODO: track stack pointerS
10281030
auto *m = bb.getParent()->getParent();
10291031
auto *func = m->getFunction(name);
1030-
if (!func)
1031-
throw std::runtime_error("Could not find \"" + name + "\" in module");
1032+
if (!func) {
1033+
std::string instr;
1034+
raw_string_ostream ss(instr);
1035+
minst.print(ss);
1036+
throw std::runtime_error("Could not find \"" + name +
1037+
"\" in module: " + instr);
1038+
}
10321039
auto uses = minst.uses();
10331040
bool uses_sp = ranges::find_if(uses, [&](auto &u) {
10341041
return u.isReg() && sptrack.is_stack_pointer(u.getReg());
@@ -1037,8 +1044,7 @@ auto generate_instruction(const MachineInstr &minst, BasicBlock &bb,
10371044
!minst.defs().empty() && minst.defs().begin()->isReg() && uses_sp;
10381045
if (is_stack_pointer_manipulation) {
10391046
auto dst = minst.defs().begin()->getReg();
1040-
if (sptrack.is_stack_pointer(dst))
1041-
sptrack.add(dst);
1047+
sptrack.add(dst);
10421048
return generate_stack_pointer_modification(
10431049
minst, builder, bb, target_machine, rmap, instrs, reg_stats);
10441050
}
@@ -1091,8 +1097,12 @@ void fill_ir_for_bb(MachineBasicBlock &mbb, reg2vals &rmap,
10911097
auto last = std::prev(mbb.end());
10921098
if (!is_branch(*last, target_machine) &&
10931099
!is_return(*last, instrs, target_machine)) {
1094-
auto succ = std::next(mbb.getIterator());
1095-
builder.CreateBr(m2b[std::addressof(*succ)]);
1100+
if (is_call(*last, target_machine)) {
1101+
builder.CreateRetVoid();
1102+
} else {
1103+
auto succ = std::next(mbb.getIterator());
1104+
builder.CreateBr(m2b[std::addressof(*succ)]);
1105+
}
10961106
}
10971107
}
10981108

lib/mctomir/mctomir-transform.cpp

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
#include <cstdint>
44
#include <llvm/ADT/STLExtras.h>
55
#include <llvm/ADT/StringExtras.h>
6+
#include <llvm/CodeGen/GlobalISel/GISelValueTracking.h>
7+
#include <llvm/CodeGen/GlobalISel/InstructionSelector.h>
68
#include <llvm/CodeGen/MIRParser/MIRParser.h>
79
#include <llvm/CodeGen/MIRPrinter.h>
810
#include <llvm/CodeGen/MachineInstrBuilder.h>
11+
#include <llvm/CodeGen/TargetOpcodes.h>
912
#include <llvm/IR/LegacyPassManager.h>
13+
#include <llvm/MC/MCInstrAnalysis.h>
1014
#include <llvm/MC/TargetRegistry.h>
1115
#include <llvm/Object/ELFObjectFile.h>
1216
#include <llvm/Object/ObjectFile.h>
17+
#include <llvm/Support/CodeGenCoverage.h>
1318
#include <llvm/Support/Error.h>
1419
#include <llvm/Support/ErrorHandling.h>
1520
#include <llvm/Target/TargetMachine.h>
@@ -266,6 +271,31 @@ Error translator_t::translate_instructions() {
266271
return Error::success();
267272
}
268273

274+
static bool is_tail_call(const MCInst &instr, const MachineBasicBlock *current,
275+
const MachineBasicBlock *target,
276+
const MCInstrAnalysis &mi_analysis) {
277+
return mi_analysis.isUnconditionalBranch(instr) &&
278+
target->getParent() != current->getParent();
279+
}
280+
static bool is_call(const MCInst &instr, const MachineBasicBlock *current,
281+
const MachineBasicBlock *target,
282+
const MCInstrAnalysis &mi_analysis) {
283+
return mi_analysis.isCall(instr) ||
284+
is_tail_call(instr, current, target, mi_analysis);
285+
}
286+
287+
void translator_t::fill_operands(MachineInstrBuilder &builder,
288+
const MCInst &inst, const MCInstrDesc &desc,
289+
bool is_branch) {
290+
for (unsigned i = 0; i < inst.getNumOperands(); ++i) {
291+
if (is_branch && (i == inst.getNumOperands() - 1) &&
292+
inst.getOperand(i).isImm())
293+
break;
294+
const MCOperand &mc_op = inst.getOperand(i);
295+
add_operand_to_mib(builder, mc_op, i, desc);
296+
}
297+
}
298+
269299
MachineInstr *translator_t::create_machine_instr(const translated_inst &tinst,
270300
MachineBasicBlock *mbb) {
271301
if (!tii || !mbb)
@@ -276,36 +306,40 @@ MachineInstr *translator_t::create_machine_instr(const translated_inst &tinst,
276306
const MCInstrDesc &desc = tii->get(opcode);
277307
uint64_t target;
278308
bool is_branch = res.mi_analysis->evaluateBranch(inst, 0, 4, target);
279-
MachineInstrBuilder mib = BuildMI(*mbb, mbb->end(), DebugLoc(), desc);
280-
281-
for (unsigned i = 0; i < inst.getNumOperands(); ++i) {
282-
if (is_branch && (i == inst.getNumOperands() - 1) &&
283-
inst.getOperand(i).isImm())
284-
break;
285-
const MCOperand &mc_op = inst.getOperand(i);
286-
add_operand_to_mib(mib, mc_op, i, desc);
287-
}
288309

289310
if (is_branch) {
290-
// TODO(Ilyagavilin): deduce operands in other way
291-
if (inst.getNumOperands() > 0 &&
292-
inst.getOperand(inst.getNumOperands() - 1).isImm()) {
293-
auto target_it = address_to_mbb.find(target + tinst.address);
294-
if (target_it != address_to_mbb.end()) {
295-
if (res.mi_analysis->isCall(inst))
296-
mib.addGlobalAddress(&target_it->second->getParent()->getFunction(),
297-
0);
298-
else
299-
mib.addMBB(target_it->second);
300-
} else {
301-
std::string instr;
302-
raw_string_ostream ss(instr);
303-
mib->print(ss);
304-
std::cerr << "Warning: destination not found for instruction:\n\t"
305-
<< instr << '\n';
311+
assert(inst.getNumOperands() > 0 &&
312+
inst.getOperand(inst.getNumOperands() - 1).isImm());
313+
auto target_it = address_to_mbb.find(target + tinst.address);
314+
if (target_it != address_to_mbb.end()) {
315+
if (mctomir::is_call(inst, mbb, target_it->second, *res.mi_analysis)) {
316+
bool is_tail = mctomir::is_tail_call(inst, mbb, target_it->second,
317+
*res.mi_analysis);
318+
319+
auto mib = is_tail ? BuildMI(*mbb, mbb->end(), DebugLoc(),
320+
tii->get(TargetOpcode::G_BR))
321+
: BuildMI(*mbb, mbb->end(), DebugLoc(), desc);
322+
if (!is_tail)
323+
fill_operands(mib, inst, desc, is_branch);
324+
mib.addGlobalAddress(&target_it->second->getParent()->getFunction(), 0);
325+
326+
return mib.getInstr();
306327
}
328+
MachineInstrBuilder mib = BuildMI(*mbb, mbb->end(), DebugLoc(), desc);
329+
fill_operands(mib, inst, desc, is_branch);
330+
mib.addMBB(target_it->second);
331+
mbb->addSuccessor(target_it->second);
332+
return mib.getInstr();
333+
} else {
334+
std::string instr;
335+
raw_string_ostream ss(instr);
336+
std::cerr << "Warning: destination not found for instruction:\n\t"
337+
<< instr << '\n';
307338
}
308339
}
340+
MachineInstrBuilder mib = BuildMI(*mbb, mbb->end(), DebugLoc(), desc);
341+
342+
fill_operands(mib, inst, desc, is_branch);
309343

310344
return mib.getInstr();
311345
}
@@ -356,12 +390,14 @@ Error translator_t::link_machine_basic_blocks() {
356390
if (res.mi_analysis->evaluateBranch(last_inst, last_t_inst->address, 0,
357391
target)) {
358392
auto target_it = address_to_mbb.find(target);
359-
if (target_it != address_to_mbb.end()) {
360-
mbb->addSuccessor(target_it->second);
393+
if (target_it != address_to_mbb.end() &&
394+
!mctomir::is_call(last_inst, mbb, target_it->second,
395+
*res.mi_analysis)) {
396+
// mbb->addSuccessor(target_it->second);
361397
} else {
362398
MachineBasicBlock *target_mbb =
363399
get_or_create_mbb_for_address(target, *finfo.mfunc);
364-
mbb->addSuccessor(target_mbb);
400+
// mbb->addSuccessor(target_mbb);
365401
}
366402
}
367403
if (!res.mi_analysis->isUnconditionalBranch(last_inst) &&

0 commit comments

Comments
 (0)