36#include <gtest/gtest.h>
59 std::string stdout_text;
60 std::string stderr_text;
78 function.
name =
"choose";
85 flag.
kind = Compiler_IR_Slot_Kind::Parameter;
91 value.kind = Compiler_IR_Slot_Kind::Local;
97 entry.
label =
"entry";
100 zero.
kind = Compiler_IR_Instruction_Kind::Constant;
123 exit.predecessors.append(3);
130 one.
kind = Compiler_IR_Instruction_Kind::Constant;
141 then_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
155 join_block.terminator.kind = Compiler_IR_Terminator_Kind::Return;
166 two.
kind = Compiler_IR_Instruction_Kind::Constant;
177 else_block.terminator.kind = Compiler_IR_Terminator_Kind::Jump;
181 function.
blocks.append(entry);
194 function.
name =
"add_one";
201 param.kind = Compiler_IR_Slot_Kind::Parameter;
207 local.
kind = Compiler_IR_Slot_Kind::Local;
213 entry.
label =
"entry";
222 store.
kind = Compiler_IR_Instruction_Kind::Store;
228 load_x.
kind = Compiler_IR_Instruction_Kind::Load;
240 add.kind = Compiler_IR_Instruction_Kind::Binary;
242 add.op = Compiler_Operator_Kind::Plus;
243 add.operands.append(2);
244 add.operands.append(3);
252 exit.predecessors.append(0);
254 function.
blocks.append(entry);
266 global.kind = Compiler_IR_Slot_Kind::Global;
268 module.global_slots.append(global);
271 module.functions.append(function);
275 top->name =
"<top-level>";
276 top->entry_block = 0;
278 top->next_value_id = 3;
282 entry.
label =
"entry";
297 call.
kind = Compiler_IR_Instruction_Kind::Call;
313 exit.predecessors.append(0);
315 top->blocks.append(entry);
316 top->blocks.append(
exit);
317 module.top_level = top;
328 top->name =
"<top-level>";
329 top->entry_block = 0;
331 top->next_value_id = 3;
335 entry.
label =
"entry";
338 lhs.
kind = Compiler_IR_Instruction_Kind::Constant;
344 rhs.
kind = Compiler_IR_Instruction_Kind::Constant;
350 div.kind = Compiler_IR_Instruction_Kind::Binary;
352 div.op = Compiler_Operator_Kind::Slash;
353 div.operands.append(1);
354 div.operands.append(2);
362 exit.predecessors.append(0);
364 top->blocks.append(entry);
365 top->blocks.append(
exit);
366 module.top_level = top;
371 read_text(
const std::filesystem::path & path)
373 std::ifstream
in(path);
374 return std::string((std::istreambuf_iterator<char>(
in)),
375 std::istreambuf_iterator<char>());
379 write_text(
const std::filesystem::path & path,
380 const std::string & text)
382 std::ofstream
out(path);
390 for (
const char ch : text)
404 return std::system(
"command -v cc >/dev/null 2>&1") == 0;
411 return static_cast<long long>(
_getpid());
413 return static_cast<long long>(
getpid());
417 std::filesystem::path
419 const std::string & extension)
428 static std::atomic<unsigned long long>
counter{0};
429 const auto nonce = std::to_string(
431 "_" + std::to_string(process_id()) +
432 "_" + std::to_string(
counter++);
433 return std::filesystem::temp_directory_path()
440 Command_Result result;
458 const std::string &
extra_c =
"")
465 "cc -std=c11 -Wall -Wextra -pedantic "
484 module.functions.append(&source);
501 GTEST_SKIP() <<
"No se encontrĂ³ `cc` en el host";
503 auto module = make_module_with_top_level_call();
514 EXPECT_NE(executed.stdout_text.find(
"Result = Unit"), std::string::npos);
515 EXPECT_NE(executed.stdout_text.find(
"g0 answer = Int(42)"), std::string::npos);
518 delete module.functions.access(0);
519 delete module.top_level;
525 GTEST_SKIP() <<
"No se encontrĂ³ `cc` en el host";
529 module.functions.append(&source);
539 " " +
emitted.module_struct_name +
" module;\n"
540 " " +
emitted.module_init_symbol +
"(&module);\n"
541 " " +
emitted.value_type_name +
" args[1];\n"
542 " args[0] = " +
emitted.c_prefix +
"_make_bool(false);\n"
543 " " +
emitted.value_type_name +
" result = "
544 +
emitted.function_symbols.access(0) +
"(&module, args, 1u);\n"
545 " " +
emitted.print_value_symbol +
"(stdout, result);\n"
546 " fputc('\\n', stdout);\n"
552 EXPECT_EQ(executed.stdout_text,
"Int(2)\n");
559 GTEST_SKIP() <<
"No se encontrĂ³ `cc` en el host";
561 auto module = make_divide_by_zero_top_level_module();
572 EXPECT_NE(executed.stderr_text.find(
"division by zero"), std::string::npos);
574 delete module.top_level;
Portable C backend that emits standalone C from Compiler_IR_Model.H.
size_t size_t int32_t value
size_t size_t int32_t * out
T & append()
Allocate a new entry to the end of array.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::string shell_quote(const std::string &s)
const char * extension(Frame_Output_Format format) noexcept
Compiler_SSA_Block & block(Compiler_SSA_Function &function, const Compiler_SSA_Block_Id id)
Main namespace for Aleph-w library functions.
void exit(const char *file, int line, const char *format,...)
Print a message and exit the program.
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
Compiler_C_Backend_Emission compiler_emit_c_module(const Compiler_IR_Module *module, const Compiler_C_Backend_Options &options={}, const Compiler_Type_Context *types=nullptr)
Convenience wrapper that emits one IR module to portable C.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
double add(double a, double b)
double div(double a, double b)
static struct argp_option options[]
Result of one C backend emission request.
Options that control one C backend emission request.
std::string module_name
Prefix used to derive stable C identifiers.
One basic block of IR instructions.
std::string label
Deterministic debug label.
Compiler_IR_Terminator terminator
Explicit block terminator.
DynArray< Compiler_IR_Instruction > instructions
Linear instruction list.
Compiler_IR_Block_Id id
Stable block id.
Lowered IR for one function or top-level body.
Compiler_IR_Value_Id next_value_id
Next value id to allocate while lowering.
DynArray< Compiler_IR_Block > blocks
Basic blocks in deterministic id order.
std::string name
Debug or source-level name.
Compiler_IR_Block_Id exit_block
Canonical exit block.
Compiler_IR_Block_Id entry_block
Canonical entry block.
DynArray< Compiler_IR_Slot > local_slots
Parameter/local slots in stable order.
Compiler_IR_Function_Id id
Stable function id within the module.
One instruction producing an optional explicit result value.
std::string text
Constant spelling or debug payload.
Compiler_IR_Instruction_Kind kind
Instruction category.
Compiler_IR_Value_Id result_id
Produced value id, or 0 for void instructions.
DynArray< Compiler_IR_Value_Id > operands
Input values in deterministic order.
Compiler_IR_Local_Slot_Id local_slot_id
Referenced local/parameter slot, when relevant.
Lowered IR module with shared global slots and functions.
One storage slot used by the IR.
std::string name
Debug name of the slot.
size_t id
Stable slot id within its storage space.
Compiler_IR_Slot_Kind kind
Slot storage category.
Compiler_IR_Terminator_Kind kind
Terminator category.
DynArray< Compiler_IR_Block_Id > successors
Successor blocks in deterministic order.
Compiler_IR_Value_Id condition_value
Branch condition value, if any.
Compiler_IR_Value_Id return_value
Return value, if any.
Compiler_SSA_Block_Id id
Dense SSA block id.
std::string label
Deterministic debug label.
Compiler_SSA_Terminator terminator
Explicit block terminator.
Compiler_IR_Terminator_Kind kind
Terminator category.