mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Adding saturated builtins. Remove LLVM 12 support. Remove old llvm optimizer use.
This commit is contained in:
committed by
Christoffer Lerno
parent
fd9d300b06
commit
a66c0942f8
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
@@ -164,7 +164,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [12, 13, 14, 15, 16]
|
||||
llvm_version: [13, 14, 15, 16]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -182,10 +182,7 @@ jobs:
|
||||
fi
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
|
||||
|
||||
if [[ "${{matrix.llvm_version}}" > 12 ]]; then
|
||||
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
|
||||
fi
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
@@ -251,7 +248,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [12, 13, 14]
|
||||
llvm_version: [13, 14]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download LLVM
|
||||
|
||||
@@ -44,7 +44,7 @@ if(C3_USE_MIMALLOC)
|
||||
endif()
|
||||
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 12 OR ${C3_LLVM_VERSION} VERSION_GREATER 16)
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 13 OR ${C3_LLVM_VERSION} VERSION_GREATER 16)
|
||||
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -261,7 +261,7 @@ You can try it out by running some sample code: `c3c.exe compile ../resources/ex
|
||||
|
||||
1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed.
|
||||
2. Install CMake: `sudo apt install cmake`
|
||||
3. Install LLVM 12 (or greater: C3C supports LLVM 12-16): `sudo apt-get install clang-12 zlib1g zlib1g-dev libllvm12 llvm-12 llvm-12-dev llvm-12-runtime liblld-12-dev liblld-12`
|
||||
3. Install LLVM 13 (or greater: C3C supports LLVM 13-16): `sudo apt-get install clang-13 zlib1g zlib1g-dev libllvm13 llvm-13 llvm-13-dev llvm-13-runtime liblld-13-dev liblld-13`
|
||||
4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
5. Enter the C3C directory `cd c3c`.
|
||||
6. Create a build directory `mkdir build`
|
||||
@@ -277,7 +277,7 @@ You can try it out by running some sample code: `./c3c compile ../resources/exam
|
||||
#### Compiling on other Linux / Unix variants
|
||||
|
||||
1. Install CMake.
|
||||
2. Install or compile LLVM and LLD *libraries* (version 12+ or higher)
|
||||
2. Install or compile LLVM and LLD *libraries* (version 13+ or higher)
|
||||
3. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
4. Enter the C3C directory `cd c3c`.
|
||||
5. Create a build directory `mkdir build`
|
||||
|
||||
@@ -29,17 +29,14 @@ else
|
||||
fi
|
||||
|
||||
TAG="$1"
|
||||
if [ "$1" = 20 ]; then
|
||||
UBUNTU_VERSION="20.04"
|
||||
LLVM_VERSION="12"
|
||||
elif [ "$1" = 21 ]; then
|
||||
if [ "$1" = 21 ]; then
|
||||
UBUNTU_VERSION="21.10"
|
||||
LLVM_VERSION="13"
|
||||
elif [ "$1" = 22 ]; then
|
||||
UBUNTU_VERSION="22.04"
|
||||
LLVM_VERSION="14"
|
||||
else
|
||||
echo "ERROR: expected 20, 21 or 22 as Ubuntu version argument" 1>&2
|
||||
echo "ERROR: expected 21 or 22 as Ubuntu version argument" 1>&2
|
||||
exit 2
|
||||
fi
|
||||
IMAGE="$IMAGE:$TAG"
|
||||
|
||||
@@ -114,7 +114,6 @@ static void usage(void)
|
||||
OUTPUT(" -L <library dir> - Append the directory to the linker search paths.");
|
||||
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
|
||||
OUTPUT(" --forcelinker - Force built in linker usage when doing non-cross linking.");
|
||||
OUTPUT(" --newoptimizer - Use new optimizer pipeline.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE");
|
||||
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, mmx, sse, avx, avx512.");
|
||||
@@ -465,21 +464,9 @@ static void parse_option(BuildOptions *options)
|
||||
options->symtab_size = next_highest_power_of_2(symtab);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("newoptimizer"))
|
||||
{
|
||||
options->use_new_optimizer = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("forcelinker"))
|
||||
{
|
||||
if (llvm_version_major > 12)
|
||||
{
|
||||
options->force_linker = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Force linking ignored on LLVM 12 and earlier.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (match_longopt("version"))
|
||||
|
||||
@@ -257,7 +257,6 @@ typedef struct BuildOptions_
|
||||
bool test_mode;
|
||||
bool no_stdlib;
|
||||
bool force_linker;
|
||||
bool use_new_optimizer;
|
||||
const char *panicfn;
|
||||
const char *cc;
|
||||
const char *build_dir;
|
||||
@@ -334,7 +333,6 @@ typedef struct
|
||||
bool no_stdlib;
|
||||
bool emit_object_files;
|
||||
bool force_linker;
|
||||
bool use_new_optimizer;
|
||||
OptimizationLevel optimization_level;
|
||||
SizeOptimizationLevel size_optimization_level;
|
||||
DebugInfo debug_info;
|
||||
|
||||
@@ -195,7 +195,6 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
target->emit_llvm = options->emit_llvm;
|
||||
target->emit_asm = options->emit_asm;
|
||||
target->force_linker = options->force_linker;
|
||||
target->use_new_optimizer = options->use_new_optimizer;
|
||||
target->panicfn = options->panicfn;
|
||||
if (options->macos.sdk) target->macos.sdk = options->macos.sdk;
|
||||
if (options->win.sdk) target->win.sdk = options->win.sdk;
|
||||
|
||||
@@ -813,6 +813,9 @@ typedef enum
|
||||
BUILTIN_RINT,
|
||||
BUILTIN_ROUND,
|
||||
BUILTIN_ROUNDEVEN,
|
||||
BUILTIN_SAT_ADD,
|
||||
BUILTIN_SAT_SUB,
|
||||
BUILTIN_SAT_SHL,
|
||||
BUILTIN_SIN,
|
||||
BUILTIN_SHUFFLEVECTOR,
|
||||
BUILTIN_SQRT,
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#include "llvm_codegen_internal.h"
|
||||
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
#include <llvm-c/Error.h>
|
||||
#include <llvm-c/Comdat.h>
|
||||
|
||||
typedef struct LLVMOpaquePassBuilderOptions *LLVMPassBuilderOptionsRef;
|
||||
LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes,
|
||||
LLVMTargetMachineRef TM,
|
||||
@@ -14,7 +15,6 @@ LLVMPassBuilderOptionsRef LLVMCreatePassBuilderOptions(void);
|
||||
void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, LLVMBool VerifyEach);
|
||||
void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, LLVMBool DebugLogging);
|
||||
void LLVMDisposePassBuilderOptions(LLVMPassBuilderOptionsRef Options);
|
||||
#endif
|
||||
|
||||
const char* llvm_version = LLVM_VERSION_STRING;
|
||||
const char* llvm_target = LLVM_DEFAULT_TARGET_TRIPLE;
|
||||
@@ -637,6 +637,7 @@ void llvm_codegen_setup()
|
||||
intrinsic_id.sadd_overflow = lookup_intrinsic("llvm.sadd.with.overflow");
|
||||
intrinsic_id.sadd_sat = lookup_intrinsic("llvm.sadd.sat");
|
||||
intrinsic_id.sin = lookup_intrinsic("llvm.sin");
|
||||
intrinsic_id.sshl_sat = lookup_intrinsic("llvm.sshl.sat");
|
||||
intrinsic_id.smax = lookup_intrinsic("llvm.smax");
|
||||
intrinsic_id.smin = lookup_intrinsic("llvm.smin");
|
||||
intrinsic_id.smul_overflow = lookup_intrinsic("llvm.smul.with.overflow");
|
||||
@@ -651,6 +652,7 @@ void llvm_codegen_setup()
|
||||
intrinsic_id.umin = lookup_intrinsic("llvm.umin");
|
||||
intrinsic_id.umul_overflow = lookup_intrinsic("llvm.umul.with.overflow");
|
||||
intrinsic_id.usub_overflow = lookup_intrinsic("llvm.usub.with.overflow");
|
||||
intrinsic_id.ushl_sat = lookup_intrinsic("llvm.ushl.sat");
|
||||
intrinsic_id.usub_sat = lookup_intrinsic("llvm.usub.sat");
|
||||
intrinsic_id.vector_reduce_fmax = lookup_intrinsic("llvm.vector.reduce.fmax");
|
||||
intrinsic_id.vector_reduce_fmin = lookup_intrinsic("llvm.vector.reduce.fmin");
|
||||
@@ -806,46 +808,8 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void llvm_opt_old(GenContext *c)
|
||||
{
|
||||
LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate();
|
||||
LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, (unsigned)active_target.optimization_level);
|
||||
LLVMPassManagerBuilderSetSizeLevel(pass_manager_builder, (unsigned)active_target.size_optimization_level);
|
||||
LLVMPassManagerBuilderSetDisableUnrollLoops(pass_manager_builder, active_target.optimization_level == OPTIMIZATION_NONE);
|
||||
if (active_target.optimization_level != OPTIMIZATION_NONE)
|
||||
{
|
||||
LLVMPassManagerBuilderUseInlinerWithThreshold(pass_manager_builder, (unsigned)get_inlining_threshold());
|
||||
}
|
||||
LLVMPassManagerRef pass_manager = LLVMCreatePassManager();
|
||||
LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(c->module);
|
||||
LLVMAddAnalysisPasses(c->machine, function_pass_manager);
|
||||
LLVMAddAnalysisPasses(c->machine, pass_manager);
|
||||
LLVMPassManagerBuilderPopulateModulePassManager(pass_manager_builder, pass_manager);
|
||||
LLVMPassManagerBuilderPopulateFunctionPassManager(pass_manager_builder, function_pass_manager);
|
||||
|
||||
// IMPROVE
|
||||
// In LLVM Opt, LoopVectorize and SLPVectorize settings are part of the PassManagerBuilder
|
||||
// Anything else we need to manually add?
|
||||
|
||||
LLVMPassManagerBuilderDispose(pass_manager_builder);
|
||||
|
||||
// Run function passes
|
||||
LLVMInitializeFunctionPassManager(function_pass_manager);
|
||||
LLVMValueRef current_function = LLVMGetFirstFunction(c->module);
|
||||
while (current_function)
|
||||
{
|
||||
LLVMRunFunctionPassManager(function_pass_manager, current_function);
|
||||
current_function = LLVMGetNextFunction(current_function);
|
||||
}
|
||||
LLVMFinalizeFunctionPassManager(function_pass_manager);
|
||||
LLVMDisposePassManager(function_pass_manager);
|
||||
|
||||
// Run module pass
|
||||
LLVMRunPassManager(pass_manager, c->module);
|
||||
LLVMDisposePassManager(pass_manager);
|
||||
}
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
static inline void llvm_opt_new(GenContext *c)
|
||||
static inline void llvm_optimize(GenContext *c)
|
||||
{
|
||||
LLVMPassBuilderOptionsRef options = LLVMCreatePassBuilderOptions();
|
||||
LLVMPassBuilderOptionsSetVerifyEach(options, active_target.emit_llvm);
|
||||
@@ -884,20 +848,11 @@ static inline void llvm_opt_new(GenContext *c)
|
||||
}
|
||||
LLVMDisposePassBuilderOptions(options);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *llvm_codegen(void *context)
|
||||
{
|
||||
GenContext *c = context;
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
if (active_target.use_new_optimizer)
|
||||
{
|
||||
llvm_opt_new(c);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
llvm_opt_old(c);
|
||||
}
|
||||
llvm_optimize(c);
|
||||
|
||||
// Serialize the LLVM IR, if requested, also verify the IR in this case
|
||||
if (active_target.emit_llvm)
|
||||
|
||||
@@ -4346,6 +4346,9 @@ unsigned llvm_get_intrinsic(BuiltinFunction func)
|
||||
case BUILTIN_ABS:
|
||||
case BUILTIN_SHUFFLEVECTOR:
|
||||
case BUILTIN_REVERSE:
|
||||
case BUILTIN_SAT_ADD:
|
||||
case BUILTIN_SAT_SHL:
|
||||
case BUILTIN_SAT_SUB:
|
||||
UNREACHABLE
|
||||
case BUILTIN_SYSCLOCK:
|
||||
return intrinsic_id.readcyclecounter;
|
||||
@@ -4454,11 +4457,7 @@ static inline LLVMValueRef llvm_syscall_asm(GenContext *c, LLVMTypeRef func_type
|
||||
{
|
||||
return LLVMGetInlineAsm(func_type, call, strlen(call),
|
||||
scratch_buffer_to_string(), scratch_buffer.len,
|
||||
true, true, LLVMInlineAsmDialectATT
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
, /* can throw */ false
|
||||
#endif
|
||||
);
|
||||
true, true, LLVMInlineAsmDialectATT, /* can throw */ false);
|
||||
}
|
||||
|
||||
static inline void llvm_emit_syscall(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
@@ -4582,39 +4581,53 @@ INLINE void llvm_emit_reverse(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
llvm_value_set(result_value, LLVMBuildShuffleVector(c->builder, arg1, arg2, mask, "reverse"), rtype);
|
||||
}
|
||||
|
||||
INLINE unsigned llvm_intrinsic_by_type(Type *type, unsigned int_intrinsic, unsigned uint_intrinsic, unsigned float_intrinsic)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
RETRY:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case ALL_SIGNED_INTS:
|
||||
return int_intrinsic;
|
||||
case TYPE_BOOL:
|
||||
case ALL_UNSIGNED_INTS:
|
||||
return uint_intrinsic;
|
||||
case ALL_FLOATS:
|
||||
return float_intrinsic;
|
||||
case TYPE_VECTOR:
|
||||
type = type->array.base;
|
||||
goto RETRY;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
{
|
||||
BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin;
|
||||
if (func == BUILTIN_UNREACHABLE)
|
||||
unsigned intrinsic;
|
||||
switch (func)
|
||||
{
|
||||
case BUILTIN_UNREACHABLE:
|
||||
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
|
||||
c->current_block = NULL;
|
||||
c->current_block_is_target = false;
|
||||
LLVMBasicBlockRef after_unreachable = llvm_basic_block_new(c, "after.unreachable");
|
||||
llvm_emit_block(c, after_unreachable);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_SHUFFLEVECTOR)
|
||||
{
|
||||
case BUILTIN_SHUFFLEVECTOR:
|
||||
llvm_emit_shufflevector(c, result_value, expr);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_REVERSE)
|
||||
{
|
||||
case BUILTIN_REVERSE:
|
||||
llvm_emit_reverse(c, result_value, expr);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_STACKTRACE)
|
||||
{
|
||||
case BUILTIN_STACKTRACE:
|
||||
if (!c->debug.enable_stacktrace)
|
||||
{
|
||||
llvm_value_set(result_value, llvm_get_zero(c, type_voidptr), type_voidptr);
|
||||
return;
|
||||
}
|
||||
llvm_value_set(result_value, llvm_emit_bitcast(c, c->debug.stack_slot, type_voidptr), type_voidptr);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_VOLATILE_STORE)
|
||||
case BUILTIN_VOLATILE_STORE:
|
||||
{
|
||||
BEValue value;
|
||||
llvm_emit_expr(c, &value, expr->call_expr.arguments[0]);
|
||||
@@ -4626,7 +4639,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
if (store) LLVMSetVolatile(store, true);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_VOLATILE_LOAD)
|
||||
case BUILTIN_VOLATILE_LOAD:
|
||||
{
|
||||
llvm_emit_expr(c, result_value, expr->call_expr.arguments[0]);
|
||||
llvm_value_rvalue(c, result_value);
|
||||
@@ -4636,81 +4649,45 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
LLVMSetVolatile(result_value->value, true);
|
||||
return;
|
||||
}
|
||||
if (func == BUILTIN_SYSCALL)
|
||||
{
|
||||
case BUILTIN_SYSCALL:
|
||||
llvm_emit_syscall(c, result_value, expr);
|
||||
return;
|
||||
}
|
||||
unsigned intrinsic;
|
||||
if (func == BUILTIN_MAX)
|
||||
{
|
||||
Type *type = type_flatten(expr->call_expr.arguments[0]->type);
|
||||
RETRY:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case ALL_SIGNED_INTS:
|
||||
intrinsic = intrinsic_id.smax;
|
||||
case BUILTIN_MAX:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.smax,
|
||||
intrinsic_id.umax,
|
||||
intrinsic_id.maxnum);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
case ALL_UNSIGNED_INTS:
|
||||
intrinsic = intrinsic_id.umax;
|
||||
case BUILTIN_MIN:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.smin,
|
||||
intrinsic_id.umin,
|
||||
intrinsic_id.minnum);
|
||||
break;
|
||||
case ALL_FLOATS:
|
||||
intrinsic = intrinsic_id.maxnum;
|
||||
case BUILTIN_ABS:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.abs,
|
||||
intrinsic_id.abs,
|
||||
intrinsic_id.fabs);
|
||||
break;
|
||||
case BUILTIN_SAT_SHL:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.sshl_sat,
|
||||
intrinsic_id.ushl_sat, 0);
|
||||
break;
|
||||
case BUILTIN_SAT_ADD:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.sadd_sat,
|
||||
intrinsic_id.uadd_sat, 0);
|
||||
break;
|
||||
case BUILTIN_SAT_SUB:
|
||||
intrinsic = llvm_intrinsic_by_type(expr->call_expr.arguments[0]->type,
|
||||
intrinsic_id.ssub_sat,
|
||||
intrinsic_id.usub_sat, 0);
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
type = type->array.base;
|
||||
goto RETRY;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
else if (func == BUILTIN_MIN)
|
||||
{
|
||||
Type *type = type_flatten(expr->call_expr.arguments[0]->type);
|
||||
RETRY2:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case ALL_SIGNED_INTS:
|
||||
intrinsic = intrinsic_id.smin;
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
case ALL_UNSIGNED_INTS:
|
||||
intrinsic = intrinsic_id.umin;
|
||||
break;
|
||||
case ALL_FLOATS:
|
||||
intrinsic = intrinsic_id.minnum;
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
type = type->array.base;
|
||||
goto RETRY2;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
else if (func == BUILTIN_ABS)
|
||||
{
|
||||
Type *type = type_flatten(expr->call_expr.arguments[0]->type);
|
||||
RETRY3:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_BOOL:
|
||||
case ALL_INTS:
|
||||
intrinsic = intrinsic_id.abs;
|
||||
break;
|
||||
case ALL_FLOATS:
|
||||
intrinsic = intrinsic_id.fabs;
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
type = type->array.base;
|
||||
goto RETRY3;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intrinsic = llvm_get_intrinsic(func);
|
||||
break;
|
||||
}
|
||||
llvm_emit_intrinsic_expr(c, intrinsic, result_value, expr);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,6 @@
|
||||
#include <llvm-c/Analysis.h>
|
||||
#include <llvm-c/BitWriter.h>
|
||||
#include <llvm-c/DebugInfo.h>
|
||||
#include <llvm-c/Transforms/PassManagerBuilder.h>
|
||||
#include <llvm-c/Transforms/InstCombine.h>
|
||||
#include <llvm-c/Transforms/Vectorize.h>
|
||||
#include <llvm-c/Transforms/Scalar.h>
|
||||
#include <llvm-c/Transforms/IPO.h>
|
||||
#include <llvm-c/Transforms/Utils.h>
|
||||
#include <llvm-c/Comdat.h>
|
||||
#include "dwarf.h"
|
||||
|
||||
#define SLICE_MAX_UNROLL 4
|
||||
|
||||
@@ -1188,10 +1188,8 @@ static inline void llvm_emit_asm_block_stmt(GenContext *c, Ast *ast)
|
||||
strlen(clobbers),
|
||||
ast->asm_block_stmt.is_volatile,
|
||||
true,
|
||||
ast->asm_block_stmt.is_string ? LLVMInlineAsmDialectIntel : LLVMInlineAsmDialectATT
|
||||
#if LLVM_VERSION_MAJOR > 12
|
||||
, /* can throw */ false
|
||||
#endif
|
||||
ast->asm_block_stmt.is_string ? LLVMInlineAsmDialectIntel : LLVMInlineAsmDialectATT,
|
||||
/* can throw */ false
|
||||
);
|
||||
LLVMValueRef res = LLVMBuildCall2(c->builder, asm_fn_type, asm_fn, args, param_count, "");
|
||||
#if LLVM_VERSION_MAJOR > 13
|
||||
|
||||
@@ -2534,6 +2534,9 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
|
||||
case BUILTIN_MIN:
|
||||
case BUILTIN_POW:
|
||||
case BUILTIN_VOLATILE_STORE:
|
||||
case BUILTIN_SAT_ADD:
|
||||
case BUILTIN_SAT_SUB:
|
||||
case BUILTIN_SAT_SHL:
|
||||
return 2;
|
||||
case BUILTIN_FMA:
|
||||
case BUILTIN_FSHL:
|
||||
@@ -2854,6 +2857,15 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex
|
||||
arg_count)) return false;
|
||||
rtype = args[0]->type;
|
||||
break;
|
||||
case BUILTIN_SAT_SHL:
|
||||
case BUILTIN_SAT_SUB:
|
||||
case BUILTIN_SAT_ADD:
|
||||
if (!sema_check_builtin_args(args,
|
||||
(BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE },
|
||||
arg_count)) return false;
|
||||
if (!sema_check_builtin_args_match(args, 2)) return false;
|
||||
rtype = args[0]->type;
|
||||
break;
|
||||
case BUILTIN_REVERSE:
|
||||
if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_VEC }, arg_count)) return false;
|
||||
rtype = args[0]->type;
|
||||
|
||||
@@ -208,6 +208,9 @@ void symtab_init(uint32_t capacity)
|
||||
builtin_list[BUILTIN_RINT] = KW_DEF("rint");
|
||||
builtin_list[BUILTIN_ROUND] = KW_DEF("round");
|
||||
builtin_list[BUILTIN_ROUNDEVEN] = KW_DEF("roundeven");
|
||||
builtin_list[BUILTIN_SAT_ADD] = KW_DEF("sat_add");
|
||||
builtin_list[BUILTIN_SAT_SHL] = KW_DEF("sat_shl");
|
||||
builtin_list[BUILTIN_SAT_SUB] = KW_DEF("sat_sub");
|
||||
builtin_list[BUILTIN_SIN] = KW_DEF("sin");
|
||||
builtin_list[BUILTIN_SHUFFLEVECTOR] = KW_DEF("shufflevector");
|
||||
builtin_list[BUILTIN_SQRT] = KW_DEF("sqrt");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.45"
|
||||
#define COMPILER_VERSION "0.3.46"
|
||||
38
test/test_suite/builtins/sat_builtins.c3t
Normal file
38
test/test_suite/builtins/sat_builtins.c3t
Normal file
@@ -0,0 +1,38 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
char a = 123;
|
||||
char b = 222;
|
||||
io::printfln("%s %s", $$sat_add(a, b), $$sat_add((ichar)a, (ichar)30));
|
||||
io::printfln("%s %s", $$sat_sub(a, b), $$sat_sub((ichar)-120, (ichar)10));
|
||||
b = 3;
|
||||
io::printfln("%s %s", $$sat_shl(a, b), $$sat_shl((ichar)a, (ichar)1));
|
||||
b = 222;
|
||||
char[<2>] x = { 123, 222 };
|
||||
char[<2>] y = { 143, 50 };
|
||||
ichar[<2>] z = { 120, -120 };
|
||||
ichar[<2>] w = { -44, 30 };
|
||||
io::printfln("%s %s", $$sat_add(x, y), $$sat_add(z, z));
|
||||
io::printfln("%s %s", $$sat_sub(x, y), $$sat_sub(w, z));
|
||||
io::printfln("%s %s", $$sat_shl(x, char[<2>] { 1, 1 }), $$sat_shl(z, ichar[<2>] { 1, 1 }));
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
call i8 @llvm.uadd.sat.i8
|
||||
call i8 @llvm.sadd.sat.i8
|
||||
call i8 @llvm.usub.sat.i8
|
||||
call i8 @llvm.ssub.sat.i8
|
||||
call i8 @llvm.ushl.sat.i8
|
||||
call i8 @llvm.sshl.sat.i8
|
||||
call <2 x i8> @llvm.uadd.sat.v2i8
|
||||
call <2 x i8> @llvm.sadd.sat.v2i8
|
||||
call <2 x i8> @llvm.usub.sat.v2i8
|
||||
call <2 x i8> @llvm.ssub.sat.v2i8
|
||||
call <2 x i8> @llvm.ushl.sat.v2i8
|
||||
call <2 x i8> @llvm.sshl.sat.v2i8
|
||||
38
test/test_suite2/builtins/sat_builtins.c3t
Normal file
38
test/test_suite2/builtins/sat_builtins.c3t
Normal file
@@ -0,0 +1,38 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
char a = 123;
|
||||
char b = 222;
|
||||
io::printfln("%s %s", $$sat_add(a, b), $$sat_add((ichar)a, (ichar)30));
|
||||
io::printfln("%s %s", $$sat_sub(a, b), $$sat_sub((ichar)-120, (ichar)10));
|
||||
b = 3;
|
||||
io::printfln("%s %s", $$sat_shl(a, b), $$sat_shl((ichar)a, (ichar)1));
|
||||
b = 222;
|
||||
char[<2>] x = { 123, 222 };
|
||||
char[<2>] y = { 143, 50 };
|
||||
ichar[<2>] z = { 120, -120 };
|
||||
ichar[<2>] w = { -44, 30 };
|
||||
io::printfln("%s %s", $$sat_add(x, y), $$sat_add(z, z));
|
||||
io::printfln("%s %s", $$sat_sub(x, y), $$sat_sub(w, z));
|
||||
io::printfln("%s %s", $$sat_shl(x, char[<2>] { 1, 1 }), $$sat_shl(z, ichar[<2>] { 1, 1 }));
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
call i8 @llvm.uadd.sat.i8
|
||||
call i8 @llvm.sadd.sat.i8
|
||||
call i8 @llvm.usub.sat.i8
|
||||
call i8 @llvm.ssub.sat.i8
|
||||
call i8 @llvm.ushl.sat.i8
|
||||
call i8 @llvm.sshl.sat.i8
|
||||
call <2 x i8> @llvm.uadd.sat.v2i8
|
||||
call <2 x i8> @llvm.sadd.sat.v2i8
|
||||
call <2 x i8> @llvm.usub.sat.v2i8
|
||||
call <2 x i8> @llvm.ssub.sat.v2i8
|
||||
call <2 x i8> @llvm.ushl.sat.v2i8
|
||||
call <2 x i8> @llvm.sshl.sat.v2i8
|
||||
@@ -166,20 +166,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
int llvm_version_major = LLVM_VERSION_MAJOR;
|
||||
#if LLVM_VERSION_MAJOR < 13
|
||||
#if _MSC_VER
|
||||
__declspec(selectany)
|
||||
#else
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID,
|
||||
LLVMTypeRef type_ref)
|
||||
{
|
||||
auto &Ctx = *llvm::unwrap(C);
|
||||
auto AttrKind = (llvm::Attribute::AttrKind)KindID;
|
||||
return wrap(llvm::Attribute::get(Ctx, AttrKind, llvm::unwrap(type_ref)));
|
||||
}
|
||||
#endif
|
||||
|
||||
LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal)
|
||||
{
|
||||
llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal);
|
||||
|
||||
Reference in New Issue
Block a user