diff --git a/include/IR/IRBuilder.h b/include/IR/IRBuilder.h index fa0816d..74a7c74 100644 --- a/include/IR/IRBuilder.h +++ b/include/IR/IRBuilder.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include "IR_basic.h" #include "ast/astnode_visitor.h" +#include "tools.h" class IRBuilder : public ASTNodeVirturalVisitor { friend std::shared_ptr BuildIR(std::shared_ptr src); std::shared_ptr prog; @@ -17,6 +19,9 @@ class IRBuilder : public ASTNodeVirturalVisitor { std::string cur_continue_target; bool just_encountered_jmp; std::shared_ptr global_scope; + size_t const_str_counter; + std::unordered_map const_str_dict; + size_t const_arr_counter; public: IRBuilder() { @@ -25,6 +30,8 @@ class IRBuilder : public ASTNodeVirturalVisitor { is_in_class_def = false; is_in_func_def = false; just_encountered_jmp = false; + const_str_counter = 0; + const_arr_counter = 0; } // Structural AST Nodes void ActuralVisit(FuncDef_ASTNode *node) override; @@ -70,6 +77,61 @@ class IRBuilder : public ASTNodeVirturalVisitor { void ActuralVisit(FunctionCallExpr_ASTNode *node) override; void ActuralVisit(FormattedStringExpr_ASTNode *node) override; void ActuralVisit(ConstantExpr_ASTNode *node) override; + std::string ArrangeConstArrDfs(BlockItem &blk, ConstantExpr_ASTNode *node, size_t depth, size_t total_level, + LLVMType basetype) { + if (std::holds_alternative(node->value)) { + node->accept(this); + return node->IR_result_full; + } + LLVMType ty; + size_t elem_size; + if (depth + 1 == total_level) { + ty = basetype; + if (std::holds_alternative(ty)) { + elem_size = (std::get(ty).bits + 7) / 8; + } else if (std::holds_alternative(ty)) { + elem_size = 4; + } else { + throw std::runtime_error("Unexpected type in const array"); + } + } else { + ty = LLVMIRPTRType(); + elem_size = 4; + } + auto& sub_nodes=std::get>>(node->value); + std::string array_head = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto allocate_action=std::make_shared(); + blk.actions.push_back(allocate_action); + allocate_action->func_name_raw=".builtin.AllocateArray"; + allocate_action->result_full=array_head; + allocate_action->return_type=LLVMIRPTRType(); + allocate_action->args_ty.push_back(LLVMIRIntType(32)); + allocate_action->args_val_full.push_back(std::to_string(elem_size)); + allocate_action->args_ty.push_back(LLVMIRIntType(32)); + allocate_action->args_val_full.push_back(std::to_string(sub_nodes.size())); + for(size_t i=0;i(); + blk.actions.push_back(ptr_cal); + ptr_cal->result_full=addr; + ptr_cal->ty=ty; + ptr_cal->ptr_full=array_head; + ptr_cal->indices.push_back(std::to_string(i)); + auto store_action=std::make_shared(); + blk.actions.push_back(store_action); + store_action->ty=ty; + store_action->ptr_full=addr; + store_action->value_full=ret; + } + + return allocate_action->result_full; + } + void ArrangeConstArr(BlockItem &blk, ConstantExpr_ASTNode *node) { + ArrayType tp = std::get(node->expr_type_info); + std::dynamic_pointer_cast(blk.exit_action)->value = + ArrangeConstArrDfs(blk, node, 0, tp.level, Type_AST2LLVM(tp.basetype)); + } }; std::shared_ptr BuildIR(std::shared_ptr src); \ No newline at end of file diff --git a/include/IR/IR_basic.h b/include/IR/IR_basic.h index bf5b330..090dc2e 100644 --- a/include/IR/IR_basic.h +++ b/include/IR/IR_basic.h @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include #include "ast/astnode.h" @@ -192,6 +194,7 @@ class StoreAction : public ActionItem { } }; class GetElementPtrAction : public ActionItem { + friend class IRBuilder; std::string result_full; LLVMType ty; std::string ptr_full; @@ -241,6 +244,7 @@ class ICMPAction : public ActionItem { }; class BlockItem : public LLVMIRItemBase { friend class IRBuilder; + friend void ArrangeConstArr(BlockItem &blk, class ConstantExpr_ASTNode *node, size_t &tmp_var_counter); std::string label_full; std::vector> actions; std::shared_ptr exit_action; @@ -439,9 +443,41 @@ class FunctionDeclareItem : public LLVMIRItemBase { os << ")\n"; } }; +class ConstStrItem : public LLVMIRItemBase { + friend class IRBuilder; + std::string string_raw; + size_t const_str_id; + static std::string Escape(const std::string &src) { + std::stringstream ss; + for (auto &ch : src) { + if (ch == '\n') { + ss << "\\0A"; + } else if (ch == '\t') { + ss << "\\09"; + } else if (ch == '\r') { + ss << "\\0D"; + } else if (ch == '\"') { + ss << "\\22"; + } else if (ch == '\\') { + ss << "\\5C"; + } else { + ss << ch; + } + } + return ss.str(); + } + + public: + ConstStrItem() = default; + void RecursivePrint(std::ostream &os) const { + os << "@.str." << const_str_id << " = private unnamed_addr constant [" << string_raw.size() + 1 << " x i8] c\"" + << Escape(string_raw) << "\\00\"\n"; + } +}; class ModuleItem : public LLVMIRItemBase { friend class IRBuilder; friend std::shared_ptr BuildIR(std::shared_ptr src); + std::vector> const_strs; std::vector> function_declares; std::vector> type_defs; std::vector> global_var_defs; @@ -450,6 +486,9 @@ class ModuleItem : public LLVMIRItemBase { public: ModuleItem() = default; void RecursivePrint(std::ostream &os) const { + for (auto &item : const_strs) { + item->RecursivePrint(os); + } for (auto &item : function_declares) { item->RecursivePrint(os); } diff --git a/include/ast/semantic_visitor.h b/include/ast/semantic_visitor.h index 521cc71..928ba45 100644 --- a/include/ast/semantic_visitor.h +++ b/include/ast/semantic_visitor.h @@ -1,9 +1,9 @@ #pragma once #include "astnode.h" +#include "astnode_visitor.h" #include "expr_astnode.h" #include "statement_astnode.h" #include "structural_astnode.h" -#include "astnode_visitor.h" class ASTSemanticCheckVisitor : public ASTNodeVirturalVisitor { bool is_in_func_def; @@ -21,7 +21,7 @@ class ASTSemanticCheckVisitor : public ASTNodeVirturalVisitor { } public: - ASTSemanticCheckVisitor() : is_in_func_def(false), loop_level(0) {} + ASTSemanticCheckVisitor() : is_in_func_def(false), loop_level(0), is_in_class_def(false) {} // Structural AST Nodes void ActuralVisit(FuncDef_ASTNode *node) override; void ActuralVisit(ClassDef_ASTNode *node) override; diff --git a/include/tools.h b/include/tools.h index 8ee8d4b..98bd277 100644 --- a/include/tools.h +++ b/include/tools.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -172,4 +173,32 @@ inline LLVMType Type_AST2LLVM(const ExprTypeInfo &src) { if (tname == "int") return LLVMIRIntType(32); if (tname == "void") return LLVMVOIDType(); return LLVMIRPTRType(); +} + +inline std::string StringLiteralDeEscape(const std::string src) { + std::stringstream ss; + for (size_t i = 1; i < src.size() - 1; i++) { + if (src[i] != '\\') + ss << src[i]; + else { + i++; + if (src[i] == 'n') + ss << '\n'; + else if (src[i] == 'r') + ss << '\r'; + else if (src[i] == 't') + ss << '\t'; + else if (src[i] == '\\') + ss << '\\'; + else if (src[i] == '\'') + ss << '\''; + else if (src[i] == '\"') + ss << '\"'; + else if (src[i] == '0') + ss << '\0'; + else + throw std::runtime_error("Invalid escape character"); + } + } + return ss.str(); } \ No newline at end of file diff --git a/src/IR/IRBuilder.cpp b/src/IR/IRBuilder.cpp index 0853c3d..8fcd478 100644 --- a/src/IR/IRBuilder.cpp +++ b/src/IR/IRBuilder.cpp @@ -103,11 +103,20 @@ void IRBuilder::ActuralVisit(DefinitionStatement_ASTNode *node) { var_def->name_full = "%.var.local." + std::to_string(node->current_scope->scope_id) + "." + var.first + ".addrkp"; if (var.second) { var.second->accept(this); + std::string init_var = var.second->IR_result_full; + if (init_var[0] == '#') { + init_var = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = init_var; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = var.second->IR_result_full.substr(1); + } auto act = std::make_shared(); cur_block->actions.push_back(act); act->ty = var_def->type; act->ptr_full = var_def->name_full; - act->value_full = var.second->IR_result_full; + act->value_full = init_var; } } } @@ -309,7 +318,74 @@ void IRBuilder::ActuralVisit(SuiteStatement_ASTNode *node) { // Expression AST Nodes void IRBuilder::ActuralVisit(NewArrayExpr_ASTNode *node) { - // TODO: Implement function body + if (node->initial_value) { + node->initial_value->accept(this); // Just visit it + node->IR_result_full = node->initial_value->IR_result_full; + return; + } + std::string constructing_func_name = ".constarr." + std::to_string(const_arr_counter++); + auto cons_func = std::make_shared(); + prog->function_defs.push_back(cons_func); + cons_func->func_name_raw = constructing_func_name; + cons_func->return_type = LLVMIRPTRType(); + auto block = std::make_shared(); + cons_func->basic_blocks.push_back(block); + block->label_full = "label_constarr_" + std::to_string(const_arr_counter - 1); + block->exit_action = std::make_shared(); + std::dynamic_pointer_cast(block->exit_action)->type = LLVMIRPTRType(); + + std::vector dim_size_info; + for (size_t i = 0; i < node->dim_size.size(); i++) { + if (!(node->dim_size[i])) break; + node->dim_size[i]->accept(this); + dim_size_info.push_back(node->dim_size[i]->IR_result_full); + } + int dims_with_size = dim_size_info.size(); + int element_size = 4; + if (dims_with_size == node->dim_size.size()) { + ArrayType tp = std::get(node->expr_type_info); + std::string base_type = tp.basetype; + if (base_type == "bool") element_size = 1; + } + + auto dim_info = std::make_shared(); + std::string dim_info_var = "%.var.tmp." + std::to_string(tmp_var_counter++); + block->actions.push_back(dim_info); + dim_info->num = dims_with_size; + dim_info->name_full = dim_info_var; + dim_info->type = LLVMIRIntType(32); + for (size_t i = 0; i < dim_size_info.size(); i++) { + std::string cur_ptr = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto get_addr = std::make_shared(); + block->actions.push_back(get_addr); + get_addr->result_full = cur_ptr; + get_addr->ty = LLVMIRIntType(32); + get_addr->ptr_full = dim_info_var; + get_addr->indices.push_back(std::to_string(i)); + auto store_act = std::make_shared(); + block->actions.push_back(store_act); + store_act->ty = LLVMIRIntType(32); + store_act->ptr_full = cur_ptr; + store_act->value_full = dim_size_info[i]; + } + auto allocate_call = std::make_shared(); + block->actions.push_back(allocate_call); + allocate_call->func_name_raw = ".builtin.RecursiveAllocateArray"; + allocate_call->return_type = LLVMIRPTRType(); + std::string res = "%.var.tmp." + std::to_string(tmp_var_counter++); + allocate_call->result_full = res; + allocate_call->args_ty.push_back(LLVMIRIntType(32)); + allocate_call->args_val_full.push_back(std::to_string(dims_with_size)); + allocate_call->args_ty.push_back(LLVMIRIntType(32)); + allocate_call->args_val_full.push_back(std::to_string(element_size)); + allocate_call->args_ty.push_back(LLVMIRPTRType()); + allocate_call->args_val_full.push_back(dim_info_var); + auto ret = std::make_shared(); + block->exit_action = ret; + ret->type = LLVMIRPTRType(); + ret->value = res; + + node->IR_result_full = "#" + constructing_func_name; } void IRBuilder::ActuralVisit(NewConstructExpr_ASTNode *node) { @@ -325,7 +401,44 @@ void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) { } void IRBuilder::ActuralVisit(IndexExpr_ASTNode *node) { - // TODO: Implement function body + node->base->accept(this); + std::string cur_val = node->base->IR_result_full; + std::string cur_addr; + for (size_t i = 0; i < node->indices.size(); i++) { + LLVMType cur_ty; + if (i + 1 < node->indices.size()) + cur_ty = LLVMIRPTRType(); + else { + ArrayType tp = std::get(node->base->expr_type_info); + if (tp.basetype == "bool") + cur_ty = LLVMIRIntType(1); + else if (tp.basetype == "int") + cur_ty = LLVMIRIntType(32); + else + cur_ty = LLVMIRPTRType(); + } + node->indices[i]->accept(this); + std::string idx = node->indices[i]->IR_result_full; + cur_addr = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto addr_cal = std::make_shared(); + cur_block->actions.push_back(addr_cal); + addr_cal->result_full = cur_addr; + addr_cal->ty = cur_ty; + addr_cal->ptr_full = cur_val; + addr_cal->indices.push_back(idx); + if (i + 1 == node->indices.size() && node->is_requiring_lvalue) break; + auto val_load = std::make_shared(); + cur_val = "%.var.tmp." + std::to_string(tmp_var_counter++); + cur_block->actions.push_back(val_load); + val_load->result_full = cur_val; + val_load->ty = cur_ty; + val_load->ptr_full = cur_addr; + } + if (node->is_requiring_lvalue) { + node->IR_result_full = cur_addr; + } else { + node->IR_result_full = cur_val; + } } void IRBuilder::ActuralVisit(SuffixExpr_ASTNode *node) { @@ -605,14 +718,24 @@ void IRBuilder::ActuralVisit(AssignExpr_ASTNode *node) { node->dest->accept(this); node->src->accept(this); auto act = std::make_shared(); - cur_block->actions.push_back(act); act->ptr_full = node->dest->IR_result_full; - act->value_full = node->src->IR_result_full; + std::string src = node->src->IR_result_full; + if (src[0] == '#') { + src = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = src; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = node->src->IR_result_full.substr(1); + } + cur_block->actions.push_back(act); + act->value_full = src; act->ty = Type_AST2LLVM(node->src->expr_type_info); } void IRBuilder::ActuralVisit(ThisExpr_ASTNode *node) { // TODO: Implement function body + throw std::runtime_error("this not supported"); } void IRBuilder::ActuralVisit(ParenExpr_ASTNode *node) { @@ -676,6 +799,7 @@ void IRBuilder::ActuralVisit(FunctionCallExpr_ASTNode *node) { void IRBuilder::ActuralVisit(FormattedStringExpr_ASTNode *node) { // TODO: Implement function body + throw std::runtime_error("formatted string not supported"); } void IRBuilder::ActuralVisit(ConstantExpr_ASTNode *node) { @@ -689,16 +813,33 @@ void IRBuilder::ActuralVisit(ConstantExpr_ASTNode *node) { } else if (std::holds_alternative(val)) { node->IR_result_full = std::to_string(int(std::get(val))); } else if (std::holds_alternative(val)) { - // TODO: string constant - throw std::runtime_error("String constant not supported"); + std::string str = StringLiteralDeEscape(std::get(val)); + if (const_str_dict.find(str) == const_str_dict.end()) { + const_str_dict[str] = const_str_counter++; + auto const_str_item = std::make_shared(); + prog->const_strs.push_back(const_str_item); + const_str_item->string_raw = str; + const_str_item->const_str_id = const_str_dict[str]; + } + node->IR_result_full = "@.str." + std::to_string(const_str_dict[str]); } else if (std::holds_alternative(val)) { node->IR_result_full = "null"; } else { throw std::runtime_error("unknown constant type"); } } else { - // TODO: array constant - throw std::runtime_error("Array constant not supported"); + std::string constructing_func_name = ".constarr." + std::to_string(const_arr_counter++); + auto cons_func = std::make_shared(); + prog->function_defs.push_back(cons_func); + cons_func->func_name_raw = constructing_func_name; + cons_func->return_type = LLVMIRPTRType(); + auto block = std::make_shared(); + cons_func->basic_blocks.push_back(block); + block->label_full = "label_constarr_" + std::to_string(const_arr_counter - 1); + block->exit_action = std::make_shared(); + std::dynamic_pointer_cast(block->exit_action)->type = LLVMIRPTRType(); + ArrangeConstArr(*block, node); + node->IR_result_full = "#" + constructing_func_name; } } @@ -720,6 +861,19 @@ std::shared_ptr BuildIR(std::shared_ptr src) { tmp->return_type = LLVMVOIDType(); tmp->args.push_back(LLVMIRPTRType()); visitor.prog->function_declares.push_back(tmp); + tmp = std::make_shared(); + tmp->func_name_raw = ".builtin.AllocateArray"; + tmp->return_type = LLVMIRPTRType(); + tmp->args.push_back(LLVMIRIntType(32)); + tmp->args.push_back(LLVMIRIntType(32)); + visitor.prog->function_declares.push_back(tmp); + tmp = std::make_shared(); + tmp->func_name_raw = ".builtin.RecursiveAllocateArray"; + tmp->return_type = LLVMIRPTRType(); + tmp->args.push_back(LLVMIRIntType(32)); + tmp->args.push_back(LLVMIRIntType(32)); + tmp->args.push_back(LLVMIRPTRType()); + visitor.prog->function_declares.push_back(tmp); visitor.global_scope = std::dynamic_pointer_cast(src->current_scope); if (!(visitor.global_scope)) throw std::runtime_error("global scope not found"); visitor.visit(src.get()); diff --git a/src/IR/builtin.c b/src/IR/builtin.c index e8490d3..938b108 100644 --- a/src/IR/builtin.c +++ b/src/IR/builtin.c @@ -113,6 +113,14 @@ void* _builtin_RecursiveAllocateArray(int dims_with_size, int element_size, int* } return res; } +void* _builtin_AllocateArray(int element_size, int element_num) { + void* res=malloc(element_size*element_num+4); + ((unsigned char*)res)[0] = element_num&0xff; + ((unsigned char*)res)[1] = (element_num>>8)&0xff; + ((unsigned char*)res)[2] = (element_num>>16)&0xff; + ((unsigned char*)res)[3] = (element_num>>24)&0xff; + return ((char*)res)+4; +} // void* _builtin_AllocateArray(int total_dimensions,int basic_element_size,...) { // va_list args; // va_start(args, basic_element_size); diff --git a/src/IR/builtin.ll b/src/IR/builtin.ll index f35695f..5e67ce7 100644 --- a/src/IR/builtin.ll +++ b/src/IR/builtin.ll @@ -35,7 +35,7 @@ declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 define dso_local noalias noundef ptr @string.substring(ptr nocapture noundef readonly %0, i32 noundef %1, i32 noundef %2) local_unnamed_addr #2 { %4 = sub nsw i32 %2, %1 %5 = add nsw i32 %4, 1 - %6 = tail call ptr @malloc(i32 noundef %5) #10 + %6 = tail call ptr @malloc(i32 noundef %5) #11 %7 = getelementptr i8, ptr %0, i32 %1 %8 = icmp sgt i32 %4, 0 br i1 %8, label %11, label %9 @@ -62,10 +62,10 @@ declare dso_local noalias noundef ptr @malloc(i32 noundef) local_unnamed_addr #3 ; Function Attrs: nofree nounwind define dso_local i32 @string.parseInt(ptr nocapture noundef readonly %0) local_unnamed_addr #4 { %2 = alloca i32, align 4 - call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %2) #11 - %3 = call i32 (ptr, ptr, ...) @sscanf(ptr noundef %0, ptr noundef nonnull @.str, ptr noundef nonnull %2) #12 + call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %2) #12 + %3 = call i32 (ptr, ptr, ...) @sscanf(ptr noundef %0, ptr noundef nonnull @.str, ptr noundef nonnull %2) #13 %4 = load i32, ptr %2, align 4, !tbaa !12 - call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %2) #11 + call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %2) #12 ret i32 %4 } @@ -82,7 +82,7 @@ define dso_local i32 @string.ord(ptr nocapture noundef readonly %0, i32 noundef ; Function Attrs: nounwind define dso_local void @print(ptr noundef %0) local_unnamed_addr #6 { - %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.1, ptr noundef %0) #13 + %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.1, ptr noundef %0) #14 ret void } @@ -90,26 +90,26 @@ declare dso_local i32 @printf(ptr noundef, ...) local_unnamed_addr #7 ; Function Attrs: nounwind define dso_local void @println(ptr noundef %0) local_unnamed_addr #6 { - %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.2, ptr noundef %0) #13 + %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.2, ptr noundef %0) #14 ret void } ; Function Attrs: nounwind define dso_local void @printInt(i32 noundef %0) local_unnamed_addr #6 { - %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str, i32 noundef %0) #13 + %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str, i32 noundef %0) #14 ret void } ; Function Attrs: nounwind define dso_local void @printlnInt(i32 noundef %0) local_unnamed_addr #6 { - %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.3, i32 noundef %0) #13 + %2 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull @.str.3, i32 noundef %0) #14 ret void } ; Function Attrs: nofree nounwind define dso_local noalias noundef ptr @toString(i32 noundef %0) local_unnamed_addr #4 { - %2 = tail call dereferenceable_or_null(15) ptr @malloc(i32 noundef 15) #10 - %3 = tail call i32 (ptr, ptr, ...) @sprintf(ptr noundef nonnull dereferenceable(1) %2, ptr noundef nonnull dereferenceable(1) @.str, i32 noundef %0) #12 + %2 = tail call dereferenceable_or_null(15) ptr @malloc(i32 noundef 15) #11 + %3 = tail call i32 (ptr, ptr, ...) @sprintf(ptr noundef nonnull dereferenceable(1) %2, ptr noundef nonnull dereferenceable(1) @.str, i32 noundef %0) #13 ret ptr %2 } @@ -119,9 +119,9 @@ declare dso_local noundef i32 @sprintf(ptr noalias nocapture noundef writeonly, ; Function Attrs: nounwind define dso_local noalias ptr @getString() local_unnamed_addr #6 { %1 = alloca i8, align 1 - %2 = tail call dereferenceable_or_null(11) ptr @malloc(i32 noundef 11) #10 - call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %1) #11 - %3 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str.4, ptr noundef nonnull %1) #12 + %2 = tail call dereferenceable_or_null(11) ptr @malloc(i32 noundef 11) #11 + call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %1) #12 + %3 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str.4, ptr noundef nonnull %1) #13 %4 = icmp eq i32 %3, 1 br i1 %4, label %5, label %34 @@ -142,12 +142,12 @@ define dso_local noalias ptr @getString() local_unnamed_addr #6 { 12: ; preds = %10 %13 = shl nuw nsw i32 %7, 1 %14 = or disjoint i32 %13, 1 - %15 = call ptr @malloc(i32 noundef %14) #10 + %15 = call ptr @malloc(i32 noundef %14) #11 %16 = icmp eq i32 %7, 0 br i1 %16, label %17, label %19 17: ; preds = %19, %12 - call void @free(ptr noundef %6) #12 + call void @free(ptr noundef %6) #13 %18 = load i8, ptr %1, align 1, !tbaa !6 br label %26 @@ -168,7 +168,7 @@ define dso_local noalias ptr @getString() local_unnamed_addr #6 { %30 = add nuw nsw i32 %7, 1 %31 = getelementptr inbounds i8, ptr %29, i32 %7 store i8 %27, ptr %31, align 1, !tbaa !6 - %32 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str.4, ptr noundef nonnull %1) #12 + %32 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str.4, ptr noundef nonnull %1) #13 %33 = icmp eq i32 %32, 1 br i1 %33, label %5, label %34, !llvm.loop !15 @@ -177,7 +177,7 @@ define dso_local noalias ptr @getString() local_unnamed_addr #6 { %36 = phi ptr [ %2, %0 ], [ %6, %5 ], [ %6, %5 ], [ %29, %26 ] %37 = getelementptr inbounds i8, ptr %36, i32 %35 store i8 0, ptr %37, align 1, !tbaa !6 - call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %1) #11 + call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %1) #12 ret ptr %36 } @@ -190,16 +190,16 @@ declare dso_local void @free(ptr allocptr nocapture noundef) local_unnamed_addr ; Function Attrs: nofree nounwind define dso_local i32 @getInt() local_unnamed_addr #4 { %1 = alloca i32, align 4 - call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %1) #11 - %2 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str, ptr noundef nonnull %1) #12 + call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %1) #12 + %2 = call i32 (ptr, ...) @scanf(ptr noundef nonnull @.str, ptr noundef nonnull %1) #13 %3 = load i32, ptr %1, align 4, !tbaa !12 - call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %1) #11 + call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %1) #12 ret i32 %3 } ; Function Attrs: mustprogress nofree nounwind willreturn memory(inaccessiblemem: readwrite) define dso_local noalias noundef ptr @.builtin.AllocateClassBody(i32 noundef %0) local_unnamed_addr #9 { - %2 = tail call ptr @malloc(i32 noundef %0) #10 + %2 = tail call ptr @malloc(i32 noundef %0) #11 ret ptr %2 } @@ -242,7 +242,7 @@ define dso_local noalias nonnull ptr @.builtin.RecursiveAllocateArray(i32 nounde 13: ; preds = %3 %14 = mul nsw i32 %5, %1 %15 = add nsw i32 %14, 4 - %16 = tail call ptr @malloc(i32 noundef %15) #10 + %16 = tail call ptr @malloc(i32 noundef %15) #11 store i8 %6, ptr %16, align 1, !tbaa !6 %17 = getelementptr inbounds i8, ptr %16, i32 1 store i8 %8, ptr %17, align 1, !tbaa !6 @@ -256,7 +256,7 @@ define dso_local noalias nonnull ptr @.builtin.RecursiveAllocateArray(i32 nounde 21: ; preds = %3 %22 = shl i32 %5, 2 %23 = add i32 %22, 4 - %24 = tail call ptr @malloc(i32 noundef %23) #10 + %24 = tail call ptr @malloc(i32 noundef %23) #11 store i8 %6, ptr %24, align 1, !tbaa !6 %25 = getelementptr inbounds i8, ptr %24, i32 1 store i8 %8, ptr %25, align 1, !tbaa !6 @@ -275,7 +275,7 @@ define dso_local noalias nonnull ptr @.builtin.RecursiveAllocateArray(i32 nounde 33: ; preds = %30, %33 %34 = phi i32 [ 0, %30 ], [ %37, %33 ] - %35 = tail call ptr @.builtin.RecursiveAllocateArray(i32 noundef %31, i32 noundef %1, ptr noundef nonnull %32) #12 + %35 = tail call ptr @.builtin.RecursiveAllocateArray(i32 noundef %31, i32 noundef %1, ptr noundef nonnull %32) #13 %36 = getelementptr inbounds ptr, ptr %28, i32 %34 store ptr %35, ptr %36, align 4, !tbaa !16 %37 = add nuw nsw i32 %34, 1 @@ -288,6 +288,29 @@ define dso_local noalias nonnull ptr @.builtin.RecursiveAllocateArray(i32 nounde ret ptr %41 } +; Function Attrs: mustprogress nofree nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite) +define dso_local noalias nonnull ptr @.builtin.AllocateArray(i32 noundef %0, i32 noundef %1) local_unnamed_addr #10 { + %3 = mul nsw i32 %1, %0 + %4 = add nsw i32 %3, 4 + %5 = tail call ptr @malloc(i32 noundef %4) #11 + %6 = trunc i32 %1 to i8 + store i8 %6, ptr %5, align 1, !tbaa !6 + %7 = lshr i32 %1, 8 + %8 = trunc i32 %7 to i8 + %9 = getelementptr inbounds i8, ptr %5, i32 1 + store i8 %8, ptr %9, align 1, !tbaa !6 + %10 = lshr i32 %1, 16 + %11 = trunc i32 %10 to i8 + %12 = getelementptr inbounds i8, ptr %5, i32 2 + store i8 %11, ptr %12, align 1, !tbaa !6 + %13 = lshr i32 %1, 24 + %14 = trunc i32 %13 to i8 + %15 = getelementptr inbounds i8, ptr %5, i32 3 + store i8 %14, ptr %15, align 1, !tbaa !6 + %16 = getelementptr inbounds i8, ptr %5, i32 4 + ret ptr %16 +} + attributes #0 = { nofree norecurse nosync nounwind memory(argmem: read) "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } attributes #2 = { nofree nounwind memory(write, argmem: read, inaccessiblemem: readwrite) "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } @@ -298,10 +321,11 @@ attributes #6 = { nounwind "no-builtin-memcpy" "no-builtin-printf" "no-trapping- attributes #7 = { "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } attributes #8 = { mustprogress nounwind willreturn allockind("free") memory(argmem: readwrite, inaccessiblemem: readwrite) "alloc-family"="malloc" "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } attributes #9 = { mustprogress nofree nounwind willreturn memory(inaccessiblemem: readwrite) "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } -attributes #10 = { allocsize(0) "no-builtin-memcpy" "no-builtin-printf" } -attributes #11 = { nounwind } -attributes #12 = { "no-builtin-memcpy" "no-builtin-printf" } -attributes #13 = { nobuiltin nounwind "no-builtin-memcpy" "no-builtin-printf" } +attributes #10 = { mustprogress nofree nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite) "no-builtin-memcpy" "no-builtin-printf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+m,+relax,-d,-e,-experimental-zacas,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-f,-h,-smaia,-smepmp,-ssaia,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } +attributes #11 = { allocsize(0) "no-builtin-memcpy" "no-builtin-printf" } +attributes #12 = { nounwind } +attributes #13 = { "no-builtin-memcpy" "no-builtin-printf" } +attributes #14 = { nobuiltin nounwind "no-builtin-memcpy" "no-builtin-printf" } !llvm.module.flags = !{!0, !1, !2, !4} !llvm.ident = !{!5} diff --git a/src/IR/builtin.s b/src/IR/builtin.s index 7a27c65..6535bfd 100644 --- a/src/IR/builtin.s +++ b/src/IR/builtin.s @@ -434,6 +434,37 @@ getInt: # @getInt .size .builtin.RecursiveAllocateArray, .Lfunc_end13-.builtin.RecursiveAllocateArray # -- End function .option pop + .option push + .option arch, +a, +c + .globl .builtin.AllocateArray # -- Begin function .builtin.AllocateArray + .p2align 1 + .type .builtin.AllocateArray,@function +.builtin.AllocateArray: # @.builtin.AllocateArray +# %bb.0: + addi sp, sp, -16 + sw ra, 12(sp) # 4-byte Folded Spill + sw s0, 8(sp) # 4-byte Folded Spill + mv s0, a1 + mul a0, a1, a0 + addi a0, a0, 4 + call malloc + sb s0, 0(a0) + srli a1, s0, 8 + sb a1, 1(a0) + srli a1, s0, 16 + sb a1, 2(a0) + srli s0, s0, 24 + addi a1, a0, 4 + sb s0, 3(a0) + mv a0, a1 + lw ra, 12(sp) # 4-byte Folded Reload + lw s0, 8(sp) # 4-byte Folded Reload + addi sp, sp, 16 + ret +.Lfunc_end14: + .size .builtin.AllocateArray, .Lfunc_end14-.builtin.AllocateArray + # -- End function + .option pop .type .L.str,@object # @.str .section .rodata.str1.1,"aMS",@progbits,1 .L.str: